Haskell個人メモ :: 1.基本


# はじめに
Haskell学習中なのですが、アウトプットして理解を深めようと書いてみました。
まとめのベースは「すごいHaskell楽しく学ぼう」という本で、コード例も似ている（あるいは同じ）ものが多いです。

本の章ごとに個人メモという形で（リファレンス的な）記事を書いていこうと思います。

# シリーズ :: [Qiita記事]

**Haskell個人メモ :: 1.基本　←いまここ**
[Haskell個人メモ :: 2.型](http://qiita.com/YusukeHosonuma/items/b115de430aa0d3fc9205)
[Haskell個人メモ :: 3.関数の構文](http://qiita.com/YusukeHosonuma/items/5da9847db16d33f27a06)
[Haskell個人メモ :: 4.再帰](http://qiita.com/YusukeHosonuma/items/c22171dae82430aa9504)

# Haskellの特徴

- 純粋関数型言語（副作用を持たない）
- 静的型付け
- 型推論がある
- 遅延評価

# 論理演算 - && || not
```haskell
True && True	-- True
False || True	-- True
not True		-- False
```

否定は`!`ではなく`not`。

# 等値比較 - == /=

```haskell
5 == 5	-- True
5 /= 5	-- False
```

`!=`ではなく`/=`。数学の≠をイメージしたものらしい。

# 関数適用

```haskell
min 9 10	-- 9
max 9 10	-- 10
```

関数適用は` `（スペース）
殆どの関数は前置記法で、演算子などの一部が中置記法。

```haskell
10 `div` 2	-- 5
(+) 5 2		-- 7
```

``で囲むことで中置記法として記述できる。
逆に中置記法の演算子（正確には関数）を()で囲むことで前置記法ができる。

```haskell
max 2 1 + 3   -- 5
(max 2 1) + 3

max 2 (1 + 3) -- 4
```

関数適用の結合優先度は最強。
順番を明示したい場合には、他の言語と同様に()で囲む。

# 関数定義（基本）

```haskell
doubleMe  x = x + x
doubleMe' x = x * 2
```

基本形は`関数名 引数 = 本体`。

Haskellの慣習的に、違ったバージョン（遅延しないとか）の時は末尾に`'`をつけたりする。
（数学でいうところの`x`と`x'`みたいな）

# if-then-else

```haskell
isZero x = if x == 0
             then "Yes"
             else "No"
```

ifは式なので値を返す。
そのため`else`は省略できない。

# リスト
```haskell
let lostNumbers = [4, 8, 15, 16, 23, 42]
```

`[]`で囲って`,`で区切って記述する。

```haskell
[1, "Hello"] -- Compile Error
```

リスト内の要素はすべて同じ型である必要がある。

## 連結

```haskell
[1, 2, 3] ++ [4, 5, 6] -- [1,2,3,4,5,6]
```

`++`でリスト同士を連結。
連結するときに1個目のリストの最後まで走査するのでパフォーマンスは（1個目のリストの要素数に対して）O(n)。

## 先頭への要素追加

```haskell
0 : [1, 2, 3]		-- [0,1,2,3]
```

リストの先頭に要素を追加するときは`:`（cons演算子）を使う。
Haskellのリストはconsリストなので、先頭への要素追加は一瞬で終わる。

ちなみに「cons」は「construction（構築）」の略らしい。

## シンタックスシュガー

```haskell
0 : 1 : 2 : 3 : []	-- [0,1,2,3] 
```

前述してきたリスト表記は上記のシンタックスシュガー。
`[]`は空のリスト。

いわゆる単方向連結リストのイメージでOK。
`[0] --> [1] --> [2] --> [3] --> []`

末尾の`[]`は他の言語では`null`や`nil`が格納されることが多い（印象）。

## 要素へのアクセス

```haskell
"Hello" !! 1 -- 'e'
"Hello" !! 5 -- *** Exception: Prelude.!!: index too large
```

`!! index`でアクセス。
範囲外にアクセスするとエラーになる。（ちなみにLisp派生のClojureだと`nil`を返す）

## リスト in リスト

```haskell
[[1, 2, 3], [4, 5, 6]]
```

リストの要素にリストを含めてもOK。
（リストの型が`[Int]`が`[[Int]]`になるようなもの）

## リスト操作関数

### head / tail / init / last

```haskell
head [1, 2, 3, 4, 5] -- 1
tail [1, 2, 3, 4, 5] -- [2,3,4,5]
init [1, 2, 3, 4, 5] -- [1,2,3,4]
last [1, 2, 3, 4, 5] -- 5
```

リスト要素（範囲）を取り出す。

```haskell
head [] -- *** Exception: Prelude.head: empty list
```

いずれも空のリストに対して適用するとエラーになるので注意。

### length

```haskell
length [1, 2, 3, 4, 5] -- 5
```

リストの長さを取得する。

### null

```haskell
null [1, 2, 3]
null []
```

リストが空かどうか調べる。

### reverse

```haskell
reverse [1, 2, 3, 4, 5] -- [5,4,3,2,1]
```

リストを反転させる。

### take / drop

```haskell
take 3 [1, 2, 3, 4, 5] -- [1,2,3]
drop 3 [1, 2, 3, 4, 5] -- [4,5]
```

`take`は先頭から指定された数の要素を「取り出した(take)」リストを返す。
`drop`は先頭から指定された数の要素を「除外した(drop)」リストを返す。

```haskell
take 10 [1, 2, 3, 4, 5] -- [1,2,3,4,5]
drop 10 [1, 2, 3, 4, 5] -- []
```

それぞれリストの要素数を超えても機能する。

### maximum / minimum

```haskell
maximum [1, 2, 3, 4, 5] -- 5
minimum [1, 2, 3, 4, 5] -- 1
```

最大値、最小値をそれぞれ取り出す。
ただし、リストの要素は「順序付け」されている必要がある。

### sum / product

```haskell
sum [1, 2, 3, 4, 5]	-- 15
product [1, 2, 3, 4, 5]	-- 120
```

和、積、をそれぞれ返す。

### elem

```haskell
4 `elem` [1, 2, 3, 4, 5] -- True
6 `elem` [1, 2, 3, 4, 5] -- False
```

リストに指定した要素が含まれているか判定する。
（他の言語では`contains`という名前がよく使われる印象）

```haskell
elem 4 [1, 2, 3, 4, 5] -- True
```

もちろん前置記法で書いてもOK。
（慣れてくるとこっちのほうが関数っぽくて読みやすく感じたりする）

# レンジ（Range）

```haskell
[1..10]    -- [1,2,3,4,5,6,7,8,9,10]
[2, 4..20] -- [2,4,6,8,10,12,14,16,18,20]
```

`[開始値..終了値]`でレンジを指定することができ、その範囲のリストが生成できる。
`[開始値, 次の値..終了値]`でステップ（増分値）を指定したレンジになる。

```haskell
[10, 9..1] -- [10,9,8,7,6,5,4,3,2,1]
```

値が減少していくリストを作る場合は`[開始値, 次の値..終了値]`という指定にする必要がある。
（例えば`[10..1]`とやると、空のリスト`[]`が結果として得られてしまう）

# 無限リスト

```haskell
[1..] -- [1, 2, 3, ...]
```

Haskellは遅延評価なので、無限リストを作ることが可能。
上記をREPLなどで評価すると止まらない。（計算機のリソースが尽きるまで）

```haskell
take 5 [1..] -- [1,2,3,4,5]
```

`take`などを使って、（無限）リストの一部だけを取り出せる。

## repeat / cycle / replicate

```haskell
take 5 (repeat 3) -- [3,3,3,3,3]
take 5 (cycle [1, 2, 3]) -- [1,2,3,1,2]
replicate 3 10 -- [10,10,10]
```

`repeat`は指定された値、`cycle`は指定されたリスト、を繰り返す無限リストを生成。
`replicate`は指定された長さと要素で（無限ではない）リストを作成する。

# リスト内包表記

## 基本

```haskell
[ x * 2 | x <- [1..10] ] -- [2,4,6,8,10,12,14,16,18,20]
```

リストの「フィルタリング」「変換」「組み合わせ」を行う方法の1つ。
`[ 出力値 | 束縛変数 <- リスト ]`という形が基本形で、これだけであれば`map`関数に近い。

## フィルタ

```haskell
[ x * 2 | x <- [1..10], x > 5 ] -- [12,14,16,18,20]
```

`,`の後に述語を指定することでフィルタできる。
（`[ 出力値 | 束縛変数 <- リスト, フィルタ ]`）

## 組み合わせ

```haskell
[ x + y | x <- [1, 2, 3], y <- [10, 100] ] -- [11,101,12,102,13,103]
```

2つのリストの要素を束縛して処理した場合、全組み合わせが計算される。
（`[ 出力値 | 束縛変数1 <- リスト1, 束縛変数2 <- リスト2 ]`）

```haskell
[ x + y | x <- [1, 2, 3], y <- [10, 100], (x + y) > 100 ] -- [101,102,103]
```

前述したフィルタも一緒に使える。
（`[ 出力値 | 束縛変数1 <- リスト1, 束縛変数2 <- リスト2, フィルタ ]`）

ちなみにフィルタのことを「述語」と呼んだりする。（他の言語でも）

# タプル

## 基本

```haskell
(1, 2)
(1, 'A', "Foo")
```

値の組を表現するときに使う。
リストと違って異なる型でもOK。

2つ以上の組み合わせで、1つの値を表現したい時に使うイメージ。

## fst / snd

```haskell
fst (1, 'A') -- 1
snd (1, 'A') -- 'A'
```

要素数が2つのタプル（ペア）限定で、`fst`で1つ目、`snd`で2つ目、の要素が取得できる。

## zip

```haskell
zip [1, 2, 3] ['A', 'B', 'C'] -- [(1,'A'),(2,'B'),(3,'C')]
```

2つのリストを受け取って、それをタプル（ペア）のリストに結合する。

カバンとかジャケットとかの「ジッパー」を「閉める」ときの様子をイメージすると直感的。
（JOJO好きには「スティッキー・フィンガーズ」の逆バージョンと言えばOKかも）

# 文字列

```haskell
"Hello"
'H' : 'e' : 'l' : 'l' : 'o' : []
```

文字列は`""`、文字は`''`で囲む。
Haskellにおいて「文字列」は「文字のリスト」なので、上記のコードは等価。