ズンドコキヨシ with Elm

ズンドコキヨシというタグを見かけたので、Elmで書いてみた、というだけの記事。

ランダムに「ズン」または「ドコ」を出力して、「ズン」４回「ドコ」と続いたら、「キ！ヨ！シ！」と出力して終わる。

#再帰関数、Debug.log版
再帰関数を使ってループさせる。
Debug.logをはさんで、コンソールに出力している。

```hs
module Main where

import Random exposing (bool,generate,initialSeed,Seed)
import Debug exposing (log)
import List exposing (drop)

import Graphics.Element exposing (show)

--Seedを入れるとズンかドコを返す
zunDoko : Seed -> (String,Seed)
zunDoko seed =
  let generator = Random.map (\x -> if x then "ドコ" else "ズン") bool
  in generate generator seed

--判定
decision : List String -> Bool
decision list = ["ズン","ズン","ズン","ズン","ドコ"] == (drop ((List.length list)-5) list)


zundokoList (seed,list) =
  if decision list then
      (seed , list ++ [log "" "キ！ヨ！シ！"])
  else
      let
          (zd , seed') = zunDoko seed
      in
          zundokoList (seed', list ++ [log "" zd])


main = show <|  zundokoList (initialSeed 0 , [])

```

#StartApp（Elmアーキテクチャ）版
startappを使って、htmlで表示するバージョン。
Effectを使って、ループを再現している。
書いてみて思ったけど、SignalをループさせるにはEffect使うの一択だな。自力でやるのはぐちゃぐちゃになる。

あと上のdebug.log版のを改良して、初期Seed値をTask型の関数で外部から取ってくるアクションを定義した。
なので、リロードするたび結果が変わる。

```hs

module Main where

import Random exposing (bool,generate,initialSeed,Seed)
import TaskTutorial exposing(getCurrentTime)
import Signal exposing(..)
import Task exposing (Task)
import Debug exposing (log)

import Effects exposing (..)
import StartApp exposing (start)
import Html exposing (text,div,Html)
import List exposing (drop,take,append)

--App内で使うデータの定義。ランダムに使うSeed値と、画面に表示するズンドコの文字列、がある。
type alias Model =
            (Seed,List String)

--App内で起こるアクションの定義。今回のズンドコAppの場合は、Seed値を現在時間から取ってくる（きた）Settingアクション、ループのステップのアクション、すべてが終わって終了Endのアクション、を定義した。
type Action = Setting Int
            | Step
            | End

init : (Model, Effects Action)
init =
  ((initialSeed 0,[]),Effects.task initTask)

--Seed値に現在時間を使うために取ってくる。
initTask : Task x Action
initTask =
  getCurrentTime
   |> Task.map (\x -> Setting (round x))

--Seedを入れるとランダムにズンかドコを返す
zunDoko : Seed -> (String,Seed)
zunDoko seed =
             let generator = Random.map (\x -> if x then "ドコ" else "ズン") bool
              in generate generator seed

--リストの後ろ５つの文字列を見て判定する
decision : List String -> Bool
decision list = ["ズン","ズン","ズン","ズン","ドコ"] == (drop ((List.length list)-5) list)


toEffect action = action |> Task.succeed |> Effects.task


--返すEffectsでループさせているのがわかるだろうか。
update : Action -> Model -> (Model , Effects Action)
update action (seed,list) =
  case action of
    --Seed設定action
    Setting num ->((initialSeed num, list), toEffect Step )
    
　　--ループ時に実行される
    Step -> let
                    (zd , seed') = zunDoko seed
                in
                   --判定
                   if decision list then
                      (( seed' , list ++ ["キ！ヨ！シ!"] ), toEffect End )
                   else
                      (( seed' , list ++ [zd] ), toEffect Step )
    
   --終了
    End -> ((seed,list),Effects.none)


view : Address Action -> Model -> Html
view address (seed,list) =
    div [] [text <| toString list]

app =
  start
    { init = init
    , update = update
    , view = view
    , inputs = []
    }


main =
  app.html


port tasks : Signal (Task.Task Never ())
port tasks =
  app.tasks

```