Skrót funkcji anonimowej

85

Jest coś, czego nie rozumiem w przypadku funkcji anonimowych używających krótkiej notacji # (..)

Następujące prace:

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

Ale to nie jest:

REPL>  (#(%) "Eh")

To działa:

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

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

Obie są funkcjami anonimowymi i obie przyjmują tutaj jeden parametr. Dlaczego notacja skrócona potrzebuje funkcji, a druga nie?

Cedric Martin
źródło

Odpowiedzi:

126
#(...)

jest skrótem od

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

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

#(%)

jest przetłumaczone na:

(fn [arg1] (arg1))

Zauważ, że różni się to od Twojej pierwszej funkcji anonimowej, która wygląda następująco:

(fn [arg1] arg1)

Twoja wersja zwraca arg1 jako wartość, wersja, która pochodzi z rozwinięcia skrótu, próbuje wywołać ją jako funkcję. Otrzymujesz błąd, ponieważ ciąg nie jest prawidłową funkcją.

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

Barmar
źródło
64

Jak już bardzo ładnie wskazały inne odpowiedzi, #(%)opublikowany przez Ciebie tekst w rzeczywistości rozszerza się do czegoś podobnego (fn [arg1] (arg1)), co wcale nie jest tym samym, co (fn [arg1] arg1).

@John Flatness wskazał, że możesz po prostu użyć identity, ale jeśli szukasz sposobu na pisanie identityza pomocą #(...)makra wysyłki, możesz to zrobić w następujący sposób:

#(-> %)

Poprzez połączenie #(...)makra wysyłki z makrem ->wątków , zostaje ono rozwinięte do czegoś podobnego (fn [arg1] (-> arg1)), które ponownie rozszerza się do (fn [arg1] arg1), co jest po prostu pożądane. Ja również znaleźć ->i #(...)makro combo pomocne przy pisaniu funkcje proste, że wektory powrotne, np:

#(-> [%2 %1])
DaoWen
źródło
20

Kiedy używasz #(...), możesz sobie wyobrazić, że zamiast tego piszesz (fn [args] (...)), włączając nawiasy, które zacząłeś zaraz po funcie.

Tak więc Twój niedziałający przykład przekształca się w:

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

co oczywiście nie działa, ponieważ próbujesz wywołać ciąg „Eh”. Twój przykład z strdziała, ponieważ teraz twoja funkcja jest (str s)zamiast (s). (identity s)byłby bliższym odpowiednikiem pierwszego przykładu, ponieważ nie będzie zmuszony do str.

Jeśli się nad tym zastanowić, ma to sens, ponieważ poza tym całkowicie minimalnym przykładem każda anonimowa funkcja będzie coś wywoływać , więc byłoby trochę głupotą wymagać kolejnego zagnieżdżonego zestawu parametrów, aby faktycznie wykonać wywołanie.

John Flatness
źródło