(注意:答案是在這篇文章的末尾)第二屆功能,
(define (swap-ends x) ; swap [] = []
(if (or (equal (length x) 0) (equal (length x) 1)) ; swap [x] = [x]
x ; swap (x:xs)
(cons (first (swap-ends (rest x))) ; | (a:b) <- swap xs
(swap-ends (cons (first x) ; = a : swap (x : b)
(rest (swap-ends (rest x))))))))
(與在評論哈斯克爾翻譯)這是什麼做的,你問?爲if
的替代條款數據流圖是
/-> first ----------------------> cons
x --> first ------/-------------> cons --> swap --/
\-> rest -> swap ---> rest ---/
(按照從左至右的箭頭向右)。所以,
[] -> []
[1] -> [1]
/-> 2 -----------------------> [2,1]
[1,2] --> 1 --------/------------> [1] --> [1] --/
\-> [2] -> [2] ---> [] ---/
/-> 3 -------------------------> [3,2,1]
[1,2,3] --> 1 ------------/----------> [1,2] --> [2,1] --/
\-> [2,3] -> [3,2] -> [2] --/
/-----> 4 ----------------------------> [4,2,3,1]
[1,2,3,4] --> 1 ------------/---------------> [1,3,2] -> [2,3,1] -/
\-> [2,3,4] -> [4,3,2] -> [3,2] -/
到目前爲止,它確實交換了列表的結束元素。讓我們從自然感應證明這一點,
true(N-1) => true(N)
:
/-> N --------------------------------------> [N,2..N-1,1]
[1..N] --> 1 ---------/-----------> [1,3..N-1,2] -> [2,3..N-1,1] -/
\-> [2..N] -> [N,3..N-1,2] /
-> [3..N-1,2] -/
所以它被證明。因此,我們需要設計的數據流圖,其逆轉的(N-1)-length列表的假設下,將扭轉的N長度列表:
[1..N] --> 1 ------------------------------------\
\-> [2..N] -> [N,N-1..2] -> N -------------\------------------\
\-> [N-1,N-2..2] -> [2..N-1] -> [1..N-1] -> rev -> cons
這給我們的實施
(define (rev ls) ; rev [] = []
(cond ; rev [x] = [x]
((null? ls) ls) ; rev (x:xs)
((null? (rest ls)) ls) ; | (a:b) <- rev xs
(else ; = a : rev (x : rev b)
(cons (first (rev (rest ls)))
(rev (cons (first ls)
(rev (rest (rev (rest ls))))))))))
(rev '(1 2 3 4 5)) ; testing
;Value 13: (5 4 3 2 1)
評論中的Haskell翻譯很自然地遵循該圖。它實際上是可讀:a
是最後一個元素,b
被顛倒「核心」(即沒有它的第一個和最後一個元素的輸入列表),所以我們扭轉扭轉核心,前置的第一要素,以獲得butlast輸入列表的一部分,然後將其反向並添加最後一個元素。 簡單。 :)
[car and cdr](https://en.wikipedia.org/wiki/CAR_and_CDR)的概念可能會幫助你在這裏。 – JDong
那麼我知道如何使用第一個(汽車)和休息(CDR),但我不明白如何建立列表遞歸的正確列表。 – b33k3rz