Haskell 入門

# はじめに

[前回の記事「Prolog 入門」](https://qiita.com/a163236/items/c99cd16ddf77e2228719)では論理型プログラミング言語のPrologについて書いてみました。今回は関数型プログラミング言語のHaskellについて書いていきます。
前回の記事に引き続き、こちらもこれからHaskellなどの関数型言語を学ぼうとしている人や大学の試験対策をしようとしている人向けです。
扱う内容はHaskellの基礎の基礎です。Haskellの詳しい説明ではなく超基礎レベルのプログラム集（問題集）と思って見ていただけると良いと思います。
今回はHaskellの環境構築（チュートリアル）から始まり、

- リスト
- 再帰
- パターンマッチング
- ガード

を使った（本当に）簡単なプログラムを作成しようと思います。ぜひ、参考にしてください。
# 目次
1. Haskellのインストール
2. Haskellの実行
3. 問題&解答編
4. おわりに



# 1. Haskellのインストール
本記事ではWSL(Windows Subsystem for Linux)やUbuntuでのインストールを想定しています。
Haskell Platformをインストールしましょう。

```
$ sudo apt install haskell-platform
```
インストールしましたら、コマンドに`ghci`と打ち込みましょう。

```
$ ghci
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Prelude> 
```
上のようになったらHaskellの実行環境が整いました。おめでとうございます。

# 2. Haskellの実行
とりあえず下のコードのファイルを作成しましょう。Haskellの拡張子は`.hs`です。

```haskell:main.hs
f x = x * x
```
Prelude>に作成したファイル`main.hs`をロードさせます。`:load main.hs`と入力しましょう。

```haskell
Prelude> :load main.hs 
[1 of 1] Compiling Main             ( main.hs, interpreted )
Ok, modules loaded: Main.
```

`:load 「ファイル名」`は下のように`:l 「ファイル名」`ともできます。

```haskell
Prelude> :l main.hs 
[1 of 1] Compiling Main             ( main.hs, interpreted )
Ok, modules loaded: Main.
```
さて、ファイルのロードができたので早速実行してみましょう。

```haskell:実行結果
*Main> f 3
9
*Main> f 6
36
```
上の`main.hs`では引数$x$に対して$x^2$を返す`関数f`を定義しています。

# 3. 問題・解答編

## リスト
### 例題. リストの最初の要素を抜き出す関数を作成せよ
例：`my_head [1,2,3] → 1`

```haskell:my_head.hs
my_head :: [a] -> a
my_head (x:xs) = x
```

```haskell
*Main> :l my_head.hs 
[1 of 1] Compiling Main             ( my_head.hs, interpreted )
Ok, modules loaded: Main.
*Main> my_head [1,2,3,4,5]
```

## パターンマッチング、再帰

### 例題. リストの要素を逆順にする関数を作成せよ
例：`my_reverse [1,2,3,4,5] → [5,4,3,2,1]`

```haskell:my_reverse.hs
my_reverse :: [a] -> [a]
my_reverse [] = []
my_reverse (x:xs) = my_reverse xs ++ [x]
```

```haskell:実行結果
Prelude> :l my_reverse.hs 
[1 of 1] Compiling Main             ( my_reverse.hs, interpreted )
Ok, modules loaded: Main.
*Main> my_reverse [1,2,3,4,5]
[5,4,3,2,1]
```

## ガード

### 例題.ある要素がリストの要素であるかどうかを調べる関数を作成せよ
例：`my_member 3 [1,2,3,4,5] → True`

```haskell:my_member.hs
my_member :: (Eq a) => a -> [a] -> Bool
my_member x [] = False
my_member x (y:ys)
    | x == y = True
    | otherwise = my_member x ys
```

```haskell:実行結果
*Main> :l my_member.hs
[1 of 1] Compiling Main             ( my_member.hs, interpreted )
Ok, modules loaded: Main.
*Main> my_member  1 [1,2,3]
True
*Main> my_member  4 [1,2,3]
False
*Main> my_member 'a' "abc"
True
*Main> my_member 'd' "abc"
False
```

## 総合演習

### 例題. 二つのリストの直積集合リストを求める関数を作成せよ
筆者は数学苦手でこの表現でいいのかよくわかってないんですが、例のようになる関数を作ってみましょう。
例 : `my_product [1,2,3] [4,5,6] → [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]`

```haskell:my_product.hs
my_product :: [a] -> [b] -> [(a,b)]
my_product _ [] = []
my_product [] _ = []
my_product [x] (y:ys) = (x,y) : my_product [x] ys
my_product (x:xs) ys = my_product [x] ys ++ my_product xs ys
```

```haskell:実行結果
*Main> :l my_product.hs
[1 of 1] Compiling Main             ( my_product.hs, interpreted )
Ok, modules loaded: Main.
*Main> my_product [1,2,3] [4,5,6]
[(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]
```

### 例題. リストの要素をクイックソート(昇順)する関数を作成せよ
例：`my_qsort [1,3,5,7,6,4,2] → [1,2,3,4,5,6,7]`

```haskell:my_qsort.hs
my_qsort :: (Ord a) => [a] -> [a]
my_qsort [] = []
my_qsort (x:xs) = my_qsort [a | a <- xs, a < x] ++ [x] ++ my_qsort [b | b <- xs, b >= x]
```

```haskell:実行結果
*Main> :l my_qsort.hs
[1 of 1] Compiling Main             ( my_qsort.hs, interpreted )
Ok, modules loaded: Main.
*Main> my_qsort [1,3,5,7,6,4,2]
[1,2,3,4,5,6,7]
```

# 4. おわりに
最後まで目を通して頂きありがとうございます。
[前回の記事「Prolog 入門」](https://qiita.com/a163236/items/c99cd16ddf77e2228719)に続けて2つ目の記事を書いてみました。
本記事に対してもっと詳細な説明が欲しかったり違う内容についても書いてほしいなどがありましたらコメントでも[Twitter](https://twitter.com/a163236k)でもなんでもいいのでお気軽にご連絡ください。

# 5.参考文献
http://walk.northcol.org/haskell/
https://qiita.com/YoshikuniJujo/items/ad584549cf75c5d28745
https://kntmr.hatenablog.com/entry/2016/09/23/234534