2012-09-20 12 views
6
let inline myfunction x y = ... 

let inline mycurried = myfunction x // error, only functions may be marked inline 

Sembra impossibile esplicitamente funzioni inline. Quindi, ogni volta che viene chiamato il numero mycurried, non sarà possibile ottenere inlined anche se myfunction è inlined correttamente, è corretto?Le funzioni point free erano in linea?

Quindi questo può essere considerato uno degli svantaggi della funzione al curry?

risposta

5

Penso che la tua domanda è se una funzione point-free può essere inline o meno.

La limitazione trovata non è dovuta alla funzione al curry. Nota che nel tuo esempio la funzione al curry è sul lato destro, sul lato sinistro hai una funzione point-free.

F # consente solo alle funzioni di essere in linea, non di costanti.

Principalmente si può pensare che questo possa essere considerato un errore dato che l'inferenza di tipo è abbastanza intelligente da scoprire che è una funzione (senza punto), ma leggere le note di Tomas relative agli effetti collaterali.

quanto pare quando il compilatore trova sul lato sinistro solo un identificatore viene a mancare con questo errore:

let inline myfunction x y = x + y 

let inline mycurried = myfunction 1 

--> Only functions may be marked 'inline' 

Come Brian ha detto una soluzione alternativa è l'aggiunta di un parametro esplicito su entrambi i lati:

let inline mycurried x = (myfunction 1) x 

ma la tua funzione non è più point-free, è la stessa di:

let inline mycurried x = myfunction 1 x 

Un altro modo potrebbe essere quello di aggiungere un parametro generico esplicito:

let inline mycurried<'a> = myfunction 1 

quando i parametri generici sono presenti in modo esplicito sul lato sinistro si compila.

Vorrei che rimuovono il messaggio di errore e di trasformarlo un avvertimento, qualcosa come:

Since only functions can be 'inline' this value will be compiled as a function. 

UPDATE

Grazie Tomas per la risposta (e il tuo downvote).

La mia opinione personale è che questo dovrebbe essere un avvertimento, quindi sei consapevole che la semantica del tuo codice cambierà, ma poi spetta a te decidere cosa fare.

Lei dice che in linea è "solo un'ottimizzazione" ma non è del tutto vero:

. Basta trasformare tutte le funzioni in linea non garantisce un codice ottimale.

. Potresti voler usare i vincoli statici e quindi devi usare in linea.

Mi piacerebbe essere in grado di definire le mie costanti generiche (tipo), come già fa la libreria F # (cioè: GenericZero e GenericOne). So che il mio codice sarà puro, quindi non mi interessa se viene eseguito ogni volta.

+0

Si noti che la modifica del let let da un _value_ ('let x = ...') a un _function_ ('let x arg = ...') può cambiare il significato della funzione se l'espressione utilizzata per calcolare il la funzione ha alcuni effetti. Nel primo caso, gli effetti saranno valutati una volta e nel secondo, saranno valutati ripetutamente. Se vuoi che gli effetti vengano valutati solo una volta, non puoi usare 'inline'. Se si desidera eseguirli più volte, penso che sia corretto aggiungere un parametro aggiuntivo. –

+0

L'aggiunta di un parametro generico è _molto sottile_ perché assomiglia ancora a un valore, ma in realtà si comporta come una funzione (vale a dire che gli effetti vengono valutati ripetutamente), quindi non lo consiglierei. (A parte questo, sono abbastanza sicuro che il comportamento è in realtà indefinito - cioè una versione futura del compilatore potrebbe decidere di valutare gli effetti solo una volta per ogni argomento di tipo generico). –

+0

Il messaggio di errore non ha senso in lingue pure (come Haskell), ma penso che impedirti di modificare accidentalmente il comportamento del tuo programma quando aggiungi 'inline' solo per ottimizzarlo è un'ottima decisione. –

4

Penso solo bisogno di aggiungere un parametro esplicito di entrambe le parti (anche se non ho provato):

let inline myfunction x y = ... 

let inline mycurried y = myfunction 42 y // or whatever value (42) 
2

Il compilatore consente solo inline sui collegamenti che definiscono una funzione. Questo è essenzialmente la stessa cosa di quello che sta accadendo with F# value restriction (e vedere also here). Come dice Brian, puoi facilmente risolvere questo problema aggiungendo un parametro alla tua funzione.

Perché esiste questa restrizione? Se non ci fosse, aggiungere inline cambierebbe il significato dei tuoi programmi e sarebbe male!

Per esempio, supponiamo di avere una funzione come questa (che crea lo stato mutevole e restituisce una funzione di contatore):

let createCounter n = 
    let state = ref n 
    (fun() -> incr state; !state) 

Ora, il seguente codice:

let counter = createCounter 0 

... crea una singola funzione globale che è possibile utilizzare più volte (chiamare counter()) e vi fornirà numeri interi univoci a partire da 1. Se è possibile contrassegnarlo come inline:

let inline counter = createCounter 0 

... quindi ogni volta che si utilizza counter(), il compilatore deve sostituirlo con createCounter 0() e quindi si otterrebbe 1 ogni volta che si chiama il contatore!

+0

Hai ragione. In realtà puoi compilarlo come inline facendo il trucco che ho menzionato: let contatore inline <'a> = ...... Comunque preferirei comunque un avvertimento piuttosto che un errore di compilazione e dover fare affidamento su workaround/trucchi. – Gustavo

+0

@Gustavo Penso che sia più che corretto ottenere un errore del compilatore quando l'inlining (che in realtà è solo un'ottimizzazione) cambierebbe la semantica del codice. L'errore ti dice solo che il compilatore _cannot_ valori in linea (e questo ha molto senso). Se vuoi (e puoi) trasformare un valore in una funzione, allora è bene che tu lo faccia esplicitamente, perché devi pensare se questo ti dà il significato che vuoi. –

+0

@Gustavo E sì, puoi compilare il codice se scrivi 'let contatore inline <'T> = createCounter 0' e penso che sia male. Significa che otterrai sempre "1" quando chiami il contatore "<_>()" e questo non è il comportamento previsto. –