Haskel あれこれ 型

Haskell は「強く型付けられた、純粋関数言語」と紹介されることがある。Perl や Ruby などの型付けられてない言語の便利さを感じていたため、強く型づけられているというだけで、不便なんだろうなという印象をもった。

しかし、Haskell には、一体どれくらい型付けられていることによる不便があるのだろうか。たとえば、実数と整数は足し算もできない。

Hugs> (1::Float) + (2::Int)
ERROR - Type error in application
*** Expression : 1 + 2
*** Term : 1
*** Type : Float
*** Does not match : Int

ただし、明示的に型変換ができる。

Hugs> (1::Float) + fromIntegral(2::Int)
3.0

また、リストの要素はすべて同じ型でないとエラーになる。

Hugs> [1, 'a']
ERROR - Cannot infer instance
*** Instance : Num Char
*** Expression : [1,'a']

しかし、これも、data 宣言で型をつくれば可能になる。

Hugs> :e combi.hs

(combi.hs の内容)
data Combi a = Cint Int | Cchar Char
  deriving Show

Hugs> :l combi.hs
Main> [Cint 1, Cchar 'a']
[Cint 1,Cchar 'a']

不便さを感じるのはこれくらいで、関数の型宣言は単に引数と戻り値の型を並べただけだし、それだって型推測があるからどうしても書かなければならないというほどのものでもない。

Main> :e qsort.hs

(qsort.hs の内容)
qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)

Main> :l qsort.hs
Main> qsort [2,1,8,3,4]
[1,2,3,4,8]

したがって、初心者のうちは次のように関数の型を明示的に宣言するのは、あとでプログラムを読むときにイメージがつかみやすいようにするためくらいの感覚でもかまわない。

qsort :: Ord a => [a] -> [a]
qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)

要するに、Haskell は強い型づけの言語だといっても、ほとんど型のことを考えないでもプログラムすることができるのだ。

ところで、話は変わるが、関数の型の宣言はどうして 引数1->引数2->戻り値 のような書き方になっているのだろうか。感覚的には、2変数の関数なら (引数1, 引数2) -> 戻り値 のような書き方の方がよいのではないだろうか。実は、Haskell では2変数の関数を、1変数の関数を戻り値とする1変数の関数と見ることができるのだ。

例えば2つの整数を引数にとってその和を返す関数 add を定義したとする。

add :: Int -> Int -> Int
add x y = x + y

これは普通には2つの引数を与える。

Main> add 1 2
3

しかし、add 1 を括弧で囲んで次のようにしても計算できる。

Main> (add 1) 2
3

このとき、(add 1) が何を表すかというと、関数 add に引数1を与えて得られる1引数の関数なのだ。したがってこれに引数 2 を与える (add 1) 2 は数値 3 を戻り値として返す。

そうであれば、(add 1) に別名をつけて新しい関数を定義できるはずだ。そうして、実際にできるのだ。

inc :: Int -> Int
inc = add 1

(実行例)
Main> inc 2
3

Haskell の型について不思議に思ったことを書いてみた。Haskell は強い型づけをする言語かもしれないが、Haskell を使ってプログラムをつくる上ではあまり気にしないでよいことが分かる。Haskell を勉強するのは下手なやり方だ。Haskell は使ってなんぼのプログラム言語なのだ。
[PR]
by tnomura9 | 2009-08-21 20:00 | Haskell | Comments(0)
<< Haskell あれこれ 普通... Haskell あれこれ 再帰... >>