2012-06-11 35 views
5

Tôi đang cố gắng viết macro xây dựng phần mềm trung gian tương tự như được sử dụng trong compojure.Macro clojure tạo hàm bậc cao hơn từ hàm

Tôi muốn để có thể gọi:

(def-middleware plus-two [x] 
    (+ 2 x)) 

Và có kết quả như sau:

(defn plus-two [f] 
(fn [x] 
    (f (+ 2 x))) 

Tôi đã có này xa đọc hướng dẫn trên mạng nhưng nó không làm việc ra cho tôi:

(defmacro def-middleware [fn-name args & body] 
    '(defn ~fn-name [f] 
    (fn ~args 
     (f [email protected])))) 

Bất kỳ trợ giúp hoặc con trỏ đến hướng dẫn viết vĩ mô tốt hơn sẽ là tuyệt vời, cảm ơn.

+0

Làm thế nào nó không hoạt động cho bạn? –

+0

CompilerException java.lang.RuntimeException: Đối số đầu tiên để def phải là một Symbol, biên dịch: (NO_SOURCE_PATH: 33) – jdoig

+0

sử dụng back-tick, không phải là dấu ngoặc đơn – Alex

Trả lời

8

Hãy xem những gì macroexpand-1 cho chúng ta:

user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x)))) 
(defn 
~fn-name 
[f] 
$ 
(fn ~args$ (f (clojure.core/unquote-splicing body)))) 

Không chính xác những gì chúng ta đang theo đuổi! Điều đầu tiên đầu tiên: nếu bạn muốn unquote mọi thứ trong một macro, bạn cần sử dụng "` "(toán tử quasiquote/syntax-quote), chứ không phải" '". Ngoài ra, tôi không chắc chắn những gì bạn đang theo sau với những dấu hiệu đồng đô la, nhưng nó có thể là bạn đang đi cho phím tắt tiện dụng clojure để sử dụng gensym cho vệ sinh. Nhưng bạn cần nó ngay lập tức sau mỗi số nhận dạng bạn sử dụng nó với (như vậy [f#], không [f]$), và bạn cần nó trên mỗi lần xuất hiện của định danh. Và bạn không cần nó với args. Đưa tất cả điều này với nhau:

user=> (defmacro def-middleware [fn-name args & body] `(defn ~fn-name [f#] (fn ~args (f# [email protected])))) 
#'user/def-middleware 
user=> (clojure.pprint/pprint (macroexpand-1 '(def-middleware plus-two [x] (+ 2 x)))) 
(clojure.core/defn 
plus-two 
[f__594__auto__] 
(clojure.core/fn [x] (f__594__auto__ (+ 2 x)))) 
nil 
user=> 
+0

Xin lỗi $ nơi sao chép và dán biểu mẫu từ vim. Và bạn đúng đó là # i đã mất tích :) cảm ơn bạn. – jdoig

3

Có lẽ đây chỉ là một bài tập vĩ mô, nhưng các ví dụ cụ thể của việc xác định một chức năng trung gian là không tốt - bạn mất rất nhiều sự linh hoạt mà các khái niệm trung gian cung cấp cho bạn. Ví dụ: tại sao điều này nên đánh giá (f (+ 2 x)) thay vì (+ 2 (f x))? Cả hai đều là những cách hợp lý để bọc hàm này và cú pháp của bạn không có cách nào để mô tả hàm sau. Thực sự chỉ định nghĩa hàm trả về là linh hoạt, đơn giản và dễ dàng; macro này mang lại ít cho bảng.

+0

Cảm ơn amalloy; Tôi đang sử dụng nó như là một bước đệm để cả hai tìm hiểu vĩ mô và cũng xây dựng các chức năng xây dựng giống như phần mềm trung gian cụ thể hơn so với hàm câm lớn này, chỉ bao bọc một cái gì đó ... không thể ngắn mạch, vv và nó không mô tả về cách nó kết thúc tốt đẹp mọi thứ, v.v. – jdoig

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