2014-05-14 14 views
5

Tôi đã cố gắng làm việc này với báo giá, trích dẫn quote, eval và bất kỳ điều gì khác mà tôi có thể nghĩ đến, nhưng không may mắn cho đến nay. Tôi hiểu lý do tại sao nó không hoạt động - nó được xem như là một bản đồ, và nó đang cố gắng để đánh giá a, bc - chỉ cần không làm thế nào để có được nó.Lưu trữ bản đồ phá hủy để sử dụng sau này

(def destructor {a :a b :b c :c}) 
; CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(:1:15) 

(let [destructor my-map] 
    'etc) 

Tôi có một bản đồ có liên quan đến phá hoại mà tôi đang cân nhắc sử dụng nhiều lần, vì vậy, có vẻ là một ý tưởng hay để bỏ nó đi đâu đó. Có lẽ có những cách tốt hơn để đi về nó?

Trả lời

3

Ý tưởng hay, nhưng bạn không thể làm theo cách này, bởi vì thứ bạn muốn lưu trữ không thực sự là một giá trị, vì vậy bạn không thể lưu trữ nó trong một var.

Thay vào đó, bạn có thể định nghĩa một macro trong đó bao gồm này trong việc mở rộng của nó:

(defmacro with-abc [abc & body] 
    `(let [~'{:keys [a b c]} ~abc] 
    [email protected])) 

(with-abc foo 
    (...use a, b, and c...)) 
+3

Các funny-tìm '~' 'trong mệnh đề let là a, b, và cd không nhận được không gian tên đủ điều kiện theo cú pháp-trích dẫn. Tôi nghĩ điều đó là cần thiết, nhưng hiện tại tôi không có máy tính thực sự, vì vậy nếu ai đó thấy rằng nó không cảm thấy tự do để chỉnh sửa. – amalloy

+0

Rất đẹp. Tôi không thể sử dụng ': keys' (tốt để xem nó như là một ví dụ, mặc dù), như tôi có" một bản đồ destructuring khá tham gia "(tức là của nhiều cấp độ), nhưng trao đổi trong bản đồ của tôi hoạt động tuyệt vời. Tôi đã chơi với việc sử dụng macro một chút, nhưng - mặc dù đã thành công với họ nhiều lần - tôi đoán tôi vẫn không có cái đầu hoàn toàn xoay quanh mọi thứ và nhận được một thứ hoàn toàn mới, được biến đổi hoàn toàn. Cảm ơn! –

+1

@amalloy: Đối với hồ sơ, bạn nói đúng - '~ '' là cần thiết. Tôi đã thử nghiệm nó, và nó hoạt động như là, nhưng việc loại bỏ '~ '' gây ra một 'java.lang.RuntimeException: Không thể để tên đủ điều kiện: user/a'. –

2

Something như câu trả lời @ amalloy là bản năng đầu tiên của tôi quá và nó có thể là con đường để đi. Điều đó nói rằng, nó có thể là giá trị xem xét một ol đồng bằng' chức năng bậc cao:

(defn destruct 
    [{a :a b :b c :c} f] 
    (f a b c)) 

(destruct my-map 
      (fn [a b c] 
      (println a) 
      (println b) 
      (println c))) 

Đó là nosier một chút và bạn buộc phải đặt tên cho các ràng buộc mọi thời gian, nhưng bạn tránh các vấn đề vệ sinh tiềm năng và, tùy thuộc vào mức độ thoải mái của bạn với metaprogramming, nó dễ dàng hơn một chút để đặt lại với nhau.

+0

Vâng, tôi muốn tránh đặt tên cho mọi thứ, vì bản đồ của tôi không chỉ chứa hàng chục thứ, mà chúng còn ở nhiều cấp độ làm tổ khác nhau. Tuy nhiên, tốt nhất là cố gắng tìm tuyến đường chức năng, nếu có thể. Cảm ơn. –

+0

Gotcha. Âm thanh như vĩ mô là con đường để đi sau đó. – Beyamor

0

Bạn sẽ cần phải trích dẫn mô hình huỷ

(def my-destructor '{a :a b :b c :c}) 

Bạn có thể làm điều này với mức trích dẫn/unquoting, nhưng nó là dễ dàng hơn để xem với một hàm helper ít.

(defn- with-destructor* [binding & body] 
    `(let ~binding [email protected])) 

eval này xảy ra tại "biên dịch" thời gian (trong mở rộng vĩ mô)

(defmacro with-destructor [[destructor form] & body] 
    (eval `(with-destructor* [~destructor '~form] '[email protected]))) 

Như

(macroexpand-1 '(with-destructor [my-destructor {:a 1 :c 3}] (+ a c))) 
;=> (clojure.core/let [{a :a, b :b, c :c} {:a 1, :c 3}] (+ a c)) 

quả

(with-destructor [my-destructor {:a 1 :c 3}] (+ a c)) 
;=> 4 
+0

Định nghĩa 'with-destructor' không có lý do gì để sử dụng' eval'. Cơ thể của nó chỉ nên là '(áp dụng với destructor * [destructor form] body)'.Và tất nhiên bạn có thể tránh được 'áp dụng' nếu bạn vứt bỏ các varargs từ' với-destructor * '(như, theo ý kiến ​​của tôi, bạn nên). – amalloy

+0

@amalloy Có lẽ tôi đang thiếu một cái gì đó, nhưng tôi tin rằng đề nghị của bạn sẽ chỉ làm việc với một biểu thức hủy diệt nghĩa đen như trong '(with-destructor [{a: ab: bc: c} {: a 1: c 3}] (+ ac)) ', nhưng không phải là một được lưu trữ trong một var như trong câu hỏi. –

+0

Tôi hiểu. Bạn đang cố gắng để cho 'destructor' được cung cấp bởi người dùng, không cố định cho một macro cụ thể. Tôi đã nhầm lẫn bởi vì bạn đặt tên cho đối số macro giống như var, và tôi nghĩ rằng macro đã đề cập đến var. – amalloy

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