Haskell入門から学ぶ

#### Haskell入門 第2章から抜粋

##### リスト型
```
Prelude> import Data.Char
Prelude Data.Char> map toUpper "abcd"
"ABCD"
Prelude Data.Char> "This is " ++ "book"
"This is book"
Prelude Data.Char> "This is " ++ "book" ++ show [1, 2, 3]
"This is book[1,2,3]"
Prelude Data.Char> "This is " ++ "book" ++ show [1, 2, 3]
"This is book[1,2,3]"
Prelude Data.Char Data.Maybe> filter (\n -> n  `mod`  2 == 0) [1..10]
[2,4,6,8,10]
Prelude Data.Char Data.Maybe> foldl (+) 0 [1..10]
55
```

| リストを扱う関数      |   説明    |
|:-----------------|:------------------|
| head | リストを引数にとり、リストの先頭を取得する  |
| tail| リストを引数にとり、リストの2件目以降を取得する  |
| map| 関数とリストを引数にとり、リストに関数を適用する  |
| filter| boolを返す関数とリストを引数にとり、リストからtrueの要素を返す |
| foldr| 関数とリストを引数にとり、リストを右結合で集計する |
| foldl| 関数とリストを引数にとり、リストを右左結合で集計する |

`foldl`：`関数 デフォルト値 (head リスト)`
`foldr`：`関数 デフォルト値 (tail リスト)`

```
Prelude> :t map
map :: (a -> b) -> [a] -> [b]
```

##### タプル型
```
Prelude Data.Char> x = (True, [1,2,3]) :: (Bool, [Int])
Prelude Data.Char>
Prelude Data.Char> fst x
True
Prelude Data.Char> snd x
[1,2,3]
Prelude Data.Char> head $ snd x
1
Prelude Data.Char> tail $ snd x
[2,3]
```
| タプルを扱う関数      |   説明    |
|:-----------------|:------------------|
| fst| 1件目の要素を取得する  |
| snd| 2件目の要素を取得する  |

#### 3値以上のタプル型を扱う場合はパターンマッチを使って任意の値をとりだすことができる

```
# 3値のタプル型を宣言
Prelude Data.Char> x = (4, 5, 6)
# 先頭の値を取得
Prelude Data.Char> let (n,_,_) = x in n
4
# 3番目の値を取得
Prelude Data.Char> let (_,_,n) = x in n
6
```

##### Maybe a型

##### Maybeって何？
値が入ってるかもしれないし、入ってないかもしれない、そんな値を扱いたい時に`Maybe型`を使う・・・たぶん。
`Maybe`は`Nothing`と`Just`という２つのデータコンストラクターを持っている。
`Nothing`は値を持たないデータ型として例外処理などに使える。
`Just`は１つの値を持つデータコンストラクタ。

```
# 徐算関数を定義　※0除算は例外としてNothing型を返す、それ以外は除算結果をJust型に詰め込む
Prelude Data.Char> :{
Prelude Data.Char| percentage k n | n == 0 = Nothing
Prelude Data.Char|                | otherwise = Just (100.0 * k / n)
Prelude Data.Char| :}
# percentage 20 50を表示
Prelude Data.Char> :{
Prelude Data.Char| case percentage 20 50 of Nothing -> "UNKNOWN"
Prelude Data.Char|                          Just x -> show x
Prelude Data.Char| :}
"40.0"
Prelude Data.Char> import Data.Maybe
Prelude Data.Char Data.Maybe> p = percentage 20 50
Prelude Data.Char Data.Maybe> if isNothing p then "UNKNOWN" else show (fromJust p)
"40.0"
Prelude Data.Char Data.Maybe> p = percentage 20 0
Prelude Data.Char Data.Maybe> if isNothing p then "UNKNOWN" else show (fromJust p)
"UNKNOWN"
Prelude Data.Char Data.Maybe> maybe "UNKNOWN" show (percentage 10 10)
"100.0"
Prelude Data.Char Data.Maybe> maybe "Undefined" show (percentage 10 0)
"Undefined"
```
| Maybe aを扱う関数      |   説明    |
|:-----------------|:------------------|
| isNothing | Maybe aを引数にとり、Nothingか判定する  |
| fromJust | Maybe aを引数にとり、Just値から値を取得する  |
| maybe| デフォルト値、関数、Maybe aを引数にとり、関数を初期値で適用しMaybeを返す  |


