2011-01-19 58 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