(注: 答えはこの投稿の最後にあります) 2 番目の関数、
(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))))))))
(コメントに Haskell の翻訳付き) それは何をするのですか? 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) の長さのリストを逆にするという仮定の下で、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
あり、反転された「コア」(つまり、最初と最後の要素のない入力リスト) であるため、反転されたコアを反転し、最初の要素を付加して入力リストの最後の部分を取得します。それを逆にして、最後の要素を先頭に追加します。単純。:)
2020 更新:これは@Rördのコメントからのコードに基づくスキーム バージョンで、同様に読みやすく、Haskell のパターン マッチングの代わりに引数が分解されます。
(define (bind lst fun)
(apply fun lst))
(define (rev lst)
(if (or (null? lst)
(null? (cdr lst)))
lst
(bind lst
(lambda (first . rest)
(bind (rev rest)
(lambda (last . revd-core)
(cons last (rev (cons first (rev revd-core))))))))))