2012-11-03 8 views
76

Coś nie rozumiem o anonimowych funkcji stosując krótkie notacji # (..)funkcja Anonymous skrótowym

następujące prace:

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

ale to nie:

REPL> (#(%) "Eh") 

to działa:

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

Nie rozumiem, dlaczego (# (%) "Eh") nie działa, a jednocześnie nie muszę używać str w ((fn [s] s) " Eh ")

Oba są funkcjami anonimowymi i przyjmują tutaj jeden parametr. Dlaczego notacja skrócona potrzebuje funkcji, podczas gdy druga notacja nie działa?

Odpowiedz

115
#(...) 

jest skrótem

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

(gdzie liczba argN zależy od tego, ile% N masz w organizmie). Więc kiedy piszesz:

#(%) 

to tłumaczone:

(fn [arg1] (arg1)) 

Zauważ, że różni się od swojej pierwszej anonimowej funkcji, która jest jak:

(fn [arg1] arg1) 

przywracany wersja arg1 jako wartość, wersja, która pochodzi z rozszerzenia skrótu, próbuje nazwać ją funkcją. Otrzymujesz błąd, ponieważ ciąg nie jest prawidłową funkcją.

Ponieważ skrót stanowi zestaw nawiasów wokół ciała, można go użyć tylko do wykonania pojedynczego wywołania funkcji lub specjalnego formularza.

18

Podczas korzystania #(...), można sobie wyobrazić, że zamiast pisać ty (fn [args] (...)), tym nawiasach początek tuż po funta.

Więc twój nieprodukcyjnym przykład konwertuje do:

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

co oczywiście nie działa, ponieważ próbujesz rozmowy napisu „Eh”. Twój przykład z str działa, ponieważ teraz twoja funkcja to (str s) zamiast (s). (identity s) byłby bliżej analogiczny do twojego pierwszego przykładu, ponieważ nie będzie zmuszał do str.

To ma sens, jeśli się nad tym zastanowić, ponieważ zupełnie inny niż ten minimalny przykład, każda funkcja anonimowa ma zamiar zadzwonić coś, więc byłoby to trochę głupie wymaga innego zestawu zagnieżdżonego parens faktycznie zrobić połączenie.

56

Jak inne odpowiedzi zostały już bardzo dobrze wskazane, opublikowany #(%) rozszerza się na coś takiego, jak (fn [arg1] (arg1)), co wcale nie jest takie samo jak (fn [arg1] arg1).

@John płaskości wskazał, że można po prostu użyć identity, ale jeśli szukasz sposobu, aby napisać identity pomocą makra #(...) wysyłki, można to zrobić tak:

#(-> %) 

Łącząc makro wysyłki #(...) z -> threading macro zostaje rozwinięte do czegoś podobnego do (fn [arg1] (-> arg1)), które rozwija się ponownie do (fn [arg1] arg1), który jest pożądany. Uważam także, że kombinacja makr -> i #(...) jest pomocna przy pisaniu prostych funkcji zwracających wektory, np .:

#(-> [%2 %1]) 
Powiązane problemy