Fonction anonyme raccourci

Il y a quelque chose que je ne comprends pas à propos des fonctions anonymes utilisant la notation courte #(..)

Les œuvres suivantes:

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

Mais ce n'est pas le cas:

REPL>  (#(%) "Eh")

Cela fonctionne:

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

Ce que je ne comprends pas, c'est pourquoi (#(%) "Eh") ne fonctionne pas et en même temps je n'ai pas besoin d'utiliser str dans ((fn [s] s) "Hein")

Ce sont toutes les deux des fonctions anonymes et elles prennent toutes les deux, ici, un paramètre. Pourquoi la notation abrégée besoin d'une fonction alors que l'autre notation ne le fait pas?

78
demandé sur Cedric Martin 2012-11-03 05:00:11

3 réponses

#(...)

Est un raccourci pour

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

(où le nombre d'argN dépend du nombre de %n que vous avez dans le corps). Donc, quand vous écrivez:

#(%)

Il est traduit en:

(fn [arg1] (arg1))

Notez que ceci est différent de votre première fonction anonyme, qui est comme:

(fn [arg1] arg1)

Votre version renvoie arg1 en tant que valeur, la version qui vient de l'expansion du raccourci essaie de l'appeler en tant que fonction. Vous obtenez une erreur car une chaîne n'est pas une fonction valide.

Depuis le sténographie fournit un ensemble de parenthèses autour du corps, il ne peut être utilisé pour exécuter un seul appel de fonction ou un formulaire spécial.

119
répondu Barmar 2012-11-03 02:50:33

Comme les autres réponses l'ont déjà très bien souligné, le #(%) que vous avez posté s'étend en fait à quelque chose comme (fn [arg1] (arg1)), qui n'est pas du tout le même que (fn [arg1] arg1).

@ John Flatness a souligné que vous pouvez simplement utiliser identity, mais si vous cherchez un moyen d'écrire identity en utilisant la macro #(...) dispatch, vous pouvez le faire comme ceci:

#(-> %)

En combinant la macro #(...) dispatch avec -> threading macro Il est étendu à quelque chose comme (fn [arg1] (-> arg1)), qui se développe à nouveau à (fn [arg1] arg1), ce qui est juste que vous vouliez. Je trouve également le combo de macro -> et #(...) utile pour écrire des fonctions simples qui renvoient des vecteurs, par exemple:

#(-> [%2 %1])
58
répondu DaoWen 2012-11-03 05:30:46

Lorsque vous utilisez #(...), vous pouvez imaginer que vous écrivez à la place (fn [args] (...)), y compris {[9] } les parenthèses que vous avez commencé juste après La Livre.

Ainsi, votre exemple non fonctionnel se convertit en:

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

Ce qui ne fonctionne évidemment pas parce que vous essayez de appeler la chaîne "Eh". Votre exemple avec str fonctionne car maintenant votre fonction est (str s) au lieu de (s). (identity s) serait l'analogue le plus proche de votre premier exemple, car il ne forcera pas à str.

Il fait sens si vous y réfléchissez, car à part cet exemple totalement minimal, chaque fonction anonyme va appeler quelque chose , Il serait donc un peu stupide d'exiger un autre ensemble imbriqué de parens pour faire un appel.

20
répondu John Flatness 2012-11-03 01:33:01