簡體   English   中英

使用foldl和foldr反轉Scheme中的列表

[英]Reverse a list in Scheme with foldl and foldr

如何使用foldrfoldl定義在Scheme中反轉列表的函數?

我們想要的是一個簡潔的解決方案,該方案使用foldl調用來反轉Scheme中的列表,並使用定義的foldr調用來解決另一個問題:

(define (foldl operation lst initial)
    (if (null? lst) initial
        (foldl operation 
               (cdr lst) 
               (operation (car lst) initial))))

(define (foldr operation lst initial)
    (if (null? lst) initial
        (operation 
            (car lst) 
            (foldr operation (cdr lst) initial))))

精明的人會發現foldl實現是尾遞歸的,因為返回值是在調用每個遞歸步驟時計算的-在最后一步,整個答案已經計算出來,並簡單地在鏈上返回。

foldr實現不是尾遞歸的,因為它必須使用返回到遞歸鏈上的值來構建返回的值。

因此,我們感興趣的兩個Scheme實現應采用以下形式:

(define (rev1 lst)
    (foldl ___________________________

**Solution:**
(define (rev1 lst)
    (foldl cons lst '()))

(define (rev2 lst)
    (foldr ___________________________

**Solution 1:**
(define (rev2 lst)
    (foldr 
       (lambda (element accumulator) 
               (foldr cons accumulator (cons element '())))
       lst '())) 

**Solution 2:**
(define (rev2 lst)
    (foldr 
       (lambda (element accumulator) 
               (append accumulator (cons element '())))
       lst '())) 

最終目標是能夠調用以下命令,

(rev1 '(1 2 3)) -> (3 2 1)
(rev2 '(1 2 3)) -> (3 2 1)

foldl解決方案應該相對瑣碎(根據我們的直覺),但是foldr解決方案可能需要更多的思考。

先前與此問題類似(但文獻記載少得多)的問題卻未得到回答和/或結束。

這看起來像是作業,所以我會給您一些提示以幫助您入門。 foldl情況很簡單,您只需要發現要傳遞的正確函數,並記住: foldl可以可視化為向后處理列表(最后一個元素在前,最后一個元素在后),所以您要做的就是將當前列表中具有累計值的元素:

(define (rev1 lst)
  (foldl <???> lst '()))

文件foldr情況只是稍微困難一點,只記得文件foldr會按照在輸入列表中出現的順序處理列表中的元素。 同樣,您必須找到正確的過程來調用:

(define (rev2 lst)
  (foldr (lambda (e a)
           <???>)
         lst
         '()))

您需要以某種方式將e (當前元素)放在累積值a末尾 提示:您會發現appendlist在這里很有用。

您的rev1 '解決方案'無法編譯...如果您將list替換為l

> (define (rev1 l) 
    (foldl cons l '()))
> (rev1 '(1 2 3))
(3 2 1)

對於您的rev2它可以作為主體:

> (foldr (lambda (a b) (append b (list a))) '(1 2 3) '())
(3 2 1)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM