HOME Haskell のお勉強 書き込む

1. Haskell とは


Haskell は遅延評価を基本とする、純粋な関数型プログラミング言語です。

Haskell は簡単なことと難しいことが入れ替わったような言語で、 IO などの普通の言語ではなんでもないことが難しく、探索、構文解析などの むずかしいことが比較的簡単に出来ます。

Haskell は純粋な関数型なので、代入に伴うバグを気にしないですみます (参照透明性があるといいます)。また、 値は必要になって初めて求められるので、無限の大きさをもつデータを扱うことが出来ます。

例えば、奇数の最初の3つが欲しいときは

take 3 [1,3..]
と書くことが出来ます。 遅延評価を行わない普通のプログラミング言語では、途中に無限ループがあると そこで止まってしまいますが、Haskell の場合は必要な値だけを計算して、 最後まで実行してくれます。

Haskell のプログラムは、値を求める手順ではなく、値の定義を書いたものなので、 数学の本に載っている数式の定義がほぼそのまま使えます。特に、再帰的な定義はすっきり書けます。

階乗

fact 0 = 1
fact n = n * fact (n-1)
quick sort
Haskell の紹介記事によく載っている例です。
qsort _ [] = []                                             (1)
qsort f (x:xs) =  before ++ (x : after)                     (2)
 where before =  qsort f (filter  (not . (f x)) xs)         (3)
       after  =  qsort f (filter (f x) xs)                  (4)
注:
  1. リストが空の時は空のリストを返します。
  2. before と after の定義は次の行以降で出てきます。この行はとりあえず、before, x, after の順にリストを並べ替えるという意味です。
  3. where は "ここで" という意味の予約語です。前の行で出てきた before と after を定義します。
    この行で、before の定義をしています。これは、xs の中から関数 (f x) を満たさないものを選んで、それを再帰的に qsort するという意味です。
    filter は、関数 fun とリスト ls をとり、 ls の要素のうち、fun を満たすものからなるリストを返す関数です。 f は2つのものを比較する関数なので、2つの引数を取る関数です。それと引数の1つ x とから (f x) という1つの引数を取る関数が作られます。 これを関数の部分適用といいます。 たとえば、filter (> 2) [0,1,2,3,4,5][3,4,5] になります。
  4. after の定義です。xs の中から関数 (f x) を満たすものを選んで、それを再帰的に qsort しています。 再帰的に関数を定義することによって、繰り返しをすっきりと記述することができます。
Main> qsort (>) [3,1,5,2,10,0]
[10,5,3,2,1,0]
数列
驚くべきほど簡潔に定義できます。
この例のほうが前に挙げた例より Haskell の性質をよく表していると思います。
-- 等比数列などの次の項が今の項の関数であらわされる無限数列(初項 a0、 関数 f) 
seqn a0 f = a0 : seqn (f a0) f                  -- (1)

-- 初項 a0 公比 r の等比数列
geo a0 r = seqn a0 (*r)
  
--  Fibonacci 数列
fib = 1:1:zipWith (+) fib (tail fib)
(1) はほとんどトートロジー(単なる言い換え)ですが、ちゃんと計算してくれます。 この様な数列の定義は一見無駄な計算をしているように見えますが、そのようなことはなく、 O(n) のオーダーです。
(1) が
a0 = a0
an+1 = f(an)
で表される無限数列であることの証明は ここ を見てください。

上の例でも分かるように、コードには”どういう値が欲しいか?”を記述するだけです。 その値をどういう手順で求めるかについてはほとんど気にする必要がありません。

このことから、下で示すような種類のプログラムでは有効です。

一方、以下の種類のプログラムには向きません。書けないことはありませんが、 他の言語で書いたほうが楽でしょう。また、Haskell でこれらのプログラムを書くと、 手続き型言語で書いたのと同じようなコードが出来上がります。

このことから、Haskell は Fortran ユーザー、AI プログラマにとっては 便利だと思います。もちろん、実行速度は Fortran に比べてかなり遅いのですが、 GHC には profiler が付いているので、bottle-neck を見つけることが出来ます。 そして、もし、どうしても必要ならその部分を C で書き直せば速度は改善されます。

大雑把な感じとしては、GHC でコンパイルした Haskell プログラムは Python のプログラムと同じくらいの 速度です。つまり、多くの場合ほとんど問題が無いが、速度が気になるプログラムでは問題になります。

以下に主な Web site を挙げておきます。