2012-03-13 47 views
10

Tôi muốn viết macro sử dụng các hàm từ thư viện clj-time. Trong một không gian tên tôi muốn gọi vĩ mô như thế này:Sự nhầm lẫn và không gian tên

(ns budget.account 
    (:require [budget.time])) 

(budget.time/next-date interval frequency) 

vĩ mô tiếp theo được cập nhật sẽ được xác định trong tập tin khác như thế này:

(ns budget.time 
    (:require [clj-time.core :as date])) 

(defmacro next-date [interval freq] 
    `(~interval ~freq)) 

Nếu macro được gọi với các đối số sau đây (budget.time/freq khoảng thời gian tiếp theo) và khoảng thời gian và freq nơi "tuần" và "2" repectively sau đó mở rộng vĩ mô sẽ giống như thế này (clj-time.core/tuần 2)

Bất cứ khi nào tôi thử điều này từ REPL nó không thể giải quyết không gian tên.

Có cách nào để buộc macro phân giải khoảng thời gian thành đối số cho không gian tên clj-time không? Cách tốt nhất để làm việc này là gì?

Cảm ơn!

+0

Tại sao bạn cần viết macro. Điều này có thể được thực hiện bởi một chức năng bình thường không? Hãy nhớ rằng: bạn không bao giờ nên viết macro khi một hàm sẽ thực hiện. – viebel

Trả lời

10

Macro trả về danh sách sau đó được đánh giá trong không gian tên mà nó được gọi, không phải không gian tên được xác định. Điều này khác với các hàm đánh giá trong không gian tên mà chúng được xác định. Đây là vì các macro trả về mã để chạy, thay vì chỉ chạy nó.

nếu tôi đi đến không gian tên khác, ví dụ hello.core và mở rộng một cuộc gọi đến tiếp theo ngày tôi nhận được:

hello.core> (macroexpand-1 '(next-date weeks 2)) 
(weeks 2) 

sau đó sau khi mở rộng, tuần được giải quyết từ hello.core, trong đó nó là tất nhiên là không được định nghĩa. để khắc phục điều này, chúng ta cần biểu tượng trả về để mang thông tin không gian tên với nó.

may mắn thay bạn có thể giải quyết rõ ràng biểu tượng trong không gian tên với ns-resolve. Phải mất một namespace và một biểu tượng và cố gắng để tìm thấy nó trong không gian tên trở về con số không nếu nó không tìm thấy

(ns-resolve 'clj-time.core (symbol "weeks")) 
#'clj-time.core/weeks 

tiếp theo macro của bạn sẽ được tham gia một biểu tượng và một số vì vậy chúng tôi có thể phân chia với các cuộc gọi rõ ràng để symbol

(ns-resolve 'clj-time.core 'weeks) 
#'clj-time.core/weeks 

vì vậy bây giờ bạn chỉ cần một chức năng giải quyết các chức năng và sau đó tạo ra một danh sách các chức năng giải quyết tiếp theo là số,

(defmacro next-date [interval freq] 
    (list (ns-resolve 'clj-time.core interval) freq)) 

Trong macro trên tất cả nó làm là thực hiện cuộc gọi chức năng mà được gọi là lập tức, vì vậy bạn thậm chí không cần một macro cho việc này:

(defn next-date [interval freq] 
    ((ns-resolve 'clj-time.core interval) freq)) 
(next-date 'weeks 2) 
#<Weeks P2W> 

phiên bản phi vĩ mô đòi hỏi bạn phải trích dẫn khoảng vì nó cần nó không được đánh giá trước khi bạn có thể tra cứu nó. Những gì macro thực sự mua bạn ở đây không phải bao gồm báo giá, với chi phí yêu cầu tất cả người gọi yêu cầu clj-time

tất nhiên bạn cũng có thể yêu cầu thời gian ở mọi nơi, nhưng đó không thực sự là điểm .

+1

Có tốt hơn khi yêu cầu clj-time ở mọi nơi hoặc sử dụng ns-resolve không? – user1265564

+1

cá nhân tôi thấy yêu cầu clj-thời gian ở khắp mọi nơi như là lựa chọn sạch hơn. –