web-dev-qa-db-fra.com

Raccourci de fonction anonyme

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

Les oeuvres suivantes:

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

Mais cela ne veut pas:

REPL>  (#(%) "Eh")

Cela marche:

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 in - ((fn [s] s) "Eh")

Ce sont deux fonctions anonymes et elles prennent toutes les deux, ici, un paramètre. Pourquoi la notation abrégée a-t-elle besoin d'une fonction alors que l'autre notation n'en a pas?

84
Cedric Martin
#(...)

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 provient 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.

Étant donné que la sténographie fournit un ensemble de parenthèses autour du corps, elle ne peut être utilisée que pour exécuter un appel de fonction unique ou un formulaire spécial.

123
Barmar

Comme les autres réponses l'ont déjà très bien souligné, la #(%) que vous avez publiée se développe en fait à quelque chose comme (fn [arg1] (arg1)), Qui n'est pas du tout la même chose 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 de répartition #(...), vous pouvez le faire comme ça:

#(-> %)

En combinant la macro de répartition #(...) avec la macro de thread -> , elle est étendue à quelque chose comme (fn [arg1] (-> arg1)), Qui se développe à nouveau en (fn [arg1] arg1), c'est juste ce que vous vouliez. Je trouve également les combinaisons de macros -> Et #(...) utiles pour écrire des fonctions simples qui renvoient des vecteurs, par exemple:

#(-> [%2 %1])
62
DaoWen

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

Ainsi, votre exemple non fonctionnel se convertit en:

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

ce qui évidemment ne fonctionne pas parce que vous essayez de appeler la chaîne "Eh". Votre exemple avec str fonctionne parce que 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 contraindra pas str.

Cela a du sens si vous y pensez, car à part cet exemple totalement minimal, chaque fonction anonyme va appeler quelque chose, il serait donc un peu stupide d'exiger un autre ensemble de parens imbriqué pour réellement passer un coup de téléphone.

20
John Flatness