2010-06-01 25 views
5

Tôi muốn có một macro mà tôi sẽ gọi def-foo. Def-foo sẽ tạo ra một hàm, và sau đó sẽ thêm hàm này vào một tập hợp.Tôi có thể tạo một macro clojure để cho phép tôi có được danh sách tất cả các hàm được tạo bởi macro không?

Vì vậy, tôi có thể gọi

(def-foo bar ...) 

(def-foo baz ...) 

Và sau đó sẽ có một số bộ, ví dụ tất cả-foos, mà tôi có thể gọi:

all-foos 
=> #{bar, baz} 

Về cơ bản, tôi chỉ cố gắng tránh lặp lại bản thân mình. Tất nhiên tôi có thể xác định các chức năng theo cách thông thường, (defn bar ...) và sau đó viết các thiết lập bằng tay.

Một lựa chọn tốt hơn, và đơn giản hơn so với ý tưởng vĩ mô, sẽ làm:

(def foos #{(defn bar ...) (defn baz ...)}) 

Nhưng tôi vẫn tò mò về việc liệu có một cách tốt cho các ý tưởng vĩ mô để làm việc.

Trả lời

5

Bạn có muốn kết thúc với một bộ có tên của các hàm trong nó (tức là một tập hợp các Ký hiệu), hoặc một tập hợp chứa các vars (mà giải quyết cho các hàm)? Nếu bạn muốn trước đây, bạn có thể thêm các biểu tượng vào một nguyên tử trong macro tại thời gian biên dịch, giống như phiên bản của Greg Harman.

Nếu bạn muốn sau này, macro của bạn phải mở rộng đến mã thực hiện hoán đổi nguyên tử sau khi hàm được xác định. Hãy nhớ rằng các macro chạy tại thời gian biên dịch và kết quả mở rộng macro chạy tại thời gian chạy; bản thân chức năng không có sẵn cho đến thời gian chạy.

(def all-foos (atom #{})) 

(defmacro def-foo [x] 
    `(let [var# (defn ~x [] (println "I am" '~x))] 
    (swap! all-foos conj var#))) 

Nếu bạn muốn có thể gọi các chức năng trong bộ này, ví dụ, bạn cần sử dụng phiên bản sau.

user> (def-foo foo) 
#{#'user/foo} 
user> (def-foo bar) 
#{#'user/foo #'user/bar} 
user> ((first @all-foos)) 
I am foo 
nil 
5

Có vĩ mô thêm tên của hàm mới để thiết lập của bạn trước khi tạo các chức năng, như vậy:

(def *foos* (atom (hash-set))) 

(defmacro def-foo [name] 
    (swap! *foos* conj name) 
    `(defn ~name 
    [] 
    (println "This is a foo!"))) 

Kết quả:

user=> (def-foo bar) 
#'user/bar 
user=> (def-foo baz) 
#'user/baz 
user=> (bar) 
This is a foo! 
nil 
user=> (baz) 
This is a foo! 
nil 
user=> *foos* 
#<[email protected]: #{baz bar}> 
Các vấn đề liên quan