2010-04-05 8 views
5

Wenn ich Folgendes tun:(teilweise gelten str) und apply-str in clojure des ->

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

... Ich erhalte eine Teilfunktion zurück. Wenn ich es jedoch an eine Variable binde:

... der Code funktioniert, wie ich es beabsichtigte. Ich würde annehmen, dass sie das Gleiche sind, aber das ist offensichtlich nicht der Fall. Kann mir jemand erklären, warum das für mich ist?

Antwort

6

-> ist ein Makro, also muss es nicht den Regeln folgen, die Sie in Bezug auf die Anwendung erwarten würden. Das Makro transformiert die Quelle, bevor die Formulare ausgewertet werden. Versuchen Sie, die Formulare zu erweitern:

Was möchten Sie hier erreichen, indem Sie das Makro '->' verwenden?

EDIT: dass Hinweis:

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

Der Code, den ich schreiben möchte, ist etwas komplexer als das. Dies ist nur ein vereinfachtes Beispiel. Ich möchte nur ein besseres Verständnis davon bekommen, wie das '->' Makro funktioniert. :-) –

+0

Ah, hab ich. Wie auch immer, siehst du, was hier vor sich geht? –

+0

Ja, das tue ich. Danke für deine Antwort! –

5

Sie nicht, dass überhaupt zu tun haben.

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

Warum nicht stattdessen?

4

Der erste Ausdruck, , expandiert in:

(partial ["1" "2"] apply str) die im Grunde bedeutet:

aus ["1" "2"] eine Funktion erstellen (die auch eine Funktion ist, da Vektoren Funktionen der Indexschlüssel sind!) Mit dem Vars apply und str bereits als die ersten beiden Argumente geliefert. Diese Funktion wird als seltsame Zeichenfolge #<core$partial...> gedruckt. Nur wenn diese Funktion aufgerufen wird, erhalten Sie eine IllegalArgumentException, da Vektoren nur ein Integer-Argument und nicht zwei Var-Argumente verwenden.

+0

Bitte beachten Sie, dass Clojure dynamisch ist die Tatsache, dass Vektoren Funktionen sind, spielt keine Rolle für diesen Fehler. (Teilweise "Hallo" "Welt") gibt auch eine Funktion zurück - eine Funktion, die aber immer wirft. – cgrand

0

Das -> Makro fügt Parens um apply-str in Ihrer zweiten Version hinzu, weshalb das Makro zu Code erweitert wird, der Ihre Funktion schließlich aufruft. Schauen Sie sich den Quellcode für -> und Sie können sehen:

(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]))) 

Der relevante Teil ist, wenn es mit zwei Argumenten zu tun, x und form. Wenn form ein Seq ist, wird x als das zweite Argument in der Liste eingefügt. Andernfalls fügt das Makro form und x es in eine Liste selbst ein. So können Sie ein leeres Symbol als Kurzform für eine Liste mit einem Symbol verwenden.

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

Das Makro -> Themen der ausdr durch die Formen als zweites Argument. In Ihrem Fall endet bei der Erweiterung auf: (partial ["1" "2"] apply str), Erstellen einer Parital-Funktion basierend auf Vektor.

Aber Sie wollen eine parital Funktion aufrufen, basierend auf anwenden und str auf dem Gewinde ausdr und somit müssen:

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

Well: dieser Code i ziemlich verwirrend und nicht idiomatischen Clojure.