Abbreviazione di funzione anonima


85

C'è qualcosa che non capisco sulle funzioni anonime che usano la notazione breve # (..)

I seguenti lavori:

REPL>  ((fn [s] s) "Eh")
"Eh"

Ma questo non:

REPL>  (#(%) "Eh")

Funziona:

REPL> (#(str %) "Eh")
"Eh"

Quello che non capisco è perché (# (%) "Eh") non funziona e allo stesso tempo non ho bisogno di usare str in ((fn [s] s) "Eh")

Sono entrambe funzioni anonime ed entrambe prendono, qui, un parametro. Perché la notazione abbreviata necessita di una funzione mentre l'altra notazione no?

Risposte:


126
#(...)

è una scorciatoia per

(fn [arg1 arg2 ...] (...))

(dove il numero di argN dipende da quanti% N hai nel corpo). Quindi quando scrivi:

#(%)

è tradotto in:

(fn [arg1] (arg1))

Nota che questo è diverso dalla tua prima funzione anonima, che è come:

(fn [arg1] arg1)

La tua versione restituisce arg1 come valore, la versione che deriva dall'espansione della scorciatoia cerca di chiamarla come funzione. Ricevi un errore perché una stringa non è una funzione valida.

Poiché la stenografia fornisce una serie di parentesi attorno al corpo, può essere utilizzata solo per eseguire una singola chiamata di funzione o una forma speciale.


64

Come le altre risposte hanno già sottolineato molto bene, quella che #(%)hai postato in realtà si espande in qualcosa di simile (fn [arg1] (arg1)), che non è affatto lo stesso di (fn [arg1] arg1).

@ John Flatness ha sottolineato che puoi semplicemente usare identity, ma se stai cercando un modo per scrivere identityusando la #(...)macro di invio, puoi farlo in questo modo:

#(-> %)

Combinando la #(...)macro di invio con la ->macro di threading , viene espansa in qualcosa di simile (fn [arg1] (-> arg1)), che si espande di nuovo in (fn [arg1] arg1), che è solo quello che volevi. Trovo anche la combinazione di macro ->e #(...)utile per scrivere semplici funzioni che restituiscono vettori, ad esempio:

#(-> [%2 %1])

20

Quando lo usi #(...), puoi immaginare di scrivere (fn [args] (...)), comprese le parentesi che hai iniziato subito dopo il cancelletto.

Quindi, il tuo esempio non funzionante viene convertito in:

((fn [s] (s)) "Eh")

che ovviamente non funziona perché stai cercando di chiamare la stringa "Eh". Il tuo esempio con strfunziona perché ora la tua funzione è (str s)invece di (s). (identity s)sarebbe l'analogo più vicino al tuo primo esempio, dal momento che non costringe a str.

Ha senso se ci pensi, dal momento che oltre a questo esempio totalmente minimo, ogni funzione anonima chiamerà qualcosa , quindi sarebbe un po 'sciocco richiedere un altro insieme annidato di parentesi per effettuare effettivamente una chiamata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.