すごいH本読んだからまとめ 3 「型」

## はじめに

* [すごいHaskellたのしく学ぼう](https://www.amazon.co.jp/%E3%81%99%E3%81%94%E3%81%84Haskell%E3%81%9F%E3%81%AE%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%BC%E3%81%86%EF%BC%81-%EF%BC%AD%EF%BD%89%EF%BD%92%EF%BD%81%EF%BD%8E%EF%BC%AC%EF%BD%89%EF%BD%90%EF%BD%8F%EF%BD%96%EF%BD%81%EF%BD%83%EF%BD%81-ebook/dp/B009RO80XY)を読んだのでちょっとずつまとめていきたい。まとめていきたい。

* シリーズ
  * [すごいH本読んだからまとめ 1 「関数の呼び方、関数の定義の仕方」](https://qiita.com/yumakkt/items/ce82eb3ffae874faf249)
  * [すごいH本読んだからまとめ 2 「リスト,タプル」](https://qiita.com/yumakkt/items/36d95c738a3bc17119bd)


### Haskellの型

#### 型を確認してみる

* ghciに`:t`と打ち込むと型を表示できる

```Haskell
*Main Lib> :t 'a' -- シングルクォーテーション、1文字
'a' :: Char
*Main Lib> :t 'ab' -- シングルクォーテーション、複数文字
<interactive>:1:1: error:
    ? Syntax error on 'ab'
      Perhaps you intended to use TemplateHaskell or TemplateHaskellQuotes
    ? In the Template Haskell quotation 'ab'
*Main Lib> :t "aiueo" -- ダブルクォーテーション、複数文字
"aiueo" :: [Char]
*Main Lib> :t True -- 真偽値
True :: Bool
```

* 値に対する型の表示は「値 `::` 型」というフォーマットで出力される。

#### 関数の型

* Haskellは関数の型を明示的に宣言することができる。

```Haskell
isZero :: Int -> Bool -- 引数 -> 戻り値
isZero x = x == 0 -- Int型のxを受け取ってそれが0より大きいかどうかをBool型で返す。
*Main> isZero 9
False

-- 引数が複数ある場合は
-- 「引数 -> 引数 -> ...-> 戻り値」の順に型を定義する。
addThree :: Int -> Int -> Int -> Int  
addThree x y z = x + y + z  

```

#### 型の種類
|型|説明|
|--|--|
|Int|整数|
|Integer|巨大な整数|
|Float|浮動小数点数|
|Double|倍精度浮動小数点数（Floatの2倍のbit数で少数を表すので精度高まる）|
|Bool|TrueとFalseの２つを表す|
|Char|Unicode文字|
|タプル|（）の中の要素数と要素の型に依存して型が決まる。空のタプルも`()`の型を持つ|

* Haskellにおける文字列は文字のリストとして考えることができる

```Haskell
*Main Lib> ['a','i','u','e','o'] == "aiueo" -- 左右は同じもの
True
```

### 型変数

* takeの型を確認するとリストの中身にaと入っている。

```haskell
*Main> :t take
take :: Int -> [a] -> [a]
*Main> take 3 "aiueo" -- 文字列は文字のリスト
"aiu"
```

* takeは指定された数の分だけ、リストの先頭を取り出す関数。

```haskell
*Main> take 2 [1,2,3]
[1,2]
```

* リストの中身はどんな型でも気にしない。そのため、`a`と表記することで、「どんな型でもいいですよ」を表す。
* `a`のようなものを`型変数`と呼ぶ
* `型変数`を用いた関数は`多相的関数`と呼ぶ

### 型クラス

#### 型クラスとは

* ある`型`に特定の関数を適用したときの`振る舞い`を定義するもの
* 型と型クラスは多体多の関係
* 文章ではなんだかよくわからないので具体例を確認する。

#### 例（等値性）
* `(==)`関数の型を確認してみる。(＊ (==)という書き方については[こちら](http://haskell.g.hatena.ne.jp/hyuki/20060601/infix))
```haskell
ghci> :t (==) 
(==) ::(Eq a) => a -> a -> Bool
```

* いままで見たことない`=>`という書き方とその左側にある`(Eq a)`なるもの。ここが型クラス。
* `=>`より右は同じ型の値を2つ突っ込んだら真偽値が入るという関数の型(私達は既に知っているはず。)

```haskell
(Eq a) => a -> a -> Bool
```

* `(Eq a) ` は「`Eq`において性質が保証された型`a`」というふうに読める。
* `A => B `は「AならばがB成立する。」と考えて大丈夫そうなので
* `(Eq a) => 左辺`で「Eqという性質を満たす型aならば左辺が成立」と読める。
* `a`が型変数ということはIntやリストなど、様々な型についてEqによる等値性の定義がされていると考えられる。

具体的に値を入れて関数を実行してみると

```haskell
*Main> (==) [1,2,3] [1,2,3]
True
*Main> (==) [1,2,3] [1,2,2] -- 要素数が同じだけではFalse
False
```
* 要素数が一緒なだけでなく、要素のパターンまで同じでないと`(==)`関数の結果がTrueにならないのは、Eqがリストの等値性をそういう定義にしているからなのである。
* 型クラスはこういう風に「ある`型`に特定の関数を適用したときの`振る舞い`を定義」する

#### 他の型クラス

* Show

文字列として表現できるもの

```haskell
*Main> :t show --show関数の定義をみると
show :: Show a => a -> String -- Show型クラスを条件にした定義が書いてある。
-- 関数名と型クラス名が同じで分かり辛いが大文字から始まるShowは「文字列として表現できる」ということを表す型クラス。
-- showは「与えられた型を文字列にする」関数
*Main> show 1
"1"
*Main> show 3.0
"3.0"
*Main> show 'a'
"'a'"
*Main> show "aaa"
"\"aaa\""
*Main> show True
"True"
*Main> show False
"False"
*Main> show [1,2,3,4]
"[1,2,3,4]"
```

* Num

数のように振る舞えるもの

```haskell
*Main> :t (+) -- 足し算の型確認
(+) :: Num a => a -> a -> a -- 数のように振る舞えるならなんでも足し算していい
*Main> (+) 20 30 --整数でも
50
*Main> (+) 20.0 30.0 -- 浮動小数点数でもね
50.0
```

他にも

+ Ord（順番がある）
+ Enum（列挙可能）
+ Bounded（上限と下限をもつ）
+ Floating（浮動少数点数のみ）
+ Integral(実数のみ)

とかの型クラスで型の性質を定義できる。（基本的な型クラスの定義はHaskellがやっといてくれる）