型クラスは、何らかの振る舞いを定義するインターフェイスである。
ある型クラスのインスタンスである型は、その型クラスが記述する
振る舞いを実装する。
もっと言うと、型クラスというのは、関数の集まりを定める。
ある型クラスに属する関数のことをその型クラスのメソッドと呼ぶこともある。
ある型を型クラスのインスタンスにしようと考えたときは、それらの関数がその型ではどういう意味を成すのかを
定義する。
# Eq型クラス(等値性をテストできる型に使われる) Prelude> :t (==) (==) :: Eq a => a -> a -> Bool Prelude> 5 == 5 True Prelude> 5 /= 5 False Prelude> 'a' == 'a' True Prelude> "Ho Ho" == "Ho Ho" True Prelude> 3.432 == 3.432 True # Ord型クラス(何らかの順序をつけられる型のための型クラス) Prelude> "Abrakadabra" < "Zebra" True Prelude> "Abrakadabra" `compare` "Zebra" LT Prelude> 5 >= 2 True Prelude> 5 `compare` 4 GT Prelude> 'b' > 'a' True # Show型クラス(文字列として表現する) Prelude> show 3 "3" Prelude> show 5.334 "5.334" Prelude> show True "True" # Read型クラス(文字列を受けとる。しかし、ただ受けとっただけでは受けとった文字列を 何の型として出力したらよいのか分からないので、型注釈を利用して、明示的に型を宣言する必要がある) Prelude> read "True" || False True Prelude> read "8.2" + 3.8 12.0 Prelude> read "5" - 2 3 Prelude> read "[1, 2, 3, 4]" ++ [3] [1,2,3,4,3] # どの型を返せばよいか分からない Prelude> read "4" <interactive>:23:1: Ambiguous type variable `a0' in the constraint: (Read a0) arising from a use of `read' Probable fix: add a type signature that fixes these type variable(s) In the expression: read "4" In an equation for `it': it = read "4" # 型変数なので、どの型でも返せる。逆に言うと、明示しないといけないときもある。 Prelude> :t read read :: Read a => String -> a Prelude> read "5" :: Int 5 Prelude> read "5" :: Float 5.0 Prelude> (read "5" :: Float) * 4 20.0 Prelude> read "[1,2,3,4]" :: [Int] [1,2,3,4] Prelude> read "(3, 'a')" :: (Int, Char) (3,'a') Prelude> [read "True", False, True, False] [True,False,True,False] # enum型クラス (順番に並んだ型、つまり要素の値を列挙する型である) Prelude> ['a'..'e'] "abcde" Prelude> [LT .. GT] [LT,EQ,GT] Prelude> [3 .. 5] [3,4,5] Prelude> succ 'B' 'C' # Bounded型クラス (下限と上限を有する) Prelude> minBound :: Int -2147483648 Prelude> maxBound :: Char '\1114111' Prelude> maxBound :: Bool True Prelude> minBound :: Bool False Prelude> maxBound :: (Bool, Int, Char) (True,2147483647,'\1114111') # Num型クラス(数のように振る舞う) Prelude> :t 20 20 :: Num a => a Prelude> 20 :: Int 20 Prelude> 20 :: Integer 20 Prelude> 20 :: Float 20.0 Prelude> 20 :: Double 20.0 Prelude> :t (*) (*) :: Num a => a -> a -> a Prelude> :t fromIntegral fromIntegral :: (Integral a, Num b) => a -> b Prelude> :t length length :: [a] -> Int Prelude> (length [1,2,3,4]) + 3.2 <interactive>:60:22: No instance for (Fractional Int) arising from the literal `3.2' Possible fix: add an instance declaration for (Fractional Int) In the second argument of `(+)', namely `3.2' In the expression: (length [1, 2, 3, 4]) + 3.2 In an equation for `it': it = (length [1, 2, 3, ....]) + 3.2 Prelude> fromIntegral(length [1,2,3,4]) + 3.2 7.2
型クラスは抽象的なインターフェイスとして定義されているので、1つの型は
いくつもの型クラスのインスタンスになることが出来るし、1つの型クラスはいくつもの
型をインスタンスとして持てる。例えば、Char 型をインスタンスとする型クラスはたくさん
あって、その中に Eq と Ord クラスがあり、これは2つの文字は等値性比較とアルファベット順比較の
両方が可能だったりするから。