2011-10-12 48 views
8

我試圖創造MIT計劃這個簡單的(Common Lisp中)宏相當於百思不得其解:如何編寫一個MIT Scheme宏來返回一個lambda表單?

(defmacro funcify (exp) 
    `(lambda (x) ,exp)) 

這是一個簡單的個人項目,數值方程求解器基於內置的功能第二屆SICP講座。我不在乎這個宏不是「安全的」或「衛生的」,或者如果exp引用除x以外的任何符號,將捕獲一個變量。我希望能寫

(solv '(* 60 x) '(* 90 (- x 1))) 

其中SOLV是:

(define (solv lh-exp rh-exp) 
    (solve (funcify lh-exp) (funcify rh-exp))) 

,而不必鍵入

(solve (lambda (x) (* 60 x)) (lambda (x) (* 90 (- x 1)))) 

但無法弄清楚如何使用要做到這一點MIT Scheme語法規則。

我已經試過,但它不工作:

(define-syntax funcify 
    (syntax-rules() 
    ((funcify y) (lambda (x) y)))) 
;Value: funcify 

(funcify x) 
;Value 17: #[compound-procedure 17] 

((funcify x) 10) 
;Unbound variable: x 

我嘗試過其他的東西可能不值得一提,涉及eval,但無濟於事。

另外,在Scheme的宏系統上引用了很好的教程(不是引用),它以小的簡單例子開始,並具有充足的註釋,並且特別顯示瞭如何轉換反引號逗號樣式的LISP宏(對我而言高度直觀)到Scheme的語法宏觀系統會很好。

回答

4

您可以通過使用explicit-renaming macros基本上做同樣的事情,與defmacro 。唯一重要的區別是您必須自行解構輸入表單:

(define-syntax funcify 
    (er-macro-transformer 
    (lambda (form rename cmp) 
     (let ((exp (cadr form))) 
     `(,(rename 'lambda) (x) ,exp))))) 
+0

ER實現(MIT Scheme支持)。 :-) –

+1

@ ChrisJester-Young感謝您的錯誤修復。 :) –

+0

+1。謝謝一堆。 define-syntax完全令人困惑,但我懷疑它非常強大,我想更好地學習它,有任何提及它的提法?我接受你的答案,因爲它提供了一個在MIT計劃中可用的函數,我希望我也可以接受克里斯的答案,因爲它也指出solv也必須是一個語法規則宏。 – Bogatyr

7

它不能在syntax-rules中完成。故事結局。

將輸入表達式中的任意標識符(x)輸入到輸出表達式中需要破壞衛生,並且syntax-rules沒有提供任何方法來打破衛生。您將需要使用較低級別的宏系統來執行此操作。麻省理工學院計劃使用顯式重命名(見馬蒂亞斯Benkard的答案),但對於使用syntax-case其他Scheme實現,你可以這樣做:

(define-syntax funcify 
    (lambda (stx) 
    (syntax-case stx() 
     ((_ body) 
     (with-syntax ((x (datum->syntax stx 'x))) 
     #'(lambda (x) 
      body)))))) 

的關鍵是(datum->syntax stx 'x)位中注入象徵x就好像它是在funcify調用的語法上下文中。

順便說一句,你solv也必須是一個宏,不是一個過程,但至少它可以是一個syntax-rules宏:

(define-syntax solv 
    (syntax-rules() 
    ((_ lhs rhs) (solve (funcify lhs) (funcify rhs))))) 
+0

+1非常感謝您的回答,並指出solv也必須是宏。首先,宏是非常棘手的,但Scheme語法 - *宏可能是迄今爲止我在語言中遇到的最難的事情,我一直在編程(大多是藍調,但我在CL中完成了我的碩士論文)30+年份。 – Bogatyr

+0

@Bogatyr:等你繼續下去。 ;-)(儘管嚴格地說,儘管R5RS規範在50頁之內,Scheme仍然是一門相當大的語言。) –

相關問題