Macros 方案自参考lambda宏
您好,我对自引用lambda的宏有一个“问题”。。它是有效的,但当我想从外部提到“自我”时,它就失败了。。也就是说,第一次申请有效,第二次申请无效Macros 方案自参考lambda宏,macros,lambda,scheme,Macros,Lambda,Scheme,您好,我对自引用lambda的宏有一个“问题”。。它是有效的,但当我想从外部提到“自我”时,它就失败了。。也就是说,第一次申请有效,第二次申请无效 ((slambda(x)(+x1))10) ((slambda()self)) 如果将let替换为letrec,可能效果会更好: (define-macro slambda (lambda (args body) `(let ((self (lambda ,args ,body))) self))) 在Scheme中,您
如果将
let
替换为letrec
,可能效果会更好:
(define-macro slambda
(lambda (args body)
`(let ((self (lambda ,args ,body)))
self)))
在Scheme中,您有词法范围,self
直到let
的主体才生效。let主体中名为self
的过程本身并不由该名称定义。也许更容易看出您是否将
(define-macro slambda
(lambda (args body)
`(letrec ((self (lambda ,args ,body)))
self)))
请注意,
define macro
不是标准的方案语法,因此您应该指定要使用的实现。幸运的是,这个问题与宏无关。Sylvester的答案是正确的,但我想提出更重要的一点:除非您的方案实现没有提供一个卫生的过程宏系统,否则没有充分的理由使用定义宏
对于回指宏(如您要编写的宏),如果您使用的是支持它的方案实现(如Racket或Guile),则最好使用语法参数。下面是一个球拍的例子:
((lambda (self) ...)
(lambda () self)) ; self referenced outside procedure that defines it
当然,正如您在我的示例中所看到的,我使用了。在一般情况下,如果您想进行自参考过程,最好使用rec
;只需指定要引用过程的名称(而不是使用硬编码的self
)。由于rec
不是回指,因此其定义要简单得多:
#lang racket
(provide slambda self)
(require racket/stxparam srfi/31)
(define-syntax-parameter self
(lambda (stx)
(raise-syntax-error 'self "Can only be used inside slambda")))
(define-syntax slambda
(syntax-rules ()
((_ params body ...)
(rec (ohai . params)
(syntax-parameterize ((self (make-rename-transformer #'ohai)))
body ...)))))
您可以这样使用它(在本例中,我使用recur
作为自引用;当然,您可以选择任何您喜欢的名称):
您需要引用拟液化的lambda零件,以便将其分配给self
如果要将点和不引号拼接用于多个参数,则需要使用点和不引号拼接。如果使用scheme,则最好使用标准定义语法,而不是不总是支持的定义宏。使用define syntax时,必须使用datum->syntax使宏的行为不卫生,并将名称“self”注入输出语法。这是经过guile测试的用于定义语法的代码:
(define-macro slambda
(lambda (arg1 . arg2)
`(let ((self '(slambda ,arg1 ,@arg2)))
(lambda ,arg1 ,@arg2))))
是的,我将它切换到了letrec,一些案例开始工作,但我停止了这个应用程序((slambda()(slambda()self)self))。。它应该能工作guess@Poody您的slambda
宏无法正确处理多个实体形式,这正是您遇到的问题。@Chris Jester Young,所以我需要深入了解一下?@Poody您需要让宏为实体获取多个参数。尽管如此,我仍然认为define macro
是解决这个问题的错误方法。如果你在用球拍,你可以用我的答案。如果您使用的是不同的实现,最好只使用。@Poody我同意Chris的观点,但您使用它的方式可能是您可以使用namedlet
。谢谢您的提问!多亏了你,我通过简单的搜索找到了我自己问题的答案。这看起来比我预期的要干净得多-谢谢分享!
(define nested-length
(rec (recur x)
(cond ((null? x) 0)
((pair? x) (+ (recur (car x)) (recur (cdr x))))
(else 1))))
(define-macro slambda
(lambda (arg1 . arg2)
`(let ((self '(slambda ,arg1 ,@arg2)))
(lambda ,arg1 ,@arg2))))
(define-syntax slambda
(lambda (x)
(syntax-case x ()
[(slambda formals body0 body1 ...)
(with-syntax ([self (datum->syntax #'slambda 'self)])
#'(letrec ([self (lambda formals body0 body1 ...)])
self))])))