3

HtDP 的练习 30.1.1 中,我开始使用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首选版本的情况?谢谢你。

4

1 回答 1

3

首先,我认为您可能会relative-2-absolute混淆add-to-each,因为add-to-each只是将相同的数字添加到列表的每个元素,而不是增加累加器。这篇文章的其余部分假设是这种情况,只是去掉了这个增量。

我认为let这将是我本地绑定的首选。您的lambda示例使用模拟let使用lambda和应用程序的通用模式:

(let ([x e]) body)

相当于:

((lambda (x) body) e)

如果您在示例中使用从lambdatolet的这种转换,您将得到:

(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检查空,第二行consfirst元素map有关,对rest. 那么,关键是将map执行f您想要执行的操作的对象传递给每个元素。

在 的情况下add-to-each,您想为每个元素添加一个特定的数字。这是添加的示例2

> (map (lambda (n) (+ 2 n)) (list 1 2 3 4 5))
(3 4 5 6 7)

请注意,maplambda都在此处作为 30.1.1 请求,并且它们作用于整个列表而没有原始 的显式递归add-to-each:递归全部抽象为map.

这应该足以让您找到解决方案;不过,我不想放弃最终答案:)

于 2011-01-19T15:50:01.157 回答