Haskellの型についての章。
一般的なHaskellの型
- Int
有界の整数値。範囲は環境依存。
- Integer
有界でない整数値。大きい値を扱う場合はこっちを使う。動的にメモリを確保するため、Intの方が早い。
- Float, Double
小数点型。他言語と同じ。
- Bool
真偽値型。TrueとFalseの2値。
- Char
Unicode文字を表す。シングルクォートで囲む。
- タプル
タプルも型。ちなみにタプルの要素の最大値は62らしい。なんだその制約。
この時点では厄介な文字列周りの型について触れてないのがすごく良い構成だと思った。
型変数
他言語におけるジェネリクスみたいなやつ。汎用的な関数のシグネチャを見てみると使われている。
:t head head :: [a] -> a
型変数を用いた関数を 多相的関数 というらしい。おそらく数学由来の用語なんだろう。
型クラス
他言語におけるインターフェースのようなもので、ある型をその型クラスのインスタンスとして定義することは、その型に特定の振る舞いを持たせることを意味する。例えば、Eq型クラスのインスタンスとなる型は「同一性を判定できるもの」と定義することができる。
- Eq型クラス
等値性をテストできる型クラス。(==) と (/=) を定義していなければならない。
- Ord型クラス
なんらかの順序を付けるための型クラス。
- Show型クラス
これのインスタンスは文字列として表現することができる。例えば、以下のようにshow 関数を適用したときに文字列に変換できる。
show 3 #=> "3"
- Read型クラス
Show型クラスの逆で、文字列から変換可能な値を表す。例えば、文字列にread関数を適用したときによしなに変換してくれる。
read "3" + 5 #=> 8
ただし、以下のように適用するとエラーになる。
read "4"
read関数のシグネチャは以下。
ghci> :t read read :: Read a => String -> a
文字列を受け取り、任意のRead型クラスのインスタンスaを返す。先程の read "3" + 5の例では、GHCが変換する値を文脈から推測できた(めちゃくちゃ賢いね)。しかし、単体で適用するとコンテキストがないため、何の型に変換すれば良いかわからなくてエラーになる。この場合、 型注釈 を使い、明示的に変換先の型を指定する必要がある。
read "4" :: Int
- Enum型クラス
順番に並んだ型、要素の値を列挙できる型。Ordとちょっと似ているが、比較できる必要はない。これのインスタンスは後者関数succ, 前者関数pred, さらにはrange記法を使ったりできる。比較の際に使用するLT, GTなどもこれのインスタンス。
[LT .. GT] #=> [LT, EQ, GT]
- Bounded型クラス
上限と下限を持つ値を表す。minBound, maxBoundを適用できる。
ghci> minBound ::Int -9223372036854775808
ちなみにminBound(maxBound)のシグネチャは以下のようになっている。
ghci> :t minBound minBound :: Bounded a => a
引数を取らず、aが何の型なのかを指定する必要があるため型注釈を用いなければならない。さっき出てきたreadと同じ。 多相定数と呼ばれる。
- Num型クラス
実数全体を表す型クラス。
ghci> :t 3 3 :: Num a => a
全ての数は多層定数になっている。そのため、Num型クラスの任意のインスタンスとして振る舞うことができる。
20::Int 5.5::Double 5.5::Float
- Floating
DoubleとFloat。浮動小数点数のための型クラス。
- Integral 整数を表す型クラス。fromIntegral関数がある。
数値計算について
数値計算周りはちょっと気をつけなきゃいけなさそう。一般的な演算子のシグネチャは以下のようになっている。
ghci> :t (+) (+) :: Num a => a -> a -> a
つまり、Num同士ならよしなに推論してくれるが、IntとDoubleに型付けられた数字同士の計算はエラーになる。
ghci> (3 :: Int) + (4.5 :: Double)
この時のための便利な関数として fromIntegral
が紹介されている。Integral(整数値)をNum型クラスの任意のインスタンスbに戻してくれるため、これで型推論を利かせられるようになる。
ghci> :t fromIntegral fromIntegral :: (Integral a, Num b) => a -> b ghci> fromIntegral((3 :: Int)) + (4.5 :: Double) 7.5
感想
数値が Num a => a
という定義になっているのは面白い。