2014-10-05 13 views
7

Có điều gì đó mà tôi phải bỏ sót về macro luồng trong Clojure.Chênh lệch lẻ giữa các hàm được đặt tên và ẩn danh khi sử dụng macro luồng

Tôi cũng có bản đồ với các giá trị là bản đồ và tôi muốn tìm kiếm kết quả của một lần tra cứu khác. Hãy để bản đồ trở thành một đơn giản {:a {:b 2}} - đầu tiên tôi muốn tìm kiếm khóa :a, tức là sẽ mang lại {:b 2}, sau đó tra cứu b, kết quả là 2. Chìa khóa cho lần tra cứu thứ hai cần phải là kết quả của một hàm.

((fn [x] (get x :b)) ({:a {:b 2} } :a)) 
=> 2 

Ok, hãy làm cho nó dễ đọc hơn với macro luồng.

(-> {:a {:b 2} } :a (fn [x] (get x :b))) 

I.e. áp dụng :a làm hàm trên bản đồ, sau đó áp dụng một hàm khác. Vâng, điều này không làm việc: CompilerException java.lang.IllegalArgumentException: Parameter declaration :a should be a vector

Lạ lùng thay, nếu chức năng ẩn danh được chiết xuất với một tên một, sau đó nó hoạt động tốt:

(defn f [x] (get x :b)) 
(-> {:a {:b 2} } :a f) 
=> 2 

Hoặc thậm chí:

(def f (fn [x] (get x :b))) 
(-> {:a {:b 2} } :a f) 
=> 2 

Tại sao có sự khác biệt giữa cách đặt tên và chức năng ẩn danh hoạt động?

Trả lời

4

Macro luồng thấy và thay đổi, mỗi biểu mẫu con trong chuỗi trước khi biểu mẫu đó được đánh giá, bằng cách đệ quy chèn biểu mẫu trước làm đối số đầu tiên cho từng biểu mẫu con.

bạn bắt đầu với:

(-> {:a {:b 2} } :a (fn [x] (get x :b))) 

này trở thành:

(-> (:a {:a {:b 2}}) (fn [x] (get x :b))) 

này trở thành:

(fn (:a {:b {:b 2}}) [x] (get x :b))) 

Mà rõ ràng là không phải những gì bạn muốn chút nào.

Nhưng chúng ta hãy xem những gì sẽ xảy ra nếu bạn thêm dấu ngoặc thêm xung quanh chức năng ẩn danh:

(-> {:a {:b 2}} :a ((fn [x] (get x :b)))) 

(-> (:a {:a {:b 2}}) ((fn [x] (get x :b)))) 

(-> ((fn [x] (get x :b)) (:a {:a {:b 2}}))) 

((fn [x] (get x :b)) (:a {:a {:b 2}})) 

Tại macroexpansion đệ quy cuối cùng của mẫu -> bây giờ chúng tôi là trái với mã hợp lệ mà những gì bạn muốn.

+0

Hmm, thú vị, cảm ơn. Tôi cần phải có được đầu của tôi xung quanh macro - rõ ràng là 'đối số đầu tiên cho mỗi subform' không có nghĩa là 'đối số đầu tiên của chức năng vô danh' - đó là cách tôi nghĩ ban đầu. –

+0

vâng, macro rất theo nghĩa đen, do đó, nó thấy và thay đổi không phải là 'fn', nhưng là lệnh gọi thành' fn'. – noisesmith

3

Để bổ sung cho phản hồi của noisesmith, trong trường hợp cụ thể này bạn không cần macro luồng. Cách thành ngữ để lấy giá trị từ bản đồ lồng nhau là get-in. ví dụ:

(get-in {:a {:b 2}} [:a :b]) 

=>

2 
+0

Thậm chí tốt hơn :) Cảm ơn. –

Các vấn đề liên quan