Type variables (型変数)

In [1]:
:t head
head :: forall a. [a] -> a
  • 型定義にて小文字で始まる名称の型は型変数となる
    • 他の言語のgenericsに似ているがより強力
  • 型変数を持つ関数を多相的関数(polymorphic function)という
  • 型変数の名前は複数文字でも良いが、通例として一文字の型変数名が使われている
In [2]:
:t fst
fst :: forall a b. (a, b) -> a
  • 関数で複数の異なる型を表す場合は異なる型変数名を与える

Typeclasses 101

型クラス(typeclass)

  • 振る舞いを定義するインターフェースの一種
In [3]:
:t (==)
(==) :: forall a. Eq a => a -> a -> Bool
  • 例えば == 関数はEqを型クラスとして持つ型を2個を引数にとる
  • (関数定義では=>の左側に型制約を定義する)

Note:

  • =,+,-,/などの記号で構成された関数名の関数は中値関数となる
  • 前置関数として呼び出す場合は関数名を()で囲んで使用する
In [4]:
:t elem
elem :: forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
  • elem関数はlistの中に探している値と等しい値があるかチェックするので引数にEq型クラスの実装を必要とする

基本的な型クラス

Eq

In [5]:
5 == 5
5 /= 5
'a' == 'a'
"Ho Ho" == "Ho HO"
3.432 == 3.432
True
False
True
False
True
  • Eqは2個の値が等しいかどうかテストするインタフェースを提供する型クラス
  • Eq型クラスのメンバは==/=を実装する

Ord

In [6]:
:t (>)
(>) :: forall a. Ord a => a -> a -> Bool
  • Ordは順序を持つ型のための型クラス
  • >, <, >=, <などの一般的な比較関数を実装する
In [7]:
"Abrakatabra" < "Zebra"
"Abrakatabra" `compare` "Zebra"
5 >= 2
5 `compare` 3
True
LT
True
GT
In [8]:
:t compare
compare :: forall a. Ord a => a -> a -> Ordering
  • compare関数は2個の同じOrd型クラスのメンバ型の変数を取りOrdering型の値を返す(OrderingはGT, LT, EQの型)

Show

In [9]:
show 3
show 5.334
show True
"3"
"5.334"
"True"
  • Showは値を文字列として表現するインターフェースを提供する型クラス
  • ここまで出てきた関数を除く全ての型はShowのメンバ型である
  • メンバー型は、値を文字列で返すshow関数を実装する
In [10]:
show "abc"
"\"abc\""
  • 文字列をshowするとダブルクォーテーションで囲まれた文字列が返る

Read

In [11]:
read "True" || False
read "8.2" + 3.8  
read "5" - 2 
read "[1,2,3,4]" ++ [3]
True
12.0
3
[1,2,3,4,3]
  • Readは文字列からRead型クラスのメンバ型の値を返すread関数を実装する
In [12]:
read "4"
Prelude.read: no parse
In [13]:
:t read
read :: forall a. Read a => String -> a

read関数にて、戻り値の型が推論できない場合はエラーとなる

In [14]:
read "5" :: Int
read "5" :: Float
(read "5" :: Float) * 4
read "[1,2,3,4]" :: [Int]
read "(3, 'a')" :: (Int, Char)
5
5.0
20.0
[1,2,3,4]
(3,'a')
  • 型注釈(type annotation)で戻り値の型を明示することができる

Enum

In [15]:
['a' .. 'e']
[LT .. GT]
[3 .. 5]
succ 'B'
pred 'B'
"abcde"
[LT,EQ,GT]
[3,4,5]
'C'
'A'
  • Enum型クラスのメンバ型は、連続的な順序を持つ
    • Enum型クラスのメンバ型はlist rangesucc, pred関数を使用可能
    • (), Bool, Char, Ordering, Int, Integer, Float, Double等がEnum型クラスを実装している

Bounded

In [16]:
(minBound :: Int)
(maxBound :: Char)
(maxBound :: Bool)
(minBound :: Bool)
Redundant bracket
Found:
(minBound :: Int)
Why Not:
minBound :: Int
Redundant bracket
Found:
(maxBound :: Char)
Why Not:
maxBound :: Char
Redundant bracket
Found:
(maxBound :: Bool)
Why Not:
maxBound :: Bool
Redundant bracket
Found:
(minBound :: Bool)
Why Not:
minBound :: Bool
-9223372036854775808
'\1114111'
True
False
  • Bounded型クラスは上限と下限の制限範囲を持つ
    • Bounded型クラスのメンバ型はminBoundmaxBound関数で制限範囲を確認できる

Note:

In [17]:
:t minBound
minBound :: forall a. Bounded a => a
  • minBoundmaxBound等の引数を取らない関数を多相定数という
In [18]:
(maxBound :: (Bool, Int, Char))
Redundant bracket
Found:
(maxBound :: (Bool, Int, Char))
Why Not:
maxBound :: (Bool, Int, Char)
(True,9223372036854775807,'\1114111')
  • tupleもBouded型クラスを実装している

Num

In [19]:
:t 20
20 :: forall p. Num p => p
  • Numは数の型クラス。メンバ型は数として扱える属性を持つ
In [20]:
20 :: Int
20 :: Integer
20 :: Float
20 :: Double
20
20
20.0
20.0
  • 全ての数値は多相定数でもある
  • Num型クラスに所属しているメンバ型はShow型クラスとEq型クラスも所属していることになる

[補足]

  • Haskell 2010 の仕様では、上に書いたように EqShowNum のスーパークラスとなっている。しかし、最近の GHC ではこれらは Num のスーパークラスではなくなっている

Integral

  • Integralも数の型クラス。Num型クラスは全ての数字(実数と整数)Integral型クラスは整数のみ。
    • IntIntegerがメンバ型

Floating

  • Floating型クラスはFloatDoubleなどの実数のみ。
In [21]:
:t fromIntegral
fromIntegral :: forall a b. (Integral a, Num b) => a -> b
In [22]:
fromIntegral (length [1, 2, 3, 4]) + 3.2
7.2
  • 数値を扱う場合fromIntegral :: (Num b, Integral a) => a -> b 関数が便利
    • 例えばlength関数はIntを返すがこれはFloatと足すことができない。fromIntegralでFloatに変換できる。