2011-01-19 57 views
3

Exercise 30.1.1 of HtDP中,我开始使用local,然后修改它以使用lambda来回答问题。本地vs 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版本更受欢迎?谢谢。

回答

3

首先,我想你可能会得到relative-2-absoluteadd-to-each混淆,因为add-to-each只是将相同的数字添加到列表的每个元素,而不是递增累加器。这篇文章的其余部分假设情况是这样,并且只是拿出增量。

我认为let将是我本地绑定的第一选择。你lambda示例使用,使用lambda和应用程序模拟let一个共同的模式:

(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)))])) 

一个很好的编译器可能会产生T的相同的代码他的两个例子,所以它主要归结为风格。正如你注意到的,“左 - 左lambda”模式可能更难以阅读,所以我更喜欢let

但是,练习30.1.1试图让您使用map作为每个示例中发生的显式递归的替代。您在示例中使用的是map,但一次只能添加一个,这使得map有种痛苦:为什么当您只想要(+ (first y) x)时,为什么还要折起(list (first y))(list x)

让我们看的map一个简单的定义,看看它可能是有帮助的,而不是痛苦的,对于这个问题:

(define (map f ls) 
    (cond 
    [(empty? ls) empty] 
    [else (cons (f (first ls)) (map f (rest ls)))])) 

向右走,你应该注意到一些相似之处add-to-each:第一行cond检查为空,并且第二行consfirst元素有关,对rest上的map进行递归调用。那么,关键是通过mapf来做你想做的每个元素。

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中被抽象化。

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

+0

谢谢亚当,这是非常有见地的。我没有介绍让我们介绍的部分,但是我看到了这一步。最好的祝愿。 – Greenhorn 2011-01-19 15:52:31