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

by shigemk2

当面は技術的なことしか書かない

型クラス

Haskell

型クラスは、何らかの振る舞いを定義するインターフェイスである。
ある型クラスのインスタンスである型は、その型クラスが記述する
振る舞いを実装する。

もっと言うと、型クラスというのは、関数の集まりを定める。
ある型クラスに属する関数のことをその型クラスのメソッドと呼ぶこともある。
ある型を型クラスのインスタンスにしようと考えたときは、それらの関数がその型ではどういう意味を成すのかを
定義する。

# 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つの文字は等値性比較とアルファベット順比較の
両方が可能だったりするから。