【问题标题】:How to implement let* using lambda如何使用 lambda 实现 let*
【发布时间】:2014-06-21 06:34:30
【问题描述】:

我正在做 lambda 演算,在我的教科书中,它说您将如何使用 lambda 演算编写 let*

我的答案:x、y 和 z 是参数; v1、v2 和 v3 参数; e 是主体:

((lambda (x y z) (e)) v1 v2 v3)

书中的答案:

  ((lambda(x)
    ((lambda(y)
      ((lambda(z) e) v3))
      v2))
    v1)

我不确定我的答案是否相同。如果不是,为什么我的答案是错误的?如何得出原始答案?

【问题讨论】:

标签: lambda scheme lambda-calculus let


【解决方案1】:

更新 2:我意识到我原来的答案是正确的并回滚到原来的答案,但会添加一些澄清说明

在 Scheme 中,let* 允许后面的值依赖于前面的值。因此,例如,您可以编写(以通常的语法):

(let* ((foo 3)
       (bar (+ foo 1))
       (baz (* bar 2)))
  (* foo bar baz))

它将foo 绑定到 3,bar 绑定到 4,baz 绑定到 8,并返回 72。您的教科书的实现允许这样做。

但是,您的实现不允许这样做 - 它需要独立评估所有值。然而,它是let 的正确实现,而不是let*

您的教科书答案的工作方式是,较早的值在以后的值之前绑定。 比如上面教科书的实现代码如下:

((lambda (foo)
  ((lambda (bar)
    ((lambda (baz) (* foo bar baz)) (* bar 2)))
    (+ foo 1)))
  3)

但是,如果您尝试以相同的方式使用您的实现:

((lambda (foo bar baz) (* foo bar baz)) 8 (+ foo 1) (* bar 2))
; Error - foo and bar aren't bound

那么(+ foo 1) 中的foo 将被解除绑定,因为foo 不在该范围内((* bar 2) 中的bar 也是如此。


附带说明,您的实现中的(e) 应该只是e,就像教科书的实现一样;前者是一个thunk call,而后者只是一个表达式。

【讨论】:

    【解决方案2】:

    Istvan 的回答是正确的,但基本上,您的代码和教科书的区别在于letlet* 之间的区别。基本上let*lets的嵌套系列,其实let*的典型定义如下:

    (define-syntax let*
      (syntax-rules ()
        ;; if no bindings, same as let
        ((let* () body ...)
         (let () body ...))
    
        ;; otherwise, take one binding, then nest the rest
        ((let* (binding next ...) body ...)
         (let (binding)
           (let* (next ...)
             body ...)))))
    

    【讨论】:

      猜你喜欢
      • 2011-06-30
      • 2020-06-02
      • 2017-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 2013-05-17
      相关资源
      最近更新 更多