Macros 方案自参考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中,您

您好,我对自引用lambda的宏有一个“问题”。。它是有效的,但当我想从外部提到“自我”时,它就失败了。。也就是说,第一次申请有效,第二次申请无效

  • ((slambda(x)(+x1))10)

  • ((slambda()self))


  • 如果将
    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的观点,但您使用它的方式可能是您可以使用named
    let
    。谢谢您的提问!多亏了你,我通过简单的搜索找到了我自己问题的答案。这看起来比我预期的要干净得多-谢谢分享!
    (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))])))