シリーズ :: [Qiita記事]
Haskell個人メモ :: 1.基本
Haskell個人メモ :: 2.型 ←いまここ
Haskell個人メモ :: 3.関数の構文
Haskell個人メモ :: 4.再帰
明示的な型指定
5 :: Int -- 5
5 :: Float -- 5.0
値 :: 型と書くことで明示的に型を指定できる。
値はxxx型によって表現される、と読むと分かりやすいかも。
:t 'A' -- 'A' :: Char
:t "Hello" -- "Hello" :: [Char]
REPLだと:t 値で実際の型が何かを調べられる。
(純粋関数型言語なので)関数も値の一種なので、:t 関数で型を調べられる。
Haskellの一般的な型
| 型 | 説明 |
|---|---|
| Int | 整数 |
| Integer | 限界がない整数(固定のビット長を持たない) |
| Float | 単精度浮動小数点 |
| Double | 倍精度浮動小数点 |
| Bool | True / False |
| Char | 文字(Unicode) |
| タプル | 最大数は62 |
型変数
:t take -- take :: Int -> [a] -> [a]
上記におけるaが「型変数」で、他の言語で言うところのジェネリクス。
つまり、中身の型(ここではリストの要素の型)を限定しない時に使う。
ちなみに型変数を用いた関数を「多相的関数」を呼ぶ。
(呼び方の問題なのであまり重要ではないけれど)
:t fst -- fst :: (a, b) -> a
同じ型変数が指定されている場合(上記ではa)、はそれらは同じ型でなければならない。
逆に異なっている型変数(上記ではaとb)が、異なる型である必要はない。
型クラス
基本
:t (==) -- (==) :: Eq a => a -> a -> Bool
Javaでいうところの「インターフェース」、Objective-C / Swift でいうところの「プロトコル」。
(既存の型を含めて、拡張できるという意味ではSwiftのプロトコル/エクステンションが非常に近い)
上記のEqが「型クラス」の例で、等値性をテストするためのインターフェースを定義している。
(具体的には==と/=の2つ)
型クラス制約
Eq a =>は「型クラス制約」と呼び、aがEq型クラスの関数を実装している必要があること示す。
つまり、aは==と/=で比較可能でなければならない。
他言語で言えば、引数として「インターフェース」や「プロトコル」が要求されているイメージ。
インスタンス
ある「型」が、ある「型クラス」に適合している場合、(その型はある型クラスの)「インスタンス」である、と表現する。
例えば、自作の型FooをEq型クラスに適合する場合、「Foo型をEq型クラスのインスタンスにする」と表現する。
型+型クラス=インスタンス化、みたいなイメージを持つと分かりやすいかも。
用語のまとめ
| 型 | 説明 | コード例 |
| :------------- | :------------- | :------------- | :------------- |
| 型クラス | 振る舞いを定義するインターフェース | Eq |
| 型クラス制約 | その型が準拠していなければならない型クラスを指定 | Eq a => |
| インスタンス | 型クラスに準拠している型 | - |
標準の型クラス(の例)
| 型クラス (*1) | 振る舞い | インターフェース |
| :------------- | :------------- | :------------- | :------------- |
| Eq | 等値性のテスト | == /= |
| Ord(Eq) | 順序付け | > < >= <= compare |
| Show | 文字列として表現可能 | show |
| Read | 文字列から値を復元可能 | read |
| Enum | 値を列挙できる | succ pred |
| Bounded | 上限と下限を持つ | maxBound minBound |
| Num | 数 | + - * 他 |
| Fractional(Num) | 分数 | / 他 |
| Floating(Fractional) | 浮動小数点 | sin cos tan 他 |
| Integral(Num) | 整数(全体) | div mod 他 |
*1 ()内は前提となる型クラス。例えば、Ordのインスタンスになるためには、Eqインスタンスでなければならない。