这个练习有点问题。具体来说,'看'lambda表达式是如何工作的
练习本身就是这样说的..
(define (map p sequence)
(accumulate (lambda (x y) <??>) nil sequence))
必须变成这个......
(define (map p sequence)
(accumulate (lambda (x y) (cons (p x) y)) null sequence))
但我不明白。我的意思是,我看到'accumulate'程序遵循(定义(累积op初始序列)... form
那么,这是否意味着(lambda(x y)(cons(p x)y))是'op'部分? &安培;若然,x&amp; y&amp;他们如何进入等式?
(体面的解释非常感谢)
答案 0 :(得分:2)
首先,让我们看看书中定义的accumulate
:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
基本上,它是foldr
(又名fold-right
)的临时实现,是处理输入列表的高阶过程,应用某个操作在每个元素上并累积结果。
请注意,op
参数是一个如下所示的过程(让我们将x
和y
重命名为更有意义的内容:
(lambda (element accumulator) <body>)
在上面,element
表示输入列表中的当前元素,每个元素按从左到右的顺序依次处理,accumulator
是累积值。输出,当我们遍历列表时递归构建。 <body>
部分通过对当前元素和累积值执行某些操作来处理更新累积值。现在,让我们来看看我们通常如何写map
:
(define (map p sequence)
(if (null? sequence)
null
(cons (p (car sequence))
(map p (cdr sequence)))))
你注意到这种模式吗? map
与accumulate
非常非常相似,我们只需要:
initial
值:null
将是完美的op
程序,将p
应用于列表中的当前元素,cons
将其应用于递归调用的结果当我们使用恰当的参数调用accumulate
时,这正是我们所做的:
(define (map p sequence)
(accumulate (lambda (element accumulator)
(cons (p element) accumulator))
null
sequence))
要注意的关键洞察力是lambda
正文中的这一行:
(cons (p element) accumulator)
与原始map
中的其他行完全相同:
(cons (p (car sequence)) (map p (cdr sequence)))
^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
cons both parts apply `p` on current element all this is the accumulated value
要了解原因,请使用替换模型,并将op
,initial
和sequence
(accumulate
中的参数)替换为我们作为参数传递的实际值。
答案 1 :(得分:1)
所以,这是否意味着(lambda(x y)(cons(p x)y))是&#39; op&#39;部分?
是
&安培;若然,x&amp; y&amp;他们如何进入等式?
x
是&#34;当前元素&#34; 和y
是&#34;递归调用(accumulate ...)
的结果在列表的其余部分&#34; 。
这就是这意味着什么。每个给定的列表都被视为一个缺点 - 一对car
及其cdr
。列表car
的值进入x
,cdr
- 进入递归调用,其结果进入y
。或者是等式的,
accumulate( op, z, CONS(e,es) ) = op( e, accumulate(op, z, es) )
其中CONS(e,es)
不是函数调用,而是数据表示(使用大写表示这一点) - {{1>} e
中的{em> cons单元和car
中的es
(阅读: eez ,如 e,复数)。因此,当调用cdr
时,会将op(x,y) = ...
和x = e
传递给它。
上面的等式定义了函数y = accumulate(op, z, es)
。对于accumulate
case:
NIL
因此假设accumulate( op, z, NIL ) = z
是二进制操作(即接收两个参数),能够处理op
的结果作为其第二个参数。这种列表处理模式称为"folding",或者#34; catamorphism&#34; - 即处理数据 down ,将数据分析成其组成部分,并以某种方式重新组合它们,安排某个&#34;呼叫协议&#34;用于二进制操作。
还有其他模式,例如一个所谓的&#34; paramorphism&#34;,
accumulate
这里假设操作是三元的(即接收三个参数),接收当前元素,输入列表的其余部分,以及输入列表的其余部分的递归处理的结果。它在实现需要访问输入和输出的数据处理模式时很有用(有时候会引用,隐藏的,&#34;有你的蛋糕和吃它的#34;)。 / p>
为了更有用,这些定义需要编码lazily,因此accumulate2( op, z, NIL ) = z
accumulate2( op, z, CONS(e,es) ) = op( e, es, accumulate2(op, z, es) )
可以选择是否强制递归结果,以便能够提前中止(参见例如{{3 }})。
答案 2 :(得分:0)
在SICP这一部分的一些练习中,对我有很多帮助的是引入了一些print
语句来查看accumulate
或其他函数调用中发生的事情,这些函数是递归调用的。
就像那样:(我正在使用Racket所以我不确定printf
是否也在其他方案中定义了)
(define (accumulate op initial seq)
(printf "op: ~a, initial: ~a, seq: ~a\n" op initial seq)
(if (null? seq)
initial
(op (car seq)
(accumulate op initial (cdr seq)))))