代码之家  ›  专栏  ›  技术社区  ›  Zoé Martin

使用(lambda args())可以防止绑定args内部的内容

  •  0
  • Zoé Martin  · 技术社区  · 8 年前

    (define foo (lambda (x)
      (lambda (y) (+ x y))))
    
    ((foo 2) 5) ; => 7
    

    但如果我想编写一个宏,用任意数量的参数为我定义lambda,如下所示:

    (define-syntax create-lambda
      (syntax-rules ()
        ((_ name args)
         (define name (lambda args
           (lambda (y) (+ x y)))))))
    

    这样使用:

    ;; create the lambda named "foo" with arguments "(x)"
    (create-lambda foo (x))
    
    ((foo 2) 5) ; => Unbound variable: x
    

    我得到一个未绑定变量错误。
    我知道 x 未定义,因为它包含在 在我的宏中。

    但如果我显示宏的结果,我会得到:

    (define foo (lambda (x) (lambda (y) (+ x y))))
    

    这对我来说非常有效。

    args 阻止我绑住里面的东西?

    1 回复  |  直到 8 年前
        1
  •  2
  •   Sylwester    8 年前

    Scheme中的宏是健康的。因此,如果您传递一个宏 x 它是 不同的 来自变量 因为它们来自不同的范围。这很有用的一个实例是 swap! 宏:

    (define-syntax swap! 
      (syntax-rules ()
        ((_ from to) 
         (let ((tmp from))
           (set! from to)
           (set! to tmp)))))
    
    (define tmp 10)
    (define test 20)
    (swap! tmp test)
    (list tmp test) ; ==> (20 10)
    

    原始版本的宏扩展器可能会泄漏使用的宏变量 tmp 最终成为 (20 20) (swap! tmp test) 可能看起来像这样:

     (let ((tmp$1 tmp))
       (set! tmp test)
       (set! test tmp$1)))))
    

    我只是在宏创建的符号后面加了1美元。可能最终看起来是一样的,但对于方案实现来说,它们是不同的变量,就像它们有不同的名称一样。宏永远不应该依赖于没有冲突的符号,因为程序员倾向于重用相同的符号。您的代码如下所示:

    (define name 
      (lambda (x)
        (lambda (y$1) (+ x$1 $1)))))))
    

    x$1

    (define-syntax lambda-arity1
      (syntax-rules ()
        ; one argument
        ((_ (arg) body ...) 
         (lambda (arg) body ...))
        ; two or more arguments
        ((_ (arg arg2 ...) body ...) 
         (lambda (arg) (lambda-arity1 (arg2 ...) body ...)))))
    
    
    (lambda-arity1 (a b c d) (+ a b c d))
    ; == (lambda (a) (lambda (b) (lambda (c) (lambda (d) (+ a b c d)))))
    

    因为名字也来自用户 a 在列表中与相同 (((lambda-arity1 (a b) (+ a b) 1) 2) ; ==> 3