问题描述
(define-Syntax macron
(Syntax-rules ()
((_ name)
(lambda (x)
(eval (cons 'name x) (interaction-environment))))))
(define x (map (macron lambda)
'(((x) (display x)) ((a b) (+ a b)))))
(let ((square (car x))
(sum (cadr x)))
(display (square 10))
(newline)
(display (sum 1 2 3))
(newline))
代码正在运行,通过将其与lambda封装在一起使用宏作为值。我的问题是如何将语法规则宏文字符号'name
而不是(cons 'lambda ...)
放在其中,所以输出代码为:
(lambda (x)
(eval (cons 'name x) (interaction-environment)))
因此它可以与以下代码一起使用:
(define (name x)
(display x)
(newline))
(for-each (macron lambda) ;; lambda can be anything
'((1) (2) (3)))
它会打印所有数字。
我知道我可以将模式中的名称更改为其他名称,但是我想进一步了解语法规则及其边缘情况。因此,如果我将其用作输入模式,可以使用名称吗?
我正在寻找R7RS的答案,其中涵盖了更多此类边缘情况。
解决方法
所有宏都发生在编译时,因此运行时内容可能不存在。这意味着您应该将其视为语法糖并将其用作替代。例如。
(for-each (macron something) '((1) (2) (3)))
然后应该在此基础上进行扩展。您当前的扩展就是变成这样:
(for-each (lambda (x)
(eval (cons 'someting x) (interaction-environment))
'((1) (2) (3)))
对于something
作为宏,它将在运行时应用宏。这是坏的。首先,它也消除了对宏的需要。您可以改为:
(define (macron-proc name)
(lambda (x)
(eval (cons name x) (interaction-environment))))
(for-each (macron-proc 'something) '((1) (2) (3)))
我制作了一种具有可传递宏的编程语言:
(define xor (flambda (a b) `(if,a (not,b),b)))
(define (fold comb init lst)
(if (null? lst)
init
(fold comb (comb (car lst) init) (cdr lst))))
(fold xor #f '(#t #t)) ; ==> #f
如果您针对高效的编译最终产品,这不是一个很好的方法。第一个宏确实是这样的,他们在Common Lisp之前的LISP 1.5中将其删除。 Scheme多年来一直避免使用宏,并在R4RS中选择了syntax-rules
作为可选功能。 R6RS是唯一具有完整功能宏的版本。
使用过程而不是宏,实际上与以下代码相同,但删除了错误的eval
:
(for-each (lambda (x)
(apply something x))
'((1) (2) (3)))
这意味着您可以更轻松地实现macron
:
(define-syntax macron
(syntax-rules ()
((_ name)
(lambda (x)
(apply name x)))))
但是从现在的角度来看,您根本不需要宏。这是部分应用程序。
(define (partial proc arg)
(lambda (lst)
(apply proc arh lst)))
(map (partial + 3) '((1 2) (3 4) (4 5)))
; ==> (6 10 12)
实际上有一个SRFI-26,叫做cut
/ cute
,它使我们可以将其包装在lambda中,从而执行类似的操作:
(map (cut apply + 3 <>) '((1 2) (3 4) (4 5)))
syntax-rules
是功率最低的宏。您不能做任何不卫生的事情,也不能基于其他标识符创建新的标识符。例如。不可能实现球拍样式struct
,在其中您可以执行(struct complex [real imag])
并让宏创建complex?
,complex-real
和complex-imag
作为过程。您需要像SRFI-57那样做,并要求用户指定所有名称,这样您就不必连接到新标识符。
现在,R7RS-small仅具有syntax-rules
。我认为没有一个更强大的宏作为替代是一个错误,因为现在R7RS-large无法用R7RS-small来实现。