Functional programming SICP练习4.6:在计算器中实现let作为基于lambda的派生表达式

Functional programming SICP练习4.6:在计算器中实现let作为基于lambda的派生表达式,functional-programming,scheme,lisp,evaluation,sicp,Functional Programming,Scheme,Lisp,Evaluation,Sicp,我正在尝试编写一个函数,用于转换表单的let表达式: 转换为以下形式的(等效)lambda表达式: ((lambda(var1…varn)body)exp1…expn) 我发现这个问题的大多数解决方案似乎都是错误的,有人能证实这一点吗 举个例子,这个解决方案来自 我相信let->composition将返回此表单的列表: ((lambda (var1 ... varn) body) (exp1 ... expn)) ((lambda (var1 ... varn) body) (exp1 ..

我正在尝试编写一个函数,用于转换表单的
let
表达式:

转换为以下形式的(等效)
lambda
表达式:

((lambda(var1…varn)body)exp1…expn)

我发现这个问题的大多数解决方案似乎都是错误的,有人能证实这一点吗

举个例子,这个解决方案来自

我相信
let->composition
将返回此表单的列表:

((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn)    body)  exp1 ... expn)
((lambda (var1 ... varn) body) (exp1 ... expn))
但是,我认为它应该返回以下表单的列表:

((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn)    body)  exp1 ... expn)
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda(var1…varn)body)exp1…expn)


不知何故,在
let->composition
中不应该使用对的调用吗?如何修改
let->composition
以包括
apply

这是正确的形式:

((lambda (var1 ... varn) body) exp1 ... expn)
我们只是调用一个具有多个参数的函数,例如:

((lambda (var1 var2 var3) (+ var1 var2 var3)) 1 2 3)
=> 6
另一个表单将引发错误,因为解释器认为您试图将
1
作为函数应用:

((lambda (var1 var2 var3) (+ var1 var2 var3)) (1 2 3))
=> expected a procedure that can be applied to arguments
也许你对
let
的工作方式感到困惑?例如,此表达式:

(let ((x 1)
      (y 2))
  (+ x y))
((lambda (x y)
   (+ x y))
 1 2)
只是语法上的糖分,它会被转换成这个等价的表达式:

(let ((x 1)
      (y 2))
  (+ x y))
((lambda (x y)
   (+ x y))
 1 2)

以上是一个程序应用程序,这是评估人员能够理解和评估的。如SICP中所述,对
let
表达式的求值需要两个步骤:首先将表达式转换为
lambda
应用程序,然后将结果转换传递给求值器进行正常求值。因此,不应该在转换中添加
apply
,让计算器中的现有代码处理这个问题,您只需要发出一个计算器可以理解的表达式。

这是正确的形式:

((lambda (var1 ... varn) body) exp1 ... expn)
我们只是调用一个具有多个参数的函数,例如:

((lambda (var1 var2 var3) (+ var1 var2 var3)) 1 2 3)
=> 6
另一个表单将引发错误,因为解释器认为您试图将
1
作为函数应用:

((lambda (var1 var2 var3) (+ var1 var2 var3)) (1 2 3))
=> expected a procedure that can be applied to arguments
也许你对
let
的工作方式感到困惑?例如,此表达式:

(let ((x 1)
      (y 2))
  (+ x y))
((lambda (x y)
   (+ x y))
 1 2)
只是语法上的糖分,它会被转换成这个等价的表达式:

(let ((x 1)
      (y 2))
  (+ x y))
((lambda (x y)
   (+ x y))
 1 2)
以上是一个程序应用程序,这是评估人员能够理解和评估的。如SICP中所述,对
let
表达式的求值需要两个步骤:首先将表达式转换为
lambda
应用程序,然后将结果转换传递给求值器进行正常求值。因此,不应该在转换中添加
apply
,让计算器中的现有代码处理这个问题,您只需要发出计算器可以理解的表达式

相信let composition将返回此表单的列表:

((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn)    body)  exp1 ... expn)
((lambda (var1 ... varn) body) (exp1 ... expn))

但是,我认为它应该返回以下表单的列表:

