だれも Data.Maybe を教えてくれなかった

# はじめに
この数年、 Haskell (以下、 H) を独習している。　[すごい H](https://www.amazon.co.jp/すごいHaskellたのしく学ぼう-Miran-Lipovača/dp/4274068854) をはじめ数冊の本を読み、 web でもたくさんの良記事に出あった。残念ながらすごい H になりきれていない私だが、それでも H 生活に小さな幸せを見出している。

ところで、モジュール `Data.Maybe` は、私にとってはとても大切な H の道具箱なのだが、それについての記事を見た記憶がないのだ。なぜだ、なぜ書く人がいないのか。仕方がないので、私が語ることにする。すでに書いている人がいたらごめんなさい。

# モジュール `Data.Maybe`
名前から想像できる通り、 `Maybe` にまつわる関数群である。 `base` に入っているので、特にインストールなど必要ない。使うには `import Data.Maybe` とすればよい。

以下, [Data.Maybe -- hackage](http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Maybe.html) に載っているものを順番に見ていこう。 (リンクは base-4.12.0.0 のもの)

## `data Maybe a`
```hs:Maybe
data  Maybe a  =  Nothing | Just a
```
みんな大好き `Maybe` の定義。ここで詳述するつもりはないが、シンプルであるにもかかわらず、 Functor とか Monad とか多くの関数型言語の概念にからみ、手続き型言語との差別化に大きな役割を果たしている。 H に欠かせないもの、それが `Maybe` だ。

## `maybe`
```hs:maybe
maybe :: b -> (a -> b) -> Maybe a -> b
```
私はよく使う。第一引数が `Nothing` の時の default 値、第二引数が Just の中身に作用させる関数。

``` title.hs
import Safe (atMay)
-- atMay: 失敗をあつかえる (!!)。 成功時は Just にくるんで値を返し,
-- インデックスに対応する値がないと Nothing を返す

title "男" = "君"
title "女" = "ちゃん"
title _ = "さん"

nameWithTitle s =
  let ws = words s
  in (ws !! 1) ++ maybe "閣下" title (ws `atMay` 3)

main = do
  putStrLn $ nameWithTitle "山田 太郎 5 男"
  putStrLn $ nameWithTitle "田中 花子 4 女"
  putStrLn $ nameWithTitle "小暮 デーモン 100056" -- 性別フィールドがない
```

```
$ stack runghc title.hs
太郎君
花子ちゃん
デーモン閣下
```

## `isJust`, `isNothing`

```hs:isJust,isNothing
isJust :: Maybe a -> Bool
isNothing :: Maybe a -> Bool
```

`Just` か `Nothing` かを判定するときに便利、なのだが、そんなに使わないのではなかろうか。これらの関数を `filter` とかと組みあわせるよりも、 `maybe` とか `catMaybes` とか使う方がより H だと思う。

## `fromJust`

```hs:fromJust
fromJust :: Maybe a -> a
```

Haskell をはじめた頃、 `Data.Map.lookup` の結果だったか、これ絶対 `Just v` なのに、 `v` を取りだせない、ググっても取り外し方見つかんない、と腹立たしく思ったものである。本当は、 functor とか monad とか、なんらかの方法で`Nothing` をちゃんと手当して、値がかぶっている `Just` の皮をやさしく剥いてあげなければならなかったのだ。いまならわかる。

だがしかーし、 `fromJust` を使うと簡単に `Just` を剥けてしまう。乱暴だと思うのだが、ちょっとした作業で絶対 `Just` だとわかっている場合は、これを使えばよいだろう。

なお、これで `Nothing` を無理矢理剥くと例外を発射してくるので注意。

```seibetsu1.hs
import Safe (atMay)
import Data.Maybe

showSeibetsu s =
  let ws = words s
  in (ws !! 1) ++ " " ++ fromJust (ws `atMay` 3)

main = do
  putStrLn $ showSeibetsu "山田 太郎 4 男"
  putStrLn $ showSeibetsu "田中 花子 5 女"
  putStrLn $ showSeibetsu "小暮 デーモン 100056"
```

```
$ stack runghc seibetsu1.hs
太郎 男
花子 女
デーモン seibetsu1.hs: Maybe.fromJust: Nothing
```

## `fromMaybe`

```hs:fromMaybe
fromMaybe :: a -> Maybe a -> a
```

`maybe` の特別な場合。もしくは丁寧な `fromJust`。 `Nothing` に対して default 値を与えられる。やさしいあなたはこれでそっと `Just` を剥いてあげて。

```seibetsu2.hs
import Safe (atMay)
import Data.Maybe

showSeibetsu s =
  let ws = words s
  in (ws !! 1) ++ " " ++ fromMaybe "悪魔" (ws `atMay` 3)

main = do
  putStrLn $ showSeibetsu "山田 太郎 4 男"
  putStrLn $ showSeibetsu "田中 花子 5 女"
  putStrLn $ showSeibetsu "小暮 デーモン 100056"
```

```
$ stack runghc seibetsu2.hs
太郎 男
花子 女
デーモン 悪魔
```

## `listToMaybe`, `maybeToList`

```hs:listToMaybe,maybeToList
listToMaybe :: [a] -> Maybe a
maybeToList :: Maybe a -> [a]
```

`Nothing` と空リストを結びつけるコマンド。 `listToMaybe` は、最初はなんじゃこりゃ、と思ったのだが、みんなのなかで最初に成功したやつだけがえらい、そいつにしか興味がない、という状況はよくあって、意外に使える。一方、 `maybeToList` は私はあまり使っていないのだが、たぶん使っている人は多いんだと思うよ。

とまあ、こんなことを書いている私だが 、実は `listToMaybe` の代わりに `Safe.headMay` を使うことが多い模様。


## `catMaybes`

```hs:catMaybes
catMaybes :: [Maybe a] -> [a]
```

かなり H な関数である、と個人的には思っている。

失敗する関数をデータに適用することについて考えてみよう。

命令型言語なら do ループの中に if 文とか置いて、「危険なの」と言われた時にはなにもしないようにすることだろう。 Haskell でもそのように書くことはできる。

`catMaybes` はちがう。後先考えずにやってしまい、まずいことがおきたら無かったことにしてしまう、そんなことを可能にする。こちらの考え方のほうがより H なのである。

```hs:catMaybes
catMaybes :: [Maybe a] -> [a]
```

``` showAge.hs
import Safe (readMay)
import Control.Applicative ((<$>))
import Data.Maybe

nameAndAge :: String -> Maybe (String,Int)
nameAndAge s =
  let ws = words s
  in ((,) (head ws)) <$> readMay (ws !! 2)

printTpl (n,i) = putStrLn $ n ++ " " ++ show i  

main = do
  mapM_ printTpl . catMaybes . map nameAndAge . lines 
    =<< readFile "meibo.txt" -- データ行のみならずヘッダーも含まれたテキストファイル

```

```
$ cat meibo.txt 
天使幼稚園 ガブリエル組 クラス名簿
姓 名 年齢 性別
山田 太郎 4 男
田中 花子 5 女
小暮 デーモン 100056
$ stack runghc showAge.hs
山田 4
田中 5
小暮 100056
```

## `mapMaybe`
あーこれ使ったことないなー、今度使ってみよー、こんな文章書いておいて `mapMaybe` 使ったことないなんて恥ずかしー、まだまだ私 H じゃないわー。

# さいごに
以上の `Data.Maybe` の関数は、どれも簡単なものである。できる人ならプログラム中に同じ効果のある snippet をさくさく埋め込むことができるだろう。なくても問題ないのだ。

以前、私はそのようなコードを書いていた。いま読み返すと、そんなコードは、なんとういか、ガバガバな感じがする。一方、 `Data.Maybe` を使うと、気持ちよく締まった、まことに　H なコードが書ける。締まったコードを書くのに役立つモジュールは他にも `Data.Either`, `Data.Bool` などがあるが、 `Data.Maybe` は格別だ。

H 初心者の方、 `Data.Maybe` の使い方をおぼえてより H なコードを書いてほしい。そして、初心者に手ほどきをする立場のあなた、是非、 `Data.Maybe` を教えてより H になれるよう、優しく導いてあげていただきたい。