プログラミング勉強ログ

プログラミングの勉強記録

Yet Another Haskell 3章 (7)

3.7 Recursion
再帰に関して

C言語などでは、for文を使ったループをよく使う。
しかし、for文では破壊的変更を伴うため、Haskellでは使われない。

代わりに再帰を使う。

例えば、C言語で階乗を計算する関数は次のように書ける。

int factorial(int n) {
  int fact = 1;
  for (int i = 2; i <= n; ++i)
    fact = fact * i;
  return fact;
}

Haskellでは次のように書く。

factorial 1 = 1
factorial n = n * factorial(n - 1)

シンプルですね。

再帰をマスターするのは難しいけど、最初の場合と再帰の場合を分けて考えるのが大事。
例えば、aのb乗を計算する関数は、b=1とそれ以外で分けるといい。

exponent a 1 = a
exponent a b = a * exponent a (b-1)

リストの長さを計算する関数(lengthと同じ関数)は、リストが空の場合と、それ以外で分けるといい。

my_length [] = 0
my_length (x:xs) = 1 + my_length xs

この(x:xs)という記法は特徴的ですね。
リストが空でない場合は、最低1つの要素があるため、先頭の要素をxで操作でき、残りのリストをxsで表し、それを自分自身に渡して再帰すればいい。

filterもリストが空の場合と、それ以外で分けるといい。
リストが空の場合は、空のリストを返し、
リストが空でない場合は、先頭の要素が条件を満たすかしらべ、残りのリストを再帰で処理する。

my_filter p [] = []
my_filter p (x:xs) =
  if p x
    then x : my_filter p xs
    else my_filter p xs

このパターンは頻出しそう。

Exercise 3.7

fib 1 = 1
fib 2 = 1
fib n = fib (n-1) + fib (n-2)

Exercise 3.8

mult a 1 = a
mult a b = a + mult a (b-1)

Exercise 3.9

my_map p [] = []
my_map p (x:xs) = p x : my_map p xs