((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn)    body)  exp1 ... expn)
((lambda (var1 ... varn) body) (exp1 ... expn))
有好消息也有坏消息。坏消息是你的信念是错误的。好消息是你的想法是正确的。也就是说,您确实希望得到结果
((lambda…)
,这就是此代码生成的结果

此方案代码不需要任何特殊的解释器或任何东西,因此您可以测试它,而不会出现任何实际问题。让我们再看看定义:

 (define (let-vars expr) (map car (cadr expr))) 
 (define (let-inits expr) (map cadr (cadr expr))) 
 (define (let-body expr) (cddr expr)) 

 (define (let->combination expr) 
   (cons (make-lambda (let-vars expr) (let-body expr)) 
         (let-inits expr))) 
那么在
(let->composition”(let((x 34))(list x))
中会发生什么呢?您将评估:

(cons (make-lambda (let-vars expr) (let-body expr)) 
      (let-inits expr))
这些部分创建了什么?
(生成lambda…
创建了您期望的lambda表达式:

(lambda (x) (list x))
(让inits…
返回:

(34)
现在的问题是,什么是
(cons'(lambda(x)(list x))
'(34))`?你可以很容易地测试出来;它是:

((lambda (x) (list x)) 34)
这可能是关于
cons
如何工作的一些混淆的结果。列表只是一个空列表,
'()
,或者由cons生成的一对,其car是列表的一个元素,其cdr是列表的其余部分。因此:

               (cons 1 '())  ;=> (1)
               (cons 1 '(2)) ;=> (1 2)
(cons '(lambda (x) x) '(34)) ;=> ((lambda (x) x) 34)
我相信let combination将返回此表单的列表:

((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn)    body)  exp1 ... expn)
((lambda (var1 ... varn) body) (exp1 ... expn))
…不知怎的,对apply函数的调用不应该在中使用吗 let组合?应如何修改let组合以包括 申请

正如我们所看到的,代码实际上生成了您想要的结果。如果它实际生成了类似于
((lambda(var1…varn)body)(exp1…expn))
,那么您可能需要使用
apply
。最简单的方法是生成

(apply (lambda (var1 ... varn) body) (list exp1 ... expn))
请注意,我们添加了
apply
,以及对
list
的调用。这需要更改
let->combination
的定义。一种可能是:

(define (let->combination expr) 
   (cons 'apply
         (cons (make-lambda (let-vars expr) (let-body expr)) 
               (cons (cons 'list (let-inits expr))
                     '()))))
另一个(更简单的)选择是:

(define (let->combination expr) 
   (list 'apply
         (make-lambda (let-vars expr) (let-body expr)) 
         (cons 'list (let-inits expr))))
相信let composition将返回此表单的列表:

((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn)    body)  exp1 ... expn)
((lambda (var1 ... varn) body) (exp1 ... expn))

但是,我认为它应该返回以下表单的列表:

((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn) body) (exp1 ... expn))
((lambda (var1 ... varn)    body)  exp1 ... expn)
((lambda (var1 ... varn) body) (exp1 ... expn))
有好消息也有坏消息。坏消息是你的信念是错误的。好消息是你的想法是正确的。也就是说,你确实想要结果
((lambda…)
,这就是代码产生的结果

此方案代码不需要任何特殊的解释器或任何东西,因此您可以在没有任何实际问题的情况下对其进行测试。让我们再次查看定义:

 (define (let-vars expr) (map car (cadr expr))) 
 (define (let-inits expr) (map cadr (cadr expr))) 
 (define (let-body expr) (cddr expr)) 

 (define (let->combination expr) 
   (cons (make-lambda (let-vars expr) (let-body expr)) 
         (let-inits expr))) 
例如,在
(let->composition'(let((x 34))(list x))
中会发生什么呢?您将评估:

(cons (make-lambda (let-vars expr) (let-body expr)) 
      (let-inits expr))
这些部件产生了什么<代码>(生成lambda…创建预期的lambda表达式:

(lambda (x) (list x))
(让inits…
返回:

(34)
现在的问题是,什么是
(cons'(lambda(x)(列表x))
'(34))`?你可以很容易地测试出来;它是:

((lambda (x) (list x)) 34)
这可能是由于对
cons
的工作原理有些混淆造成的。列表只是:空列表,
”()
,或