如何使用lambda实现let *

时间:2014-05-05 03:29:01

标签: lambda scheme lambda-calculus let

我正在做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)

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

2 个答案:

答案 0 :(得分:10)

更新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中的(+ foo 1)将不受约束,因为foo不在范围内(bar中的(* bar 2)也是如此。


作为旁注,实施中的(e)应该只是e,就像教科书的实施一样;前者是一个thunk,而后者只是一个表达。

答案 1 :(得分:0)

Istvan的回答是正确的,但基本上,您的代码和教科书之间的差异是letlet*之间的差异。基本上,let*let的嵌套系列,事实上,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 ...)))))
相关问题