2011-11-14 22 views
5

Tôi muốn xác định macro chọn ngẫu nhiên một trong các biểu thức đã cho và đánh giá nó. Ví dụ:Clojure: cách đánh giá biểu mẫu được trích dẫn trong phạm vi địa phương?

(equal-chance 
    (println "1") 
    (println "2")) 

phải in "1" một nửa thời gian và "2" nửa còn lại.

tôi đã cố gắng sử dụng,

(defmacro equal-chance 
    [& exprs] 
    `(rand-nth '~exprs)) 

nhưng điều này trả về một trong những dạng trích dẫn, chứ không phải là đánh giá nó (tức là nó sẽ quay trở lại (println "1") hơn là thực sự in ấn "1"). Tôi không thể sử dụng eval vì nó không giữ lại các ràng buộc. Ví dụ:

(let [x 10] (eval '(println x))) 

phàn nàn rằng không thể giải quyết biểu tượng x.

Có cách nào để đánh giá biểu mẫu được trích dẫn trong phạm vi địa phương không? Hoặc có thể có một cách tốt hơn để đi về điều này?

Trả lời

2

Bạn không thể đánh giá giá trị thời gian chạy trong môi trường từ vựng chỉ tồn tại trong thời gian biên dịch. Các giải pháp là sử dụng fn thay vì quote và một cuộc gọi chức năng thay vì eval:

(defmacro equal-chance [& exprs] 
    `((rand-nth [[email protected](map (fn [e] `(fn [] ~e)) exprs)]))) 

Cách làm việc này là bằng cách mở rộng (equal-chance e1 e2 ...) vào ((rand-nth [(fn [] e1) (fn [] e2) ...])).

+0

hoạt động tuyệt vời! không bao giờ có thể tự tìm ra điều này, cảm ơn – Ken

+0

Tôi thích sử dụng độ trễ/lực thay vì fn/cuộc gọi cho điều này: '(force (rand-nnth [~ @ (bản đồ (liệt kê một phần \ 'trì hoãn) exprs)])) ' – amalloy

1

Chỉ cần không báo giá cuộc gọi đến rand-nth hoặc biểu thức. Điều này sẽ làm những gì bạn muốn:

(defmacro equal-chance 
    [& exprs] 
    (rand-nth exprs)) 
+2

Tính năng này không hoạt động đối với tất cả các trường hợp. '(dấu chấm [i 10] (bằng cơ hội 1 2 3))' sẽ trả về một trong những số đó 10 lần. – Ken

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