ガイドライン
再帰を理解しようとするとき、特定の入力に対してアルゴリズムがどのように動作するかを考えた方が簡単な場合があります。実行パスがどのように見えるかということに夢中になりやすいので、代わりに次のような質問を自問してみてください。
- 空のリストを渡すとどうなりますか?
- 項目が 1 つのリストを渡すとどうなりますか?
- 多くのアイテムを含むリストを渡すとどうなりますか?
または、数値の再帰の場合:
- 負の数を渡すとどうなりますか?
- 0 を渡すとどうなりますか?
- 0 より大きい数値を渡すとどうなりますか?
再帰アルゴリズムの構造は、多くの場合、上記のケースをカバーするだけの問題です。それでは、アルゴリズムがどのように動作するかを見て、このアプローチの感触をつかみましょう。
最大'
maximum [] = error
maximum [1] = 1
maximum [1, 2] = 2
ご覧のとおり、興味深い動作は #3 だけです。他のものは、アルゴリズムが終了することを保証するだけです。定義を見ると、
maximum' (x:rest) = max x (maximum' rest)
これを呼び出すと、次のように[1, 2]
展開されます。
maximum [1, 2] ~ max 1 (maximum' [2])
~ max 1 2
maximum'
この場合、 を使用して再帰的に処理する方法を知っていますmax
。もう 1 つのケースを見てみましょう。
maximum [0, 1, 2] ~ max 0 (maximum' [1, 2])
~ max 0 (max 1 2)
~ max 0 2
この入力の場合、maximum'
最初の行の への再帰呼び出しが前の例とまったく同じであることがわかります。
逆行する'
reverse [] = []
reverse [1] = [1]
reverse [1, 2] = [2, 1]
リバースは、指定されたリストの先頭を取得して最後に貼り付けることで機能します。空のリストの場合、これには作業が含まれないため、これが基本ケースです。したがって、次の定義が与えられます。
reverse' (x:xs) = reverse' xs ++ [x]
代用をしましょう。[x]
がと同等であることを考えるとx:[]
、実際には 2 つの値を処理する必要があることがわかります。
reverse' [1] ~ reverse' [] ++ 1
~ [] ++ 1
~ [1]
簡単です。2 要素リストの場合:
reverse' [0, 1] ~ reverse' [1] ++ 0
~ [] ++ [1] ++ 0
~ [1, 0]
取った'
この関数は、リストだけでなく整数引数にも再帰を導入するため、2 つの基本ケースがあります。
0以下のアイテムを取るとどうなりますか? 項目を取得する必要はないので、空のリストを返すだけです。
take' n _ | n <= 0 = []
take' -1 [1] = []
take' 0 [1] = []
空のリストを渡すとどうなりますか? 取るアイテムがなくなったので、再帰を停止します。
take' _ [] = []
take' 1 [] = []
take -1 [] = []
アルゴリズムの本質は、実際にはリストをたどり、入力リストを引き離し、上記の基本ケースのいずれかがプロセスを停止するまで、取得するアイテムの数を減らすことです。
take' n (x:xs) = x : take' (n-1) xs
したがって、数値ベースのケースが最初に満たされた場合、リストの最後に到達する前に停止します。
take' 1 [9, 8] ~ 9 : take (1-1) [8]
~ 9 : take 0 [8]
~ 9 : []
~ [9]
リストの基本ケースが最初に満たされた場合、カウンターが 0 に達する前にアイテムを使い果たし、可能なものだけを返します。
take' 3 [9, 8] ~ 9 : take (3-1) [8]
~ 9 : take 2 [8]
~ 9 : 8 : take 1 []
~ 9 : 8 : []
~ [9, 8]