Scheme自引用lambda宏

时间:2014-04-19 07:51:46

标签: macros lambda scheme

(define-macro slambda
  (lambda (args body)
    `(let ((self (lambda ,args ,body)))
        self)))

你好,我对这个宏有一个“问题”用于自引用lambda ..它有效,但是当我想从外面引用“self”时失败...意味着第一个应用程序有效,第二个不能< / p>

  1. ((slambda(x)(+ x 1))10)

  2. ((slambda()self))

4 个答案:

答案 0 :(得分:1)

也许这会更好地替换let letrec,如下所示:

(define-macro slambda
  (lambda (args body)
    `(letrec ((self (lambda ,args ,body)))
        self)))

在Scheme中,您有词法范围,selflet的正文之前不起作用。在let的主体中调用self的过程本身并未由该名称定义。你可能更容易看到你是否let

((lambda (self) ...)
 (lambda () self)) ; self referenced outside procedure that defines it

请注意define-macro不是标准的方案语法,因此您应该指定正在使用的实现。幸运的是,这个问题与宏无关。

答案 1 :(得分:1)

如果您正在使用方案,那么最好使用标准的define-syntax而不是不常用的define-macro。使用define-syntax,您必须使用datum-&gt;语法来使宏不受干扰地操作并将名称“self”注入输出语法。这是您的代码翻译为define-syntax,与guile一起测试:

(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))])))

答案 2 :(得分:0)

Sylwester的回答是正确的,但我想提出一个更大的观点:除非您的Scheme实现不提供卫生的程序宏系统,否则没有充分理由使用define-macro

对于回指宏(例如您要编写的宏),如果您使用支持它的Scheme实现(例如Racket或Guile),最好使用语法参数。这是一个球拍示例:

#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 ...)))))

当然,正如您在我的示例中所看到的,我使用了rec。在您想要自我引用程序的一般情况下,最好使用rec;您只需指定要引用该过程的名称(而不是使用硬编码的self)。由于rec不是照应用的,因此它的定义要简单得多:

(define-syntax rec
  (syntax-rules ()
    ((_ (id . params) body ...)
     (rec id (lambda params body ...)))
    ((_ id value)
     (letrec ((id value)) id))))

您可以像这样使用它(在这种情况下,我使用recur作为自引用;当然,您可以选择任何您喜欢的名称):

(define nested-length
  (rec (recur x)
    (cond ((null? x) 0)
          ((pair? x) (+ (recur (car x)) (recur (cdr x))))
          (else 1))))

答案 3 :(得分:0)

您需要引用 lambda-part ,在那里您可以将其分配给 self

(define-macro slambda
  (lambda (arg1 . arg2)
    `(let ((self '(slambda ,arg1 ,@arg2)))
       (lambda ,arg1 ,@arg2))))

如果你想将它与多个参数一起使用,那么就需要点和 unquote-splicing