一次リスト
以下をfoo.lhsとし hugs foo.lhsで実行可能。
haskellではリストは a:b:c:[] で表され、その省略形は[a,b,c]となる。 リストの全ての要素を足しあわせる関数sumlistを定義する >sumlist [] = 0 >sumlist (x:xs) = (+) x (sumlist xs) 次にリストの全ての要素を掛け合わせる関数multilistを定義する >multilist [] = 1 >multilist (x:xs) = (*) x (multilist xs) 実行結果はそれぞれ以下のようになり正しいことが分かる Main> sumlist [1,2,3] 6 Main> multilist [2,3,4,5] 120 ここで、sumlistとmultilistは演算子と[]のときの動作のみが異なるので高階関数reduceを以下のように定義すると >reduce f x []= x >reduce f x (y:ys) = f y (reduce f x ys) sumlist,multilistは以下のように定義される。 >sumlist2 = reduce (+) 0 >multilist2 = reduce (*) 1 このreduceについて考察してみる 二つのリストを接続する関数appendは以下のように定義される >append [] b = b >append (x:xs) b = (:) x (append xs b) やはりappendもリストに対する繰り返しであることが分かるので、演算子を(:) []時の値bを引数としてreduceに与えてやればいい。 >append2 a b = reduce (:) b a とりあえず実行結果 Main> append2 ["a","b","c"] ["d","e"] ["a","b","c","d","e"] Main> append2 [3,4,5,7][1,2] [3,4,5,7,1,2] リストの各要素の値を倍にするdoublelistという関数を考える。 >doublelist [] = [] >doublelist (x:xs) = (:) ((*) 2 x) (doublelist xs) doubleandconsを以下のように定義し >doubleandcons_pre a b = (:) ((*) 2 a) b ここでbは省略可能なので(理由がうまく説明できない)、reduceでdoublelistを定義し直す >doubleandcons a = (:) ((*) 2 a) >doublelist2 = reduce doubleandcons [] doubleandconsの演算子をパラメータにすることが出来るから >fandcons f x = (:) (f x) >double x = (*) 2 x >doublelist3 = reduce (fandcons double) [] ここでdoubleを引数とする関数をmap(標準にある関数なのでmap2とする)として定義する >map2 f = reduce (fandcons f) [] >doublelist4 = map2 double このmap2を利用する 各要素の値に+1するplusonelistが簡単にかける 各要素の値に/2するhalflistが簡単にかける (*2)は二倍する関数 例:(*2) 2 --> 4 >plusonelist = map2 (+1) >halflist = map2 (/2)