##### Either a b型
エラーが発生するかもしれない処理を扱いたい時に`Either`を使う。
`Right型`, `Left型`二つのデータコンストラクタを持ち、正常系は`Right型`,異常系は`Left型`で扱う。

```
Prelude Data.Char Data.Maybe> :{
Prelude Data.Char Data.Maybe| percentage k n | n == 0 = Left "Illegal division by zelo"
Prelude Data.Char Data.Maybe|                | otherwise = Right (100.0 * k / n) :: Either String Double
Prelude Data.Char Data.Maybe| :}
Prelude Data.Char Data.Maybe>
Prelude Data.Char Data.Maybe> -- show
Prelude Data.Char Data.Maybe> :{
Prelude Data.Char Data.Maybe| case percentage 20 50 of Left err -> err
Prelude Data.Char Data.Maybe|                          Right x -> show x
Prelude Data.Char Data.Maybe| :}
"40.0"
Prelude Data.Char Data.Maybe> -- 実行
Prelude Data.Char Data.Maybe> import Data.Either
Prelude Data.Char Data.Maybe Data.Either> either id show (percentage 10 10)
"100.0"
Prelude Data.Char Data.Maybe Data.Either> either id show (percentage 10 0)
"Illegal division by zelo"
```

##### 再帰処理の例

```
Prelude> :{
Prelude| -- n <= 1 の時はnを返す
Prelude| fact n | n <= 1  = 1
Prelude|        | otherwise = n * fact (n - 1)
Prelude| :}
Prelude>
Prelude> fact 10
3628800
```

##### モジュール
**記法：**`module モジュール名(公開する識別子) where`
**記法：**`module モジュール名 where -- 識別子を指定しなかった場合は全てが公開される`

```Main.hs
module Main(main) where

-- mainモジュールの処理
main :: IO () -- ()<Unit型>はJavaのvoidみたいなもの
main = ...
```

##### モジュールの利用

**REPL：** `:module モジュール名`
**Haskellファイル：** `import モジュール名(識別子) -- 識別子を未指定の場合はすべて`
モジュールを読み込むことでモジュールが公開している識別子を利用できる

```
Prelude Data.Char Data.Maybe Data.Either> :module Data.Char
Prelude Data.Char>
Prelude> -- モジュール読み込み削除
Prelude Data.Char> :module -Data.Char
Prelude>
Prelude> -- モジュール読み込み追加
Prelude> :module +Data.Char
Prelude Data.Char> -- <--現在読み込んでいるモジュールが表示されている
Prelude>
Prelude> -- 読み込んでるモジュール情報を取得
Prelude Data.Char> :show imports
import Data.Char
import Prelude -- implicit
```

- mainプログラムからモジュールを利用する

```Example/HelloSample.hs
module Example.HelloSample(helloSample, byeSample) where

helloSample :: String -> IO ()
helloSample name = putStrLn(getHello name)

byeSample :: String -> IO ()
byeSample name = putStrLn(getBye name)

getHello :: String -> String
getHello name = "hello, " ++ name ++ "!!"

getBye :: String -> String
getBye name = "good bye, " ++ name ++ "!!"
```

```myapp.hs
-- Mainモジュール
module Main(main) where 
import Example.HelloSample

main :: IO ()
main = do -- do構文を使うことでIO ()を逐次実行してくれる
  helloSample "Haskell"
  byeSample "Haskell"
```

```
$>stack runghc myapp.hs
hello, Haskell!!
good bye, Haskell!!
```

##### パッケージ
モジュールを再利用、再配布できる単位でまとめたもの。
パッケージの構成はCabalの形式に則って作成する。
パッケージはHackage上で公開、共有されている。
StackageはHackage上のパッケージから選別し管理している。
Stackageは依存関係の解決を簡潔にし、問題なくビルドできるものが利用できるので、Stackageを利用するのがおすすめ。
Hoogleはモジュールの識別子の検索することができる。