Elmの乱数を使いこなす

# はじめに
[この記事](https://qiita.com/Keck/items/8c31af413735926ae4e1#%E6%84%9F%E6%83%B3)で乱数を使ったのですが、Elmの独特な乱数の取り扱いについて全く解説できずに終わってしまいました。
この記事で解説という名のリベンジをしてみようと思います。
最低限、Model、Update、View、CmdといったThe Elm Architectureの要素を理解している方が対象です。
`Random.map`や`Random.andThen`について解説している記事はどうやらなさそうなので、多分多少の新規性はあるでしょう、きっと・・・

Elmは**純粋関数型言語**と言われており、純粋な関数、すなわち**引数が同じなら、常に同じ戻り値を返す**ような関数しか定義することができません。
OSの時計へのアクセスや、HTTP(Ajax)通信のような**外の世界**へのアクセスを、関数内で行うことはできません。(Debugモジュールのことは一旦無視しましょう。)
乱数の生成はどう見ても**外の世界**へのアクセスを伴います。 処理の途中で乱数を使うような関数は、引数が同じなら、常に同じ戻り値を返す関数では決してありません。 (同じなら乱数使う意味ないですよね)
しかし、Elmはその純粋性と、**外の世界**へのアクセスを伴う処理を両立しています。 
それ故、多少扱いがいわゆる一般的な手続き言語とは異なっており、初めて取り組む方にとってはちょっととっつきにくいかもしれません。(が、多分すぐ慣れますし、慣れたら簡単です。)

この記事では以下の実装を行います。
1.　乱数を生成してみる
2.　偶数の乱数を生成してみる
3.　リストを受け取り、リストをシャッフルするような関数を作ってみる
4.　乱数を生成し、その数だけ偶数の乱数を生成してみる(=偶数のリストを生成する)
5.　懐かしのズンドコキヨシ

これだけできたら多分困らないでしょう・・・

次の記事では（ちゃんと書きます）トランスパイル後のJavaScriptで処理が実際にどのように行われているかを見ていきます。

# 本編
## 基本的な構成について
ベースのコードは以下の通りとします
また、ソースは[ここ](https://github.com/IamKeck/elm-random-example)に置いておきました。

```elm
module Main exposing (Flags, Model, Msg(..), main)

import Browser exposing (element)
import Html as H
import Random


type alias Model =
    { partOne : Int
    , partTwo : Int
    , partThree : List String
    , partFour : List Int
    , partFive : String
    }


type Msg
    = GotOne Int
    | GotTwo Int
    | GotThree (List String)
    | GotFour (List Int)
    | GotFive String




type alias Flags =
    ()


main : Program Flags Model Msg
main =
    element
        { init =
            always
                ( { partOne = 0, partTwo = 0, partThree = [], partFour = [], partFive = "" }
                , Cmd.none
                )
        , view = view
        , update = update
        , subscriptions = always Sub.none
        }


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotOne int ->
            ( { model | partOne = int }, Cmd.none )

        GotTwo int ->
            ( { model | partTwo = int }, Cmd.none )

        GotThree intList ->
            ( { model | partThree = intList }, Cmd.none )

        GotFour stringList ->
            ( { model | partFour = stringList }, Cmd.none )


view : Model -> H.Html Msg
view m =
    let
        concanatedPartFour =
            List.map String.fromInt m.partFour |> String.join ", "
    in
    H.table []
        [ H.tr
            []
            [ H.td [] [ H.text "Part1" ]
            , H.td [] [ H.text <| String.fromInt m.partOne ]
            ]
        , H.tr
            []
            [ H.td [] [ H.text "Part2" ]
            , H.td [] [ H.text <| String.fromInt m.partTwo ]
            ]
        , H.tr
            []
            [ H.td [] [ H.text "Part3" ]
            , H.td [] [ H.text <| String.join ", " m.partThree ]
            ]
        , H.tr
            []
            [ H.td [] [ H.text "Part4" ]
            , H.td [] [ H.text concanatedPartFour ]
            ]
        , H.tr
            []
            [ H.td [] [ H.text "Part5" ]
            , H.td [] [ H.text <| m.partFive ]
            ]
        ]




```

ModelやMsgが、各問題の答えに対応するようにしています。

あと、[elm/random](https://package.elm-lang.org/packages/elm/random/latest/) をインストールしてください。

## 1.乱数を生成してみる
まずは乱数を生成してみます。 ここでは１〜１０の整数を生成してみましょう。

```elm
partOne : Random.Generator Int
partOne =
    Random.int 1 10
```

Random.Generatorという謎の型が出てきたり、Intが戻り値じゃなかったり、Random.intというなんとなく用途は分かりそうな関数が出てきました。 一つずつ解説していきます。

まずRandom.intの型は以下の通りです。

```elm
Random.int : Int -> Int -> Random.Generator Int
```
生成する乱数の最低値と最高値を引数にとり、`Random.Generator Int`という謎の値を返していますね。

では次に、`Random.Generator`とはなんでしょうか？
ここでは、**乱数を生成する指示書**としておきましょう。 「また訳のわからない例えを使いやがって・・・」と思われる方も多数いらっしゃるかもしれません。 しかしこれはあながち例えでもないのです・・・ この指示書の正体は次の記事でちゃんと説明します。
`Random.Generator`は型引数を一つ取ります。 なんとなくお察しかもしれませんが、この型引数は、指示書によって最終的に生成される値の型を示しています。

つまり、`partOne`は**指示書**です。 乱数値そのものではありません。 今回の`partOne`はただの値ですが、今後引数をとって、指示書を返すような関数を作っていきます。 しかし、その場合でも、どんな引数を与えたとしても、返ってくるのは引数に対応した同じ指示書です。
つまり、乱数を使う処理であっても、純粋な関数として定義できるのです！ 
最初にこれを聞くとなんか屁理屈のように感じるかもしれませんが、実際そうなっているのです。

ところで、実際に乱数の値を受け取るにはどうすればよいのでしょうか？
まずこの関数を使います。

```elm
Random.generate : (a -> msg) -> Random.Generator a -> Cmd msg
```

型引数が多数使われていますが、今回の場合はこうなるでしょう

```elm
Random.generate : (Int -> Msg) -> Random.Generator Int -> Cmd Msg
```

つまり、「生成される乱数値を引数にとって、Msgにする関数」、および指示書を受け取って、Cmdを返す関数です。
Cmdはinit関数で戻り値にしたり、update関数で戻り値にするんでしたね。
そして、update関数の引数として生成された乱数を受け取ります。

今回はinit関数に渡してみましょう

```elm

main : Program Flags Model Msg
main =
    element
        { init =
            always
                ( { partOne = 0, partTwo = 0, partThree = [], partFour = [], partFive = "" }
                , Random.generate GotOne partOne  -- ← これ！！！！
                )
         -- 以下続く・・・
```
ということで渡してみました。

update関数で乱数値を受け取るところを再掲します。(ちょっと変数名を変えています)

```elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotOne randomValue ->　   --このrandomValueが生成された乱数
            ( { model | partOne = randomValue }, Cmd.none )
        -- 以下続く
```

GotOneという値に詰められた値として乱数を受け取ることができます。
乱数をModelに格納することができましたので、あとはview関数で好きに表示してください。

## 2.　偶数の乱数を生成してみる
というわけで無事に乱数を生成することができました。 
今後は指示書からCmdを作り、initで返し、update関数で値を受け取る手順は省略し、指示書を生成するところまでを解説することにします。 
また、以後は指示書という言葉は基本的に使わず、正式な名である`Random.Generator`と呼ぶことにします。

今回は偶数の乱数を生成する`Random.Generator`を生成してみます。
しかし、[公式パッケージのドキュメント](https://package.elm-lang.org/packages/elm/random/latest/Random)には、偶数を生成する`Random.Generator`を返す関数など定義されていません。
そこで、乱数値を生成し、その値を２倍することで偶数の乱数を生成することにしましょう。

ではどうやるのでしょうか。 先ほどのように生成された乱数をupdateで受け取り、その値を２倍してからModelに格納する方法が思いつきます。

今回はそれでも良さそうです。 しかし、例えば`正の整数の乱数を３つ生成し、その値を全て足した値〜全てかけた値の範囲で新たに乱数を生成、最初の３つの数のうち、新たな乱数と一番近い数と足した値を表示する`という処理だった場合は？
Cmdを発行 → Updateで受け取り という手順を何回も繰り返さないといけません。 しかも、最初の３つの乱数をModelに保存する必要もあるでしょう。 かなりめんどくさそうです。
大丈夫です、Elmにはこのような複雑な乱数処理を一発で行う方法があります。 つまり、最終的に欲しい値を得られるような`Random.Generator`を作る方法があるのです。 

カギは`Random.map`と`Random.andThen`と`Random.constant`です。(が、この章では`Random.map`しか使いません。)

では今回のコードです。 今回は1〜100の間で偶数を生成することにします。

```elm
partTwo : Random.Generator Int
partTwo =
    let
        gen =
            Random.int 1 50

        double =
            \n -> n * 2
    in
    Random.map double gen
```

(もちろんこれくらい1行でかけるのですが、今回はわかりやすさのため、冗長であってもこのように書きます。)

genは1~50の整数を生成する`Random.Generator`、doubleは値を２倍する関数ですね。
では`Random.map`とはなんでしょうか？ なんとなく察しがつくかもしれませんが、この関数を使うことで、**`Random.Generator`によって生成される予定の値に、関数を適用することができます！**

`Random.map`の型は以下の通りです。 型を見ればだいたい挙動がわかるのはElmのいい特徴です。

```elm
(a -> b) -> Random.Generator a -> Random.Generator b
```

戻り値も`Random.Generator`であることに注意してください。
あくまで処理の中で作ることができるのは、指示書だけです。 実際の値ではないのです。
指示書の例えで言うと、今回の関数はこんな感じでしょうか

```md

# 指示書1
1. 1〜50の整数を生成する
2. 1の値を返す

# 指示書2
1. 指示書1を実行する
2. 1の値を2倍する
3. 2の値を返す
```

## 3.　リストを受け取り、リストをシャッフルするような関数を作ってみる
実はこの関数は[elm-community/random-extraにある](https://package.elm-lang.org/packages/elm-community/random-extra/latest/Random-List)ので、実際に使うときはこちらを使いましょう。
しかし学習のためなら、車輪の再発明だって許されるはずです。
シャッフル処理はいろいろ考えられるのですが、今回は以下の手順でやってみようと思います。
1. `["a", "b", "c", "d"]`というリストがあるとする
2. リストと同じ長さの乱数列を生成する
3. 最初のリストと2.の乱数列をList.map2でくっつけ、以下のようなリストにする
`[("a", 32), ("b", 100), ("c", 123), ("d", 99)]` (数は例えです)
4. List.sortBy で、リストの各要素のタプルの2番目の要素でリストをソートする
5. `List.map Tuple.first`で、余計な乱数を取り除く

関数内では乱数を直接扱えず、`Random.Generator`として表現するElmでは、
結構ややこしそうな処理に見えます。 が、できます。

とりあえず関数全体を載せてしまいます

```elm
partThree : List a -> Random.Generator (List a)
partThree list =
    let
        randomNumbers : Random.Generator (List Int)
        randomNumbers =
            Random.list (List.length list) <| Random.int Random.minInt Random.maxInt

        zipWithList : List Int -> List ( a, Int )
        zipWithList intList =
            List.map2 Tuple.pair list intList

        listWithRandomNumbers : Random.Generator (List ( a, Int ))
        listWithRandomNumbers =
            Random.map zipWithList randomNumbers


        sortedGenerator : Random.Generator (List ( a, Int ))
        sortedGenerator =
            Random.map (List.sortBy Tuple.second) listWithRandomNumbers
    in
    Random.map (List.map Tuple.first) sortedGenerator
```

関数の型については特に説明は不要かと思います。 そのまんまです。
ではletで定義した変数(変数って呼称いいんでしょうか？)について説明していきます。

まず`randomNumbers`です。`2. リストと同じ長さの乱数列を生成する`に相当します。
 `Random.list`という関数が目につきますが、これの型は

```elm
Int -> Random.Generator a -> Random.Generator (List a)
```

で、第一引数で与えた長さだけ、第二引数の`Random.Generator`で生成される乱数のリストを生成します。
例えば第二引数に先ほどの`partTwo`、つまり偶数を生成する`Random.Generator`を指定すると、偶数の乱数リストが生成されます。 ここでは、整数の`Random.Generator`を指定しました。
`Random.minInt`は、システムで乱数として生成できる最小の値を指します。`Random.maxInt`も同様に最大の値を指します。 つまり、できる限り大きな振れ幅で整数の乱数値を生成します。
第一引数は普通にリストの長さですね。

では次に`zipWithList`と`listWithRandomNumbers`です。
`3. 最初のリストと2.の乱数列をList.map2でくっつけ(略)`
に相当します。
まず、`zipWithList`ですが、これは
`[32,100,123,99・・・]`
のような、`randomNumbers`で生成されるであろう整数のリストを受け取って、最初のリストとくっつけ、
``[("a", 32), ("b", 100), ("c", 123), ("d", 99)]`
のようにする関数です。
では、この関数を使って、最初のリストと、乱数の整数のリストをくっつけましょう。
しかし、乱数の整数リストは`List Int`ではなく、`Random.Generator (List Int)`です。
こういう`Random.Generator`の中に入ってしまった値に関数を適用したいときは？
そう、`Random.map`を使います。（実際にコードを書くときは、指示書がどうこう・・・と考えるのではなく、`Random.Generator`の中に入ってしまった値に関数を適用する、とかそういう風に考えた方が手っ取り早いのではないかと思います。）
というわけで、以下のようにして、「最初のリストと乱数をくっつけたリスト」が完成しました。
型を見ればどんな値なのかよくわかりますね。

```elm
        listWithRandomNumbers : Random.Generator (List ( a, Int ))
        listWithRandomNumbers =
            Random.map zipWithList randomNumbers
```

ではこの数を並べ替えます。 並べ替えには、`List.sortBy`と、`Tuple.second`を使います。
これがどんな関数なのかの解説は、この記事の主旨とは外れるため割愛します。
しかし、公式ドキュメントを見ればわかるのではないでしょうか。
[List.sortBy](https://package.elm-lang.org/packages/elm/core/latest/List#sortBy)
[Tuple.second](https://package.elm-lang.org/packages/elm/core/latest/Tuple#second)
今回も、`Random.Generator`の中の値をならべかえるため、`Random.map`を使っています。
大活躍ですね。
というわけで、並べ替えが以下のようにして完成しました。

```elm
        sortedGenerator : Random.Generator (List ( a, Int ))
        sortedGenerator =
            Random.map (List.sortBy Tuple.second) listWithRandomNumbers
```

あとは、リストの各要素に`Tuple.first`を適用して、余計なソート用の整数を排除します。
リストの各要素に関数を適用するわけですから、もちろん`List.map`を使います。
しかしリストは案の定`Random.Generator`の中にありますので・・・
あとはわかりますね？

```elm
    in
    Random.map (List.map Tuple.first) sortedGenerator
```
というわけで完成です。 めでたしめでたし。 `Random.map`、有能ですね。


## 4.　乱数を生成し、その数だけ偶数の乱数を生成してみる(=ランダムな長さの、ランダムな偶数のリストを生成する)
では次はこれです。 なんか簡単になりましたね。 リストの長さは5〜10、リストの要素である偶数は先ほど同様1〜100としましょう。

まずはリストの長さの`Random.Generator`と、偶数の`Random.Generator`を定義しましょう。

```elm

partFour : Random.Generator (List Int)
partFour =
    let
        listLengthGen : Random.Generator Int
        listLengthGen =
            Random.int 5 10

        evenGen : Random.Generator Int
        evenGen =
            Random.int 1 50 |> Random.map ((*) 2)

```
そのまんまです。 evenGenは見た目こそ違いますが、partTwoの内容と全く同じです。

では、リストの生成です。 公式ドキュメントには、以下の関数があると書いてあります。

```elm

list : Int -> Random.Generator a -> Random.Generator (List a)
```

わかりますでしょうか？ リストの長さと、要素を生成する`Random.Generator`とを渡せば、
その長さだけの乱数のリストが返ってきます。
では、リストの長さを受け取って、ランダムな偶数のリストを生成するような`Random.Generator`を返す関数を定義してみます。

```elm
-- 先ほどのletの中です
        listGen : Int -> Random.Generator (List Int)
        listGen len =
            Random.list len evenGen
```
そのままですね。

リストの長さを生成するRandom.Generatorは先ほど上で定義したので、さっきと同じように`Random.map`して・・・

```elm
    in
    Random.map listGen listLengthGen
```

part4完！と言いたいところですが、このコードはコンパイルが通りません。


```
Something is off with the body of the `partFour` definition:

119|     Random.map listGen listLengthGen
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This `map` call produces:

    Random.Generator (Random.Generator (List Int))

But the type annotation on `partThree` says it should be:

    Random.Generator (List Int)
```
型が`Random.Generator (Random.Generator (List Int))`になってしまっている、
と言っていますね。
Random.mapの型は

```elm
(a -> b) -> Random.Generator a -> Random.Generator b
```

でした。 第一引数に取る関数は、あくまで(`Random.Generator`ではない)普通の値をとって、普通の値を返すような関数です。 ここに、`Random.Generator`な値を返す関数を渡してしまうと、
`Random.Generator`の中に`Random.Generator`が入ってしまう、という二重構造になってしまいます。
このような場合に使うのが、`Random.andThen`です。
型は、

```elm
Random.andThen : (a -> Generator b) -> Generator a -> Generator b
```
です。
第**2**引数に、aな値の`Random.Generator`、第**1**引数に、aをとってbの`Random.Generator`を返すような関数をとります。
最終的には第**1**引数が返す`Random.Generator`の値が返ってきます。今回のケースにぴったりですね。
この説明だと引数は逆の方がしっくりきそうですが、この関数は`|>`と同時に使うことを想定しています。
とりあえず使ってみましょう。

```elm
    in
    listLengthGen |> Random.andThen listGen
```

はい！今度こそpart4完です！

とこれで終わってはあっさりしすぎなので、ちょっとだけ`andThen`について補足説明させてください。
この関数の捉え方はいろいろあるのですが、ひとまず、上記の説明通り捉えておけば良いのではないかと思います。 強いて例えを使うなら、`Random.Generator`と、値をとって`Random.Generator`を返す関数を**チェーン**することができる、ぐらいでしょうか。
第一引数の関数では、第二引数の`Random.Generator`が生成する値が、あたかも本物の値のように扱えるのがミソです。
こういうと`Random.map`も同じじゃないかと思われそうですが、`Random.andThen`は、(`Random.constant`と組み合わせることで)、`Random.map`より遥かに強力な汎用性を持ちます。
実は`Random.map`や(説明していませんが`Random.map2, 3, 4・・・`)は、すべて`Random.andThen`を使って再実装できます。

## 5.ズンドコキヨシ
さあラスボス、ズンドコキヨシです。 昔流行りましたね。
この問題の概要は[こちら](https://qiita.com/shunsugai@github/items/971a15461de29563bf90)の記事に書いてあります。
これこそ乱数を発行して受け取って、Modelに格納、停止判定をしてからまた乱数を発行・・・
というループでもいいような気がしますが、まあ今回は練習のため、一発で生成してみましょう。

早速問題に取り掛かる・・・前に下準備です。

```elm
type Zundoko
    = Zun
    | Doko


showZundoko : Zundoko -> String
showZundoko zundoko =
    case zundoko of
        Zun ->
            "ズン"

        Doko ->
            "ドコ"


zundokoLast =
    List.reverse [ Zun, Zun, Zun, Zun, Doko ]


isZundokoLast : List Zundoko -> Bool
isZundokoLast list =
    List.take 5 list == zundokoLast


```
`Zundoko`型を定義し、文字列化する関数を定義しています。 あとはリストの末尾が「ズン・ズン・ズン・ズン・ドコ」となっているかどうかを判定する関数です。 
(と言っていますが、思いっきり「リストの先頭が、ドコ・ズン・ズン・ズン・ズン」になっているか判定する関数になっていますね。 今回は「ズンかドコ」の乱数を生成するたび、リストの末尾ではなく、先頭に追加していくような実装になっています。したがって、判定部分も通常と逆になっています。)

例によって例のごとく、とりあえずコードを貼り付けます。

```elm
partFive : Random.Generator String
partFive =
    let
        zundokoGen : Random.Generator Zundoko
        zundokoGen =
            Random.uniform Zun [ Doko ]

        loop : Random.Generator (List Zundoko) -> Random.Generator (List Zundoko)
        loop acc =
            acc
                |> Random.andThen
                    (\list ->
                        if isZundokoLast list then
                            Random.constant list

                        else
                            Random.map (\newElem -> newElem :: list) zundokoGen
                                |> loop
                    )

        finalize : List Zundoko -> String
        finalize zundokoList =
            zundokoList
                |> List.map showZundoko
                |> (\x -> "キヨシ!" :: x)
                |> List.reverse
                |> String.join "・"
    in
    loop (Random.constant []) |> Random.map finalize
```

まずはzundokoGenです。`Random.uniform`には変な引数を渡していますが、型を見ればわかる通り、`Zun`か`Doko`をランダムに生成する`Random.Generator`です。
ここで使っている`Random.uniform`のドキュメントへの[リンク](https://package.elm-lang.org/packages/elm/random/latest/Random#uniform)を念のため貼っておきます。

次、今回の実質的なメイン関数である`loop`です。 else部分を見てわかる通り、再帰関数になっていますね。 この関数は、これまでに生成されたズンドコリストをaccという引数で受け取ります。
そして、先ほどの`Random.andThen`を使っていますね。
この関数は、本来accとして`Random.Generator`の中に入っている、これまで生成されたズンドコリストを、第一引数の関数の中で(今回はラムダ式ですね)**あたかも本物の値のように扱える**んでしたね。
つまり、ラムダ式の引数である`list`は、これまでに生成されたズンドコリストです。
ではこのラムダ式の中身を見ていきましょう。

まずif式で、終了判定をしています。頭が「ドコ・ズン・ズン・ズン・ズン」になっているかどうかを見ているんですね。
終了判定がTrueの場合、このまま`list`を返せばいい・・・ わけではありません。 `Random.andThen`の引数は、**(普通の)値を受け取って、`Random.Generator`な値を返す**関数である必要があります。
そこで、`Random.constant`の出番です。
この関数の型は、

```elm
constant : a -> Random.Generator a
```

です。

引数の値を、そのまま`Random.Generator`の中に入れて返します。 指示書の例えを使うならば、
**常に引数の値を返すような乱数生成指示書を作る**
と言ったところでしょうか。
`Random.constant 1`で返ってくる`Random.Generator`は常に1を生成しますし、`Random.constant "hoge"`で返ってくる`Random.Generator`は常に"hoge"を生成します。
意味なさそうな関数ですが、今回の用途にはうってつけです。

ではelse部を見ていきます。

```elm
   Random.map (\newElem -> newElem :: list) zundokoGen
      |> loop
```

またしても`Random.map`を使い、リストの先頭に新たなズン・ドコ乱数を追加、新リストを生成した上で、
loopに渡しています。 再帰していますね。

finalize関数は、`Zun`や`Doko`を`String`にしたり、「キヨシ！」を追加したり、
リストをひっくり返したり、リストを「・」でつないで一つの文字列にしたりしています。
色々やっていますがあまり重要なポイントではないでしょう。

では最後、inの部分です。

```elm
    in
    loop (Random.constant []) |> Random.map finalize
```
`loop`を実行するためには、リストの初期値を与える必要があります。
もちろん初期値なので空リストが適切なのですが、与える型は、`Random.Generator (List Zundoko) `でないといけません。
というわけで、先ほどと同じように`Random.constant`を使い、空リストの`Random.Generator`を作り、引数にして渡します。
`loop`の結果を`finalize`関数に渡したいのですが、`loop`の結果は`Random.Generator`なのでmap(略)

ということで、ズンドコキヨシもできました。 `Random.map`、`Random.andThen`、`Random.constant`があれば、割と複雑そうな処理でも書けてしまうのがわかりましたでしょうか？

次の記事では、コンパイルによって出力されたJSを見て`Random.Generator`の正体を見ていきます。
`Random.map`などが実際には何をしているのかも、併せて見ていきます。
記事が書けたらリンクを貼ります。

#　おまけ
## Random.map2
本文では紹介できなかった`Random.map2`について書いておきます。
`Random.map`は、`Random.Generator`の中の値(Random.Generatorによって生成されるであろう値)に、関数を適用し、`Random.Generator`を返すというものでした。
当然、その関数は1引数の関数であるはずです。 では2引数の関数では？
以下のような関数があると仮定して考えて見ましょう

```elm
add : Int -> Int -> Int
add a b = a + b
```

もし片方が`Random.Generator`、もう片方が普通の値だった場合は、以下のようにすればいいはずです。
本文中でも何回かこのやり方を使っています。

```elm
addOne : Int -> Random.Generator Int -> Random.Generator Int
addOne normalValue genValue = Random.map (add normalValue) genValue
```

`add`に`normalValue`を部分適用して、`Int -> Int`な関数を作ってから、`Random.map`を使っています。 今回は部分適用だけでスッキリ書けましたが、場合によってはラムダ式を使うこともあるでしょう。

では両方の値が、`Random.Generator`だった場合は？
`Random.map2`を使います。 なんとなく名前で察しがつくような気がしますが、見ていきましょう。
型は以下の通りです。

```elm
Random.map2 : (a -> b -> c) -> Random.Generator a -> Random.Generator b -> Random.Generator c
```
2引数の関数と、２つの`Random.Generator`を受け取って、関数適用、値を`Random.Generator`として返す関数ですね。

使ってみましょう。

```elm
addTwo : Random.Generator Int -> Random.Generator Int -> Random.Generator Int
addTwo genOne genTwo = Random.map2 add genOne genTwo
```

まあなんというか、とても普通ですね。

3引数の関数のために、`Random.map3`が、4引数の関数ために`Random.map4`が、5引数の関数のために、`Random.map5`があります。 それ以上引数をとる関数の場合、elm-community/random-extraの[Random.Extra.andMap](https://package.elm-lang.org/packages/elm-community/random-extra/latest/Random-Extra#andMap)なんかが使えると思いますが、ここでの説明は割愛します。
そもそもそんなに引数をたくさんとる関数作ります？

## `Random.andThen`と`Random.constant`で色々再実装する
第4章にて、
> 実は`Random.map`や(説明していませんが`Random.map2, 3, 4・・・`)は、すべて`Random.andThen`を使って再実装できます。

と書きました。 ここで再実装をやってみましょう。

まずは`Random.map`から

```elm
myMap : (a -> b) -> Random.Generator a -> Random.Generator b
myMap f gen =
    gen |> Random.andThen (\val -> f val |> Random.constant)

```
ほら簡単にできました。
`Random.andThen`の引数にする関数の中では、第2引数の`Random.Generator`の中の値を**あたかも本物の値のように扱える**んでしたね。 ならば関数適用だって普通にできます。 このラムダ式は、`Random.Generator`を返さないといけないので、`Random.constant`を使っておしまいです。

次に`Random.map2`をやってみます。

```elm
myMap2 : (a -> b -> c) -> Random.Generator a -> Random.Generator b -> Random.Generator c
myMap2 f gen1 gen2 =
    gen1
        |> Random.andThen
            (\val1 ->
                gen2
                    |> Random.andThen
                        (\val2 -> f val1 val2 |> Random.constant)
            )

```

ほらできた！ ・・・とはいえちょっとややこしいですね。
最初の`Random.andThen`の引数のラムダ式の中で、さらに`Random.andThen`を使っています。
このように`Random.andThen`をネストさえれば、map3だろうがなんだろうが実装できそうです。
ややこしくて、本当にこれであっているのか？と思ってしまいますが、型があっていてコンパイルが通るんだからきっと合ってるんでしょう。
理解が難しいかもしれませんが、ただただややこしいだけですし、無理して理解する必要はないと思います。 おまけですし・・・
説明が雑な気がしますが、まあおまけですし・・・

おしまい。