2010-04-05 6 views
5

Si je fais ce qui suit:(partiel appliquer str) et appliquer-str dans de Clojure ->

user=> (-> ["1" "2"] (partial apply str)) 
#<core$partial__5034$fn__5040 [email protected]> 

... Je Retournons une fonction partielle. Cependant, si je le lie à une variable:

user=> (def apply-str (partial apply str)) 
#'user/apply-str 
user=> (-> ["1" "2" "3"] apply-str)  
"123" 

... le code fonctionne comme je l'ai voulu. Je suppose qu'ils sont la même chose, mais apparemment ce n'est pas le cas. Quelqu'un peut-il expliquer pourquoi c'est pour moi?

Répondre

6

-> est une macro, donc il ne doit pas suivre les règles que vous attendez en termes d'application. La macro transforme la source avant l'évaluation des formulaires. Essayez macroexpanding les formes:

user> (macroexpand '(-> ["1" "2"] (partial apply str))) 
(partial ["1" "2"] apply str) 

Qu'est-ce que vous essayez d'atteindre ici en utilisant le - macro « > »?

EDIT: Notez que:

user> ((partial apply str) ["1" "2"]) 
"12" 
+0

Le code que j'essaie d'écrire est un peu plus complexe que cela. Ceci est juste un exemple simplifié. Je veux juste mieux comprendre comment fonctionne la macro '->. :-) –

+0

Ah, c'est vrai. De toute façon, vous voyez ce qui se passe ici? –

+0

Oui, oui. Merci pour votre réponse! –

5

Vous ne devez pas le faire du tout.

(->> ["1" "2" "3"] (apply str)) 

Pourquoi ne pas le faire à la place?

4

La première expression, , développe dans:

(partial ["1" "2"] apply str) ce qui signifie essentiellement:

Créer une fonction de ["1" "2"] (qui est également une fonction, puisque les vecteurs sont des fonctions de clés d'index!) Avec les Vars apply et str déjà fournis comme les deux premiers arguments. Cette fonction est imprimée comme la chaîne #<core$partial...> bizarre. Ce n'est que lorsque cette fonction sera appelée que vous obtiendrez une exception IllegalArgumentException, car les vecteurs ne prennent qu'un argument entier, pas deux arguments Var.

+0

s'il vous plaît noter que Clojure étant dynamique le fait que les vecteurs sont des fonctions n'a pas d'importance pour ce bug. (partiel "hello" "world") renvoie une fonction aussi - une fonction qui jette toujours bien. – cgrand

0

La macro -> ajoute des parens autour de apply-str dans votre deuxième version, c'est pourquoi la macro se développe en code qui finit par appeler votre fonction. Regardez le code source pour -> et vous pouvez voir:

(defmacro -> 
    "Threads the expr through the forms. Inserts x as the 
    second item in the first form, making a list of it if it is not a 
    list already. If there are more forms, inserts the first form as the 
    second item in second form, etc." 
    ([x] x) 
    ([x form] (if (seq? form) 
       (with-meta `(~(first form) ~x [email protected](next form)) (meta form)) 
       (list form x))) 
    ([x form & more] `(-> (-> ~x ~form) [email protected]))) 

La partie pertinente est quand il a affaire à deux arguments, x et form. Si form est un seq, x est inséré comme second argument dans cette liste. Sinon, la macro met form et dans une liste elle-même. C'est ainsi que vous pouvez utiliser un symbole nu comme raccourci pour une liste contenant un symbole.

user> (macroexpand '(-> 123 (foo))) 
(foo 123) 
user> (macroexpand '(-> 123 foo)) 
(foo 123) 
1

la macro -> Fils l'expr par les formes comme second argument. Dans votre cas finit par étendre à: (partial ["1" "2"] apply str), créant une fonction paritaire basée sur le vecteur.

Mais vous voulez invoquer une fonction parital basée sur Appliquer et str sur la expr filetée et donc besoin:

(-> ["1" "2"] ((partial apply str))) 

Eh bien: ce code i assez déroutant et non idiomatiques Clojure.

Questions connexes