読者です 読者をやめる 読者になる 読者になる

Haskell を使ってみる 5 (型)

前回の続き

Haskell を使ってみる 4 (タプル) - kntmr-blog

型宣言

式の型は :t コマンドで調べる

Prelude> :t 'a'
'a' :: Char -- Char型を持つ
Prelude> :t "Hello"
"Hello" :: [Char] -- Char型のリストを持つ
Prelude> :t ('a', True)
('a', True) :: (Char, Bool) -- (Char型, Bool型) を持つ (タプルは個々の要素が型を持つ)

:: は xxx の型を持つことを意味する。明示的な型の名前は常に大文字で始まる。
関数にも明示的な型宣言を与えることができる。 以下は Int の引数を1つ取り Int を返すことを表す。

add :: Int -> Int

型変数

関数が任意の型に対して動作できるようにする。以下は head 関数の型宣言。

Prelude> :t head
head :: [a] -> a

a は型変数と呼ばれる。任意の型を引数に取ることを表す。型変数を使った関数は多相的関数と呼ばれる。
head 関数の型宣言の場合、任意の型のリストを引数に取り、その型の要素を1つ返すことを表す。

型クラス

型クラスは振る舞いを定義するインタフェース。型クラスのインスタンスは型クラスの振る舞いを実装する。
型クラスは関数の集まりで、型クラスに属する関数をその型クラスのメソッドと呼ぶ。

以下は等値性関数の型宣言。

Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool

=> は型クラス制約と呼ばれる。等値性関数の場合、任意の型の2つの引数を取り Bool を返すことを表し、引数の型は Eq クラスのインスタンスであることを意味する。

Eq 型クラス

等値性をテストできる型に使われる。Eq のインスタンス==/= を実装する必要がある。Haskell のすべての標準型は Eq のインスタンスである。

Ord 型クラス

何らかの順序を付けられる型のための型クラス。すべての標準的な大小比較関数 (>, <, >=, <=) をサポートする。以下は compare 関数の型宣言。

Prelude> :t compare
compare :: Ord a => a -> a -> Ordering

Ord のインスタンスの型を引数に取り Ordering を返すことを表す。Ordering は GT, LT, EQ のいずれかの値を取る型。

Prelude> "abc" < "xyz"
True
Prelude> "abc" `compare` "xyz"
LT
Prelude> 2 >= 1
True
Prelude> 2 `compare` 1
GT
Show 型クラス

文字列として表現するための型クラス。show 関数は指定した値を文字列で表示する。

Prelude> show 123
"123"
Prelude> show True
"True"
Read 型クラス

文字列を取って任意の型のインスタンスの値を返すための型クラス。read 関数は文字列を受け取り Read のインスタンスの型の値を返す。

Prelude> read "1" + 2
3
Prelude> read "[1,2,3,4]" ++ [5]
[1,2,3,4,5]

ただし、read "1" は read 関数がどの型の値を返すべきか推論できないためエラーになる。以下は read 関数の型宣言。

Prelude> :t read
read :: Read a => String -> a

read 関数が返す値の型は Read のインスタンスであるが、関数が返すべき型は返される値の使い方次第で判定できる。式が取るべき型を明示的に指定する場合は型注釈を使う。

Prelude> read "1" :: Int -- :: が型注釈
1
Enum 型クラス

要素の値を列挙するための型クラス。Enumインスタンスの値はレンジの中で使える。

Prelude> [1 .. 5]
[1,2,3,4,5]
Prelude> ['a' .. 'e']
"abcde"
Prelude> [LT .. GT]
[LT,EQ,GT]

Enumインスタンスの型には succ 関数と pred 関数 が定義される。

Prelude> succ 'a'
'b'
Prelude> pred 'c'
'b'
Prelude> succ False
True
Bounded 型クラス

上限と下限を持つインスタンスの型クラス。minBound 関数と maxBound 関数で調べることができる。

Prelude> maxBound :: Int
9223372036854775807
Num 型クラス

数の型クラス。Num 型クラスのインスタンスは数として振る舞う。あらゆる数は Num 型クラスの任意のインスタンスとして振る舞うことができる。

Prelude> :t 10
10 :: Num t => t
Prelude> 10 :: Int
10
Prelude> 10 :: Integer
10
Prelude> 10 :: Float
10.0
Prelude> 10 :: Double
10.0

以下は * 演算子の型宣言。

Prelude> :t (*)
(*) :: Num a => a -> a -> a

Num 型クラスのインスタンスの値を2つ引数に取り Num 型クラスのインスタンスの値を返す。
同時に複数の型のインスタンスとして振る舞うことはできないため、(5 :: Int) * (10 :: Integer) は型エラーになる。

Floating 型クラス

浮動小数点に使うための型クラス。Float と Double が含まれる。

Integral 型クラス

整数全体の数のための型クラス。Int と Integer が含まれる。Num 型クラスは実数を含むすべての数のための型クラス。

以下は fromIntegral 関数の型宣言。

Prelude> :t fromIntegral
fromIntegral :: (Num b, Integral a) => a -> b -- 複数の型クラス制約を記述する場合はカンマで区切る

fromIntegral 関数の型宣言の場合、何らかの整数 (Integral) を引数に取り、一般的な数 (Num) を返すことを表す。整数と浮動小数点を一緒に扱う場合に使う。


今回は型について。