2013-06-06 21 views
7

Jeśli jawnie zdefiniuję funkcję podobną do tej (defn f [x] (get x "a")), , wówczas oba (-> {"a" 1} f) i (f {"a" 1}) działają zgodnie z oczekiwaniami.Clojure: jak defn różni się od fn?

Jednakże, jeśli używam funkcji anonimowej, ale tylko (#(get % "a") {"a" 1}) prace (-> {"a" 1} #(get % "a")) rzuca wyjątek: CompilerException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot \ be cast to clojure.lang.ISeq, compiling:(NO_SOURCE_PATH:1:1)

Odpowiedz

12

#(get % "a") jest rozszerzany przez czytelnika:

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

można zignorować różnicę pomiędzy Fn i fn * w tym przypadku.

(-> ...) jest makro, które po prostu rethreads swoje argumenty:

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

pamiętać, że tylko otacza nawiasów wokół f, jeśli nie są już tymi, więc:

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

ale to won” t działa tak, jak można się spodziewać po zastosowaniu do fn makr:

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

lub na # (...) formy czytnika:

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

Ogólnym rozwiązaniem jest umieścić swoją anonimową funkcję wewnątrz listy, ale jeśli można użyć funkcji o nazwie, myślę, że to brzmi dużo wyraźniej:

user=> (macroexpand-1 '(-> {"a" 1} (#(get % "a")))) 
((fn* [p1__870#] (get p1__870# "a")) {"a" 1}) 
Powiązane problemy