すごいHaskellたのしく学ぼう！ 第2章  読書メモ


##明示的な型宣言

###GHCiで型を調べる

``:t``を使う。

```haskell
:t "a"
-- "a" :: [Char]
:t 1
-- 1 :: Num a => a
:t 2.0
-- 2.0 :: Fractional a => a
```

``::``は〜の型を持つという意味。

###関数の型宣言

引数と戻り値の方は``->``で区切って、戻り値の型は最後。

```haskell
removeNonUppercase :: [Char] -> [Char]
removeNonUppercase st = [c | c <- st, c `elem` ['A'..'Z']]

addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z
```

##Haskellの一般的な型

- Int
- Float
- Double
- Bool
- Char

これらは他の言語とほぼ同じ。
違うのはこれ。

###Integer

とても大きい整数。ただし``Int``を使うほうが効率的。

```haskell
factorial 50
-- 30414093201713378043612608166064768844377641568960512000000000000
```

###()

空のタプルも型。ユニットと呼ばれる。

##型変数

```haskell
:t head
-- head :: [a] -> a
```

``a``が型変数。どんな方も取り得る。
型変数を用いた関数は**多相的関数**と呼ばれる。
他のプログラミング言語にあるジェネリクスにちょっと似ている。

###型変数の命名

``a``、``b``など1文字の場合が多い。

##型クラス

###型クラスとは？

何らかの振る舞いを定義するインターフェイス。
具体的には関数の集まり。
また、それらの関数をその型クラスのメソッドと呼ぶこともある。

オブジェクト指向型言語のクラスとは同じものではない。

###型クラス制約

``GHCi``で``==``の型を確認。

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

``=>``よりも前にあるものは**型クラス制約**と呼ばれる。
この結果の意味は「``==``は同じ型の引数を2つ受け取り、``Bool``を返す。引数の2つの型は``Eq``クラスのインスタンスでなければならない」

###``Eq``型クラス

Haskellのすべての標準型は``Eq``クラスのインスタンス（一部を除く）
2つの引数が同じ値かを確認。

###``Ord``型クラス

何らかの順序付けられる型のための型クラス。

```haskell
:t (>)
-- (>) :: Ord a => a -> a -> Bool
:t (>=)
-- (>=) :: Ord a => a -> a -> Bool
```

###``Show``型クラス

ある値はその型が``Show``型クラスのインスタンスになっていれば、文字列として表現できる。
Rubyの``to_s``みたいなもの？

```haskell
show 3
-- "3"
show "a"
-- "\"a\""
```

###``Read``型クラス

文字列を受け取り``Read``のインスタンス型の値を返す。

```haskell
read "True" || False
-- True
read "False" || False
-- False
read "1" + 2
-- 3
```

こういのはダメ。

```haskell
read "5"
```

``read``関数の型は以下のとおり。
``GHCi``が何を返せばいいかわからない。``GHCi``は``read``関数から戻ってきた値の型を判定できない。
直後に``+ 5``みたいなのがあると整数だと判定できる。

```haskell
:t read
-- read :: Read a => String -> a
```

###型注釈

コンパイラに型を伝える。

```haskell
read "5" :: Int
-- 5
(read "5" :: Int) + 5
-- 10
```

###``Enum``型クラス

要素の値を列挙できる型クラス。

```haskell
['a' .. 'z']
-- "abcdefghijklmnopqrstuvwxyz"
[LT .. GT]
-- [LT,EQ,GT]
```

サンプルとして``[LT .. GT]``とあったけど``LT``ってなんだろうか。

調べたあった。
[HaskellのLT、GT、EQって - skalabeの日記](http://d.hatena.ne.jp/skalabe/20100113/1263396347)

``Ordering``という型らしい。

###``Bounded``型クラス

上限と下限を持つ。

```haskell
minBound :: Int
--9223372036854775808
maxBound :: Int
-- 9223372036854775807
:t minBound
-- minBound :: Bounded a => a
:t maxBound
-- maxBound :: Bounded a => a
```

###``Num``型クラス

数値の型クラス。


```hakell
:t 10
-- 10 :: Num a => a
:t 10.5
-- 10.5 :: Fractional a => a
:t 10 :: Double
-- 10 :: Double :: Double

```

あらゆる数値は**多相定数**として表現されている。
多相定数ってなんだ？


``*``の型を調べる。

```haskell
:t (*)
-- (*) :: Num a => a -> a -> a
```

2つの引数を受け取って1つの数を返し、これらはすべて同じ型でないといけない。
そのため、これはエラーになる。


```haskell
(5 :: Integer) * (2 :: Int)

-- <interactive>:137:19:
--     Couldn't match expected type `Integer' with actual type `Int'
--     In the second argument of `(*)', namely `(2 :: Int)'
--     In the expression: (5 :: Integer) * (2 :: Int)
--     In an equation for `it': it = (5 :: Integer) * (2 :: Int)
--
```

けどこれはOK。

```haskell
5 * (2 :: Integer)
-- 10
```

5は``Int``、``Integer``のどちらとしても振る舞える。

###``Floating``型クラス

``Float``と``Double``が含まれる。浮動小数点の型クラス。

###``Integral``型クラス

``Num``は実数の型クラス、``Integral``は整数の型クラス。

####``fromIntegral``関数

浮動小数点と整数を一緒に扱う場合に使う。

```haskell
fromIntegral :: (Integral a, Num b) => a -> b
```

何らかの整数を引数に取って一般的な数値を返す。

例えば``length``関数は整数を返すので、その値に実数をプラスするとエラー。

```haskell
length [1,2,3] + 3.2

-- <interactive>:148:18:
--     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] + 3.2
--     In an equation for `it': it = length [1, 2, 3] + 3.2
```

``+``は同じ型でなければいけない。

```haskell
:t (+)
-- (+) :: Num a => a -> a -> a
```

```haskell
fromIntegral(length [1,2,3]) + 3.2
-- 6.2
```

###型クラスに関するいくつかの注意

* 1つの型クラスはいくつもの型クラスのインスタンスになることができる
* 1つの型クラスはいくつもの型をインスタンスとして持てる
* ある型のインスタンスにするために一旦、別のクラスのインスタンスにする必要がある場合がある
* ``Ord``クラスのインスタンスになるには``Eq``クラスにインスタンスになる必要がある