Pure Functional Programming in Haskell
Menu MenuI/O などが関係しない、入力から出力が常に同じに決まる関数プログラミングを Pure Functional Programming と言う。
再帰的な処理
変数の値を関数中で変えることができないので、 while 文などは、再帰で置き換える。例えば、Ruby の fibonacci
fib n # write Fibonacci series up to n result = [] a, b = 0, 1 while b < n do result.push(b) a, b = b, a+b end return result endは、以下のようになる。 ループで使う変数をすべて引数にしてしまうのが簡単。
fib n = fib1 0 1 n fib1 a b n = if b < n then (b : fib1 b (a + b) n) else [] :l fib.hs *Main> fib 10 [1,1,2,3,5,8]
Haskell の リスト
( : ) で、リストを作っている (cons) 。ちょっと手で作ってみよう。
*Main> ( 1 : [] ) [1] *Main> (1 : (1 : [] )) [1,1] *Main> [1,2] ++ [3,4] [1,2,3,4] *Main> head [1,2,3] 1 *Main> tail [1,2,3] [2,3] *Main> head (1: (2: 3)) <interactive>:1:13: No instance for (Num [t]) arising from the literal `3' at <interactive>:1:13 Possible fix: add an instance declaration for (Num [t]) In the second argument of `(:)', namely `3' In the second argument of `(:)', namely `(2 : 3)' In the first argument of `head', namely `(1 : (2 : 3))' *Main> head (1:(2:[])) 1 *Main> tail (1:(2:[])) [2]リストは [] で終らないと怒られる。
逆順のリストを作る
こういう方法でリストを作ると、一番先に入れたものが先頭に来る。逆順のリストを再帰で作るには、最初に [] を引数で渡してしまうと良い。
rev x = rev1 x [] rev1 [] x = x rev1 (x:xs) y = rev1 xs (x:y)異なる決まった値の入力を複数の関数で選択するのは、パターン、あるいはルールと呼ばれる。ここではリストの終了と cons pair を選択している。
rev2 n = if n==[] then [] else (rev2 (tail n)) ++ [head n]この方法だと ++ を n 回繰り返すことになる。
rev1 は、
rev3 n t = if n==[] then t else rev3 (tail n) ((head n) : t)と書いても同じ。(この方が普通っぽい?)
無限リスト
inc 0 = [] inc n = n : inc (n + 1)inc 1 は、普通止まらない。これは無限リストを表している。でも、Haskell では必要とされる分しか計算されない。
take1 0 x = [] take1 n (x:xs) = x : take1 (n-1) xsというのを作り、
*Main> take 10 (inc 1) [1,2,3,4,5,6,7,8,9,10]というように使うことができる。