在Exercise 30.1.1 of HtDP中,我开始使用local
,然后将其修改为使用lambda
以回答问题。
(define (add-to-each2 accu a-list)
(cond
[(empty? a-list) empty]
[else (local ((define s (+ accu (first a-list))))
(cons s (add-to-each2 s (rest a-list))))]))
和
(define (add-to-each5 accu a-list)
(cond
[(empty? a-list) empty]
[else (cons ((lambda (x y)
(first (map + (list (first y))
(list x)))) accu a-list)
(add-to-each5 (+ accu (first a-list))(rest a-list)))]))
在这个特定的例子中,对我来说,local
版本更容易阅读。是否存在lambda
版本首选的情况?谢谢。
答案 0 :(得分:3)
首先,我认为您可能会relative-2-absolute
与add-to-each
混淆,因为add-to-each
只是为列表的每个元素添加相同的数字,而不是递增累加器。这篇文章的其余部分假设是这种情况,并且只是取出那个增量。
我认为let
将是我本地绑定的首选。您的lambda
示例使用了使用let
和应用程序模拟lambda
的常见模式:
(let ([x e]) body)
相当于:
((lambda (x) body) e)
如果您在示例中使用从lambda
到let
的转换,则会得到:
(define (add-to-each5 n a-list)
(cond
[(empty? a-list) empty]
[else (cons (let ([x n] [y a-list])
(first (map + (list (first y))
(list x))))
(add-to-each5 n (rest a-list)))]))
一个好的编译器可能会为你的两个例子生成相同的代码,所以它主要归结为样式。正如您所注意到的,“左 - 左lambda
”模式可能更难阅读,所以我更喜欢let
。
然而,练习30.1.1试图让你使用map
来代替你的每个例子中出现的显式递归。您在示例中使用的是map
,但一次只添加一次,这会让map
感到痛苦:为什么当您刚刚结束(list (first y))
和(list x)
时想要(+ (first y) x)
?
让我们看一下map
的简单定义,看看它对这个问题有多大帮助,而不是痛苦:
(define (map f ls)
(cond
[(empty? ls) empty]
[else (cons (f (first ls)) (map f (rest ls)))]))
马上,你应该注意到add-to-each
的一些相似之处:cond
的第一行检查为空,第二行cons
与{{1}有关}}元素在first
上对map
的递归调用。因此,关键是将rest
和map
传递给每个元素。
对于f
,您希望为每个元素添加特定数字。以下是添加add-to-each
:
2
请注意> (map (lambda (n) (+ 2 n)) (list 1 2 3 4 5))
(3 4 5 6 7)
和map
都在这里作为30.1.1请求,并且它们在整个列表上操作而没有原始lambda
的显式递归:递归都是抽象的离开add-to-each
。
这应该足以让你找到解决方案;我不想放弃最后的答案,但是:)