Haskell入門

<!-- $theme: default -->

# Haskell入門

![](https://upload.wikimedia.org/wikipedia/commons/1/1c/Haskell-Logo.svg)

---

## 対象

「Scala モナド」などでググったけどHaskellでの説明が出てきて、Scalaっていうたやん！とキレたことのある人。

## 目標

Haskellで書かれた式が読める

---

## モナド則

1. `return x >>= f == f x`
2. `m >>= return == m`
3. `(m >>= f) >>= g == m >>= (\x -> f x >>= g)`

---

## ※注

![](http://ecx.images-amazon.com/images/I/51P6NdS4IGL.jpg)

僕はまだこれしか読んでません。

---

## Haskellとは？

<img src="https://upload.wikimedia.org/wikipedia/commons/1/1c/Haskell-Logo.svg" width="100" />

+ 強い静的型付け
+ 関数型言語
+ 遅延評価
+ ロゴがかっこいい

---

## 基本

```haskell
> 1 + 2
3
> True && False
False
> 1 == 1
True
> "Hello" /= "hello"
False
> 1 : 2 : 3 : []
[1,2,3]
```

---

## 関数

---

### 普通の関数(前置記法)

関数名の後にスペース区切りで引数を続ける

```haskell
> min 4 10
10
> max 100 (10 * 50)
500
```

---

### 中置記法

引数を2つ取る関数は `` で囲む事で2つの引数の真ん中に置くことが出来る。
関数の名前に記号も使える。(`!#$%&*+./<=>?@\^|-~`)
`*` などの演算子も関数で、記号のみの関数はデフォルトで中置記法になる
中置記法がデフォルトの関数を前置記法で使いたい場合は`()`で括る

```haskell
> div 5 2
2
> 5 `div` 2
2
> (+) 5 10
15
```

---

### 関数定義

`関数名 引数 = 式` とするとことで定義可能。
引数が複数ある場合はスペース区切りで渡す。
記号のみの関数名は`()`で括る

```haskell
> sum5 x = x + 5
> sum5 10
15
> (@~@!) x y = x + y
> 10 @~@! 10
20
```

---

### 無名関数

いわゆるラムダ式

`\`から始まる式が無名関数となる

```haskell
> (\x -> x + 100) 1
101
> (\x y -> x + y) 1 2
3
> map (\x -> x + 100) [1..10]
[101,102,103,104,105,106,107,108,109,110]
```

---

### セクション

中置演算子を`()`を使って部分適用したものをセクションと呼び、よく使う。
さっきの`\x -> x + 100`はセクションの`(+100)`と等しい

```haskell
> map (+100) [1..10]
[101,102,103,104,105,106,107,108,109,110]
> map (*2) [1..5]
[2,4,6,8,10]
```

---

## 型

---

### 型定義

関数定義の場合に型推論が可能なら型定義は省略できる。
型定義は `関数名 :: 型` という形で行う。
->で複数の型が繋がっている場合、一番最後の型が戻り値の型で、それ以外は引数の型

```haskell
cuboid :: Float -> Float -> Float -> Float
cuboid width height length = width * height * length

> cuboid 3.4 2.5 4
34.0
```

---

#### なぜ引数と返り値の方が同列に定義されるのか？

全ての関数はカリー化されているため。
cuboid に width を渡すと (height と length を取り直方体の体積を返す関数) が得られる
同様にして↑の関数に height を渡すと…

つまり型定義は全て`引数 -> 戻り値`となっており、

`Float -> Float -> Float -> Float` 
は 
`Float -> (Float -> (Float -> Float))` 
と同じ

---

### 型変数


リストの関数のように色々な型に対して動作するものには、型定義に型変数を用いる。
ジェネリクスのようなもの。

```haskell
> head [1,2,3]
1
> :t head
head :: [a] -> a
```

---

### 型クラスと型クラス制約

型クラスとは振る舞いを定義するインターフェース。
例えばある型に対して`Eq`型クラスのメソッド`==`を実装していれば等値性比較の振る舞いが定義できる。

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

↑の`=>`記号が型クラス制約で、
その名の通り型`a`が`Eq`の型クラスに属しているという制約を表している。
(つまりEq型クラスに属しているので `型aの値 == 型aの値` が定義されているという事)

---

### パターンマッチ

```haskell
checkList :: (Show a) => [a] -> String
checkList (x : y : []) = "Two elements " ++ show x ++ " and " ++ show y
checkList (x : []) = "Just one element " ++ show x
checkList [] = "Empty!"
checkList xs = "Many elements " ++ show xs

> checkList [1,2,3,4]
"Many elements [1,2,3,4]"
> checkList ["hello"]
"Just one element \"hello\""
```

Show型クラスは文字列に変換できるインターフェース。
++ は文字列(リスト)の結合演算が行える関数

---

### データ型定義、型コンストラクタ

新しい型は `data 型名 = 型 (| 型2 (| 型3 ...))` という様に定義できる。
`|`で複数の型が繋がっている場合はいずれかの型がそのdataの型となりうる事を表している。
またこの時`型名`を型コンストラクタと呼ぶ。

```haskell
data Point = Pt2d Double Double | Pt3d Double Double Double
distance :: Point -> Point -> Double
distance (Pt2d x1 y1) (Pt2d x2 y2) = sqrt((x1 - x2)**2 + (y1 - y2)**2)
distance (Pt3d x1 y1 z1) (Pt3d x2 y2 z2) = sqrt((distance (Pt2d x1 y1) (Pt2d x2 y2))**2 + (z1 -z2)**2)

> distance (Pt2d 0 0) (Pt2d 3 4)
5.0
```

例
`data Maybe a = Just a | Nothing`
Maybeは `Just a`と`Nothing`のどちらかを取るデータ型で、`Maybe`がその型コンストラクタ

---

### 型クラス定義

型クラスは`class`キーワードを使って行う。

```haskell
class Eq a where
    (==) :: a -> a -> Bool
    (/=) :: a -> a -> Bool
    x == y = not (x /= y)
    x /= y = not (x == y)
```

whereはブロック`{}`のようなもので、`Eq a`の定義の為にスコープを作ると思ってくれれば良い。
`(==)`と`(/=)`がその型クラスに属する型が実装すべきメソッド
`x == y`と`x /= y`はその実装を行っている。実装は行わなくても型クラスの定義は可能。
Eq型クラスでは`==`と`/=`が相補的に実装されているので、実際にはどちらかのメソッドを実装するだけで良い。

---

### 型クラスのインスタンス作成

ある型をある型クラスに属させるのには`instance`キーワードを使って行い、これをインスタンス化と呼ぶ。

```haskell
instance Eq Point where
    Pt2d x1 y1 == Pt2d x2 y2 = x1 == x2 && y1 == y2
    Pt3d x1 y1 z1 == Pt3d x2 y2 z2 = x1 == x2 && y1 == y2 && z1 == z2
    _ == _ = False
    
> Pt2d 1 1 == Pt2d 1 1
True
> Pt2d 1 1 == Pt3d 1 2 3
False
```

---

## モナド則

1. `return x >>= f == f x`
2. `m >>= return == m`
3. `(m >>= f) >>= g == m >>= (\x -> f x >>= g)`

```haskell
> :t f
f :: Monad m => a -> m b
> :t g
g :: Monad m => b -> m c
> :t return 
return :: Monad m => a -> m a
> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
```

---
---
---

## Functor型クラス

Monadのベースのベース

---

Functor型クラスは __全体を写せる__ 振る舞いを持ったインターフェース。

定義は

```haskell
> :i Functor 
class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b
  (<$) :: a -> f b -> f a
  {-# MINIMAL fmap #-}
  	-- Defined in ‘GHC.Base’
```

となっており、最低限`fmap`を実装していればFunctor型クラスのインスタンスになることが出来る。
(`Functor (f :: * -> *)`は __fは型を取って型を返す型コンストラクタ__ という意味)

---

### fmap

改めてfmapの型定義を見ると`fmap :: (a -> b) -> f a -> f b` となっている。

型コンストラクタfはコンテナ型のようなものなので、その文脈で考えると「ある型に包まれた値a」と「値aを値bに変換できる関数」を引数に取って「ある型に包まれた値b」を返すような定義をしている。
実際にリストでは`instance Functor [] where fmap = map`と定義されているため、map関数をイメージすると解りやすい。
ただし、リストのように値が連続している必要はなく、実際の値がある型で包まれていればFunctor型クラスになりうるというのが重要。

---

### fmap使用感

```haskell
> fmap (*2) [1..3]
[2,4,6]
> fmap (++ "I'm alice") (Just "Hi bob.")
Just "Hi bob.I'm alice"
> fmap (++ "I'm alice") Nothing
Nothing
```

fが型コンストラクタなので、取りうる型(MaybeならJust|Nothing)についてfmapが問題なく使える。

---

### Applicative

Monadのベース, Functorの強化版

---

Applicativeは強化版Functorの様な型クラス
定義は

```haskell
> :i Applicative 
class Functor f => Applicative (f :: * -> *) where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b
  (*>) :: f a -> f b -> f b
  (<*) :: f a -> f b -> f a
  {-# MINIMAL pure, (<*>) #-}
  	-- Defined in ‘GHC.Base
```

重要なのは`pure`と`<*>`の2つ。(最低限の実装は`<*>`だけで良い)

---

#### pure

`pure :: a -> f a`

定義から、値aをアプリカティブ値として包む事がわかる。
リストなら`pure 1`は`[1]`、Maybeなら1をJust 1の様になる。

---

#### <*>

`(<*>) :: f (a -> b) -> f a -> f b`

`<*>`は「aをbに変換する関数のアプリカティブ値」と「aのアプリカティブ値」を取って「bのアプリカティブ値」を返す。
また、記号のみの関数なのでデフォルトで中置記法での使用になる (`f (a->b) <*> fa`と使う)

ここでfmapの定義は`fmap :: (a -> b) -> f a -> f b`なので、これと見比べると`a -> b`がアプリカティブ値に包まれているだけと分かる。
つまりfmapの変換関数がJustなどで包まれている場合でも`fmap`の代わりに`<*>`を使えば同じことが出来る。

---

#### <*>使用感

```haskell
> Just (\x -> x + 10) <*> Just 5
Just 15
> Just (\x -> x + 10) <*> Nothing
Nothing
> Nothing <*> Just 5
Nothing
> pure (\x -> x + 10) <*> Just 5
Just 15
> Just (\x -> x + 10) <*> pure 5
Just 15
```

`\x -> ...`はxを引数に取る無名関数を表す。`...`の部分が実装

---

## Monad

Applicativeの強化版

---

```haskell
> :i Monad
class Applicative m => Monad (m :: * -> *) where
  (>>=) :: m a -> (a -> m b) -> m b
  (>>) :: m a -> m b -> m b
  return :: a -> m a
  fail :: String -> m a
  {-# MINIMAL (>>=) #-}
  	-- Defined in ‘GHC.Base’

```