2013-06-06 14 views
7

Se definisco esplicitamente una funzione come questa (defn f [x] (get x "a")), , allora sia (-> {"a" 1} f) che (f {"a" 1}) funzionano come previsto.Clojure: come è defn diverso da fn?

Tuttavia, se sto usando la funzione anonima, solo (#(get % "a") {"a" 1}) opere ma (-> {"a" 1} #(get % "a")) tiri eccezione: CompilerException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot \ be cast to clojure.lang.ISeq, compiling:(NO_SOURCE_PATH:1:1)

risposta

12

#(get % "a") si espande dal lettore:

user=> '#(get % "a") 
(fn* [p1__852#] (get p1__852# "a")) 

È possibile ignorare la differenza tra fn e fn * in questo caso.

(-> ...) è una macro che proprio rethreads i suoi argomenti:

user=> (macroexpand-1 '(-> {"a" 1} f)) 
(f {"a" 1}) 

Nota che avvolge solo parentesi intorno f se non ci sono quelli già, quindi:

user=> (macroexpand-1 '(-> {"a" 1} (f))) 
(f {"a" 1}) 

Ma che ha vinto' t lavoro come ci si potrebbe aspettare se applicato a fn macro:

user=> (macroexpand-1 '(-> {"a" 1} (fn [x] (get x "a")))) 
(fn {"a" 1} [x] (get x "a")) 

O su # (...) forme Reader:

user=> (macroexpand-1 '(-> {"a" 1} #(get % "a"))) 
(fn* {"a" 1} [p1__867#] (get p1__867# "a")) 

La soluzione generale è quello di mettere la vostra funzione anonima all'interno di una lista, anche se è possibile utilizzare una funzione chiamata, penso che legge molto chiara:

user=> (macroexpand-1 '(-> {"a" 1} (#(get % "a")))) 
((fn* [p1__870#] (get p1__870# "a")) {"a" 1}) 
Problemi correlati