2013-06-06 34 views
7

Nếu tôi xác định rõ ràng một chức năng như thế này (defn f [x] (get x "a")), thì cả hai (-> {"a" 1} f)(f {"a" 1}) đều hoạt động như mong đợi.Clojure: defn khác với fn như thế nào?

Tuy nhiên, nếu tôi đang sử dụng chức năng ẩn danh, chỉ (#(get % "a") {"a" 1}) công trình nhưng (-> {"a" 1} #(get % "a")) ném ngoại lệ: CompilerException java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot \ be cast to clojure.lang.ISeq, compiling:(NO_SOURCE_PATH:1:1)

Trả lời

12

#(get % "a") được mở rộng bởi người đọc:

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

Bạn có thể bỏ qua sự khác biệt giữa fn và fn * trong trường hợp này.

(-> ...) là một vĩ mô mà chỉ rethreads đối số của nó:

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

Lưu ý rằng nó chỉ kết thúc tốt đẹp ngoặc xung quanh f nếu không có những người đã, vì vậy:

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

Nhưng đó won' hoạt động như bạn có thể mong đợi khi áp dụng cho các macro fn:

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

Hoặc trên # (...) các hình thức đọc:

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

Các giải pháp chung là đặt chức năng ẩn danh của bạn bên trong một danh sách, tuy nhiên nếu bạn có thể sử dụng một hàm có tên, tôi nghĩ rằng nó đọc rõ ràng hơn rất nhiều:

user=> (macroexpand-1 '(-> {"a" 1} (#(get % "a")))) 
((fn* [p1__870#] (get p1__870# "a")) {"a" 1}) 
Các vấn đề liên quan