2013-06-06 1 views
7

Если я точно определяю функцию, подобную этой (defn f [x] (get x "a")), , то и (-> {"a" 1} f), и (f {"a" 1}) работают должным образом.Clojure: как defn отличается от fn?

Однако, если я использую анонимные функции, только работает, но (#(get % "a") {"a" 1})(-> {"a" 1} #(get % "a")) бросает исключение: CompilerException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot \ be cast to clojure.lang.ISeq, compiling:(NO_SOURCE_PATH:1:1)

ответ

12

#(get % "a") расширяется читателем:

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

Вы можете игнорировать разницу между Fn и Fn * в этом случае.

(-> ...) макрос, который только rethreads аргументы:

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

Обратите внимание, что он оборачивает только круглые скобки вокруг е, если не те уже, так:

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

Но что выиграл» т, как можно было бы ожидать при применении к fn. Макросы:

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

Или на # (...) Читатель формы:

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

Общее решение поместить вашу анонимную функцию внутри списка, хотя, если вы можете использовать функцию с именем, я думаю, что много читает яснее:

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