Abkürzung für anonyme Funktion

85

Es gibt etwas, das ich über anonyme Funktionen mit der Kurznotation # (..) nicht verstehe.

Folgendes funktioniert:

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

Das geht aber nicht:

REPL>  (#(%) "Eh")

Das funktioniert:

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

Was ich nicht verstehe ist, warum (# (%) "Eh") nicht funktioniert und ich gleichzeitig str in ((fn [s] s) "Eh") nicht verwenden muss.

Sie sind beide anonyme Funktionen und nehmen hier einen Parameter an. Warum benötigt die Kurzschreibweise eine Funktion, die andere nicht?

Cedric Martin
quelle

Antworten:

126
#(...)

ist eine Abkürzung für

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

(wobei die Anzahl von argN davon abhängt, wie viele% N Sie im Körper haben). Also, wenn Sie schreiben:

#(%)

es ist übersetzt in:

(fn [arg1] (arg1))

Beachten Sie, dass sich dies von Ihrer ersten anonymen Funktion unterscheidet.

(fn [arg1] arg1)

Ihre Version gibt arg1 als Wert zurück. Die Version, die aus dem Erweitern der Kurzschrift stammt, versucht, sie als Funktion aufzurufen. Sie erhalten eine Fehlermeldung, weil eine Zeichenfolge keine gültige Funktion ist.

Da die Kurzschrift eine Reihe von Klammern um den Körper enthält, kann sie nur zum Ausführen eines einzelnen Funktionsaufrufs oder eines speziellen Formulars verwendet werden.

Barmar
quelle
64

Wie die anderen Antworten bereits sehr gut hervorgehoben haben, #(%)erweitert sich das, was Sie gepostet haben, tatsächlich zu so etwas wie (fn [arg1] (arg1)), was überhaupt nicht dasselbe ist wie (fn [arg1] arg1).

@ John Flatness wies darauf hin, dass Sie nur verwenden können identity, aber wenn Sie nach einer Möglichkeit suchen, identitymit dem #(...)Versandmakro zu schreiben , können Sie dies folgendermaßen tun:

#(-> %)

Durch Kombinieren des #(...)Dispatch-Makros mit dem ->Threading-Makro wird es zu etwas erweitert (fn [arg1] (-> arg1)), das sich wieder zu erweitert (fn [arg1] arg1), was nur gewünscht wird. Ich finde auch die Kombination ->und #(...)Makro hilfreich, um einfache Funktionen zu schreiben, die Vektoren zurückgeben, z.

#(-> [%2 %1])
DaoWen
quelle
20

Wenn Sie verwenden #(...), können Sie sich vorstellen, dass Sie stattdessen schreiben (fn [args] (...)), einschließlich der Klammern, die Sie direkt nach dem Pfund begonnen haben.

Ihr nicht funktionierendes Beispiel wird also konvertiert in:

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

Das funktioniert offensichtlich nicht, weil Sie versuchen, die Zeichenfolge "Eh" zu nennen . Ihr Beispiel mit strfunktioniert, weil jetzt Ihre Funktion (str s)statt ist (s). (identity s)wäre das nähere Analogon zu Ihrem ersten Beispiel, da es nicht zwingt, str.

Es ist sinnvoll, wenn Sie darüber nachdenken, da abgesehen von diesem völlig minimalen Beispiel jede anonyme Funktion etwas aufruft. Es wäre also ein wenig dumm, einen anderen verschachtelten Satz von Parens zu benötigen, um tatsächlich einen Anruf zu tätigen.

John Flatness
quelle