2012-05-24 8 views
25

Ich verstehe das Makro -> in clojure wendet alle Funktionen auf das Argument gegeben. Es scheint jedoch nicht mit anonymen Funktionen zu funktionieren (auf clojure 1.3.0). Zum Beispiel:Makro -> mit anonymen Funktionen

user> (-> 4 inc inc dec) 
5 

Aber:

user> (-> 4 #(+ % 1) #(- % 1) #(+ % 1)) 

Gibt den Fehler:

clojure.lang.Symbol cannot be cast to clojure.lang.IPersistentVector 
[Thrown class java.lang.ClassCastException] 

Wenn jemand einen Weg, um es wäre hilfreich, weiß. Vielen Dank!

+3

möglich Duplikat von [Funktionsaufruf in -> threading Makro] (http://StackOverflow.com/questions/7838326/Function-Call-in-Threading-Macro) – amalloy

Antwort

31

Sie können anonyme Funktionen in Clojure-Makros verwenden. Sie haben Probleme, weil Ihnen einige Klammern fehlen. :) Dein Beispiel ist unten bearbeitet.

(-> 4 (#(+ % 1)) (#(- % 1)) (#(+ % 1))) 
+0

Ja, es funktioniert jetzt! Ich hatte Angst, dass das Makro -> anonyme Funktionen nicht mochte, aber einfach das Hinzufügen der Parens macht den Trick. Danke – S4M

+1

Check out 'macroexpand', um genau zu wissen, warum es extra parens braucht, um zu arbeiten ... es ist interessantes Zeug :) – Ankur

+0

Ankur: wird tun! Danke noch einmal. – S4M

24

(dies i in den Kommentaren gepostet auf der answer auf die Frage basiert).

das -> Makro nimmt jedes Argument, eine Liste zu machen, falls erforderlich („raw“ Funktionen ohne args Anwendung - myfunc-(myfunc) Umwandlung) und fügt dann das erste Argument -> als zweites Argument in jedem dieser Listen.

so (-> foo myfunc) wird (-> foo (myfunc)) wird (myfunc foo), grob.

Dies ist alles in der docs for -> beschrieben.

Das Problem mit anonymen Funktionen ist, dass sie von einem Lesemakro wie described here (scroll down) erzeugt werden. Das bedeutet, dass #(...) (vor normale Makroexpansion) in (fn [...] ...) konvertiert wird. Das ist in Ordnung, aber, kritisch, ist bereits eine Liste.

so glaubt das Makro, dass die anonyme Funktion bereits angewendet wird, wenn es tatsächlich eine Funktionsdefinition (beide Listen) ist. und das Hinzufügen der "extra" -Parens - wie oben in der anderen Antwort beschrieben - wendet die anonyme Funktion auf keine Argumente an.

Der Grund für dieses unintuitive Verhalten ist, dass die dwim (do-was-i-mean, nicht dwim-witted, obwohl ...) Heuristik vom -> Makro verwendet wird, um Ihnen zu ermöglichen, "bare" zu liefern "Funktionen, anstatt dass Sie sie auf keine Argumente anwenden, indem Sie sie in eine Liste einschließen, ist nur eine Heuristik - es testet einfach für eine Liste - und ist durch die Funktionsdefinition durch den Leser Makro verwirrt.

[in meiner schlechten Meinung, -> ist schlecht implementiert und sollte stattdessen alle "bare" Funktionen ablehnen, sondern nur Funktionsanwendungen akzeptieren; es würde dann konsequenter erscheinen. wenn nicht, dann könnten zumindest die Dokumente klarer sein und die motivierende Semantik hinter dem Platzieren von Dingen in Listen erklären.]

1

Ihr spezieller Fall einfach mit Hilfe hätte gelöst werden kann:

das Ergebnis das Einsetzens des vorherigen Schrittes als erstes Argument in der „aktuellen“ Funktion
(-> 4 (+ 1) (- 1) (+ 1)) 

wo der Faden ersten Makro -> Pflege nimmt.

Die Verwirrung ergibt sich aus der Tatsache, dass -> keine Funktion ist, sondern ein Makro und die Argumente werden in diesem Fall sehr unterschiedlich behandelt, wie von anderen Antworten erklärt.

Verwandte Themen