2010-02-25 33 views
6

Giả sử tôi có một loạt các không gian tên (táo, chuối, cam). Trong các không gian tên này, tôi sử dụng macro eat, gọi (không phải "tạo", gọi) chức năng peel. Chức năng peel là khác nhau đối với mỗi loại trái cây, nhưng các macro giống hệt nhau và khá lớn, vì vậy tôi muốn tạo một không gian tên fruit có chứa macro eat. Nhưng khi tôi gọi macro eat từ không gian tên apple, macro eat phải gọi hàm apple/peel.Câu hỏi về không gian tên và macro không gian tên

Để minh họa (nhưng điều này không làm việc):

(ns fruit) 
(defmacro eat [] (peel)) 

(ns apple) 
(defn peel [] (prn "peeled apple")) 
(fruit/eat) 

(ns banana) 
(defn peel [] (prn "peeled banana")) 
(fruit/eat) 

Để nhấn mạnh, điều này có nghĩa rằng chức năng vỏ nên được gọi là khi nào, và chỉ khi nào, vĩ mô được mở rộng, như trong ví dụ này.

(ns apple) 
(defn peel [] (prn "peeled apple")) 
(defmacro eat [] (peel)) 
(macroexpand-1 '(eat)) 

Vì vậy, mọi ý tưởng về cách kết hợp macro và đa hình?

Trả lời

1

EDIT: Rất tiếc. Tôi alread đăng sau đây. Nhưng bạn đang nói "cuộc gọi, không tạo ra" chức năng vỏ. Vì vậy, những gì tôi đã viết có lẽ không phải là những gì bạn muốn mặc dù có vẻ như nó sẽ có được kết quả dự định.

Chỉ cần trích dẫn (peel) có hiệu quả đối với tôi.

(ns fruit) 
(defmacro eat [] '(peel)) 

(ns apple) 
(defn peel [] (prn "peeled apple")) 
(fruit/eat) 

(ns banana) 
(defn peel [] (prn "peeled banana")) 
(fruit/eat) 
+0

Cảm ơn bạn, nhưng thực sự không phải ý của tôi. Nó có được kết quả mong muốn ở đây, nhưng không có trong trường hợp sử dụng thực tế của tôi. –

2
(defmacro eat [] ((var-get (resolve 'peel)))) 

Lưu ý rằng bạn đang lợi dụng không gian tên, mặc dù.

7

Những gì bạn mô tả không phải là đa hình nhưng được gọi là chụp cục bộ. Bạn muốn ăn macro để "chụp" định nghĩa cục bộ bóc.

Điều này được coi là phong cách xấu trong hầu hết các Lisps, đặc biệt là Clojure, vì nó có thể dẫn đến lỗi tinh tế và không thể đoán trước.

Một giải pháp tốt hơn là để vượt qua chính xác vỏ đến ăn vĩ mô khi bạn gọi nó là:

(ns fruit) 
(defmacro eat [peeler] `(~peeler)) 

(ns apple) 
(defn peel [] (prn "Peeled an apple")) 
(fruit/eat peel) 

Nếu bạn thực sự muốn làm chụp địa phương, bạn có thể buộc nó với một ~' (unquote-quote) trong macro:

(ns fruit) 
(defmacro eat [] `(~'peel)) 
+0

Đây không phải là điều tôi muốn nói. Tôi muốn chức năng 'bóc tách 'được gọi vào thời gian mở rộng. Tôi đã làm rõ câu hỏi. –

+0

Tôi hiểu, sẽ cung cấp một câu trả lời khác. –

3

Như đã giải thích trong câu hỏi đã chỉnh sửa, điều này hơi khác so với chụp địa phương, bởi vì bạn không sử dụng vỏ trong macroexpansion, nhưng đúng hơn là trong việc thực hiện chính macro đó.

Rất khó vì các macro không đánh giá các đối số của chúng. Ngay cả khi bạn vượt qua bóc làm đối số cho hãy ăn, bên trong nội dung của macro, đó chỉ là biểu tượng chứ không phải chức năng có thể gọi được.

Cách duy nhất để làm những gì bạn muốn (không sử dụng eval) là để giải quyết các biểu tượng ở thời gian biên dịch:

(defmacro eat [] 
    ((var-get (resolve 'peel))) 
    ... return the expansion of "eat" ...) 

Các quyết chức năng phải mất một biểu tượng và trả về Var nó được ánh xạ vào trong không gian tên hiện tại. Khi bạn có Var, bạn có thể truy xuất hàm thực tế (giá trị của Var) với var-get. Bộ ngoặc đơn bổ sung gọi hàm đó.

Không cần phải nói, đây là một thiết kế rất khác thường và có thể đảm bảo xem xét lại.

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