ズンドコキヨシというタグを見かけたので、Elmで書いてみた、というだけの記事。
ランダムに「ズン」または「ドコ」を出力して、「ズン」4回「ドコ」と続いたら、「キ!ヨ!シ!」と出力して終わる。
#再帰関数、Debug.log版
再帰関数を使ってループさせる。
Debug.logをはさんで、コンソールに出力している。
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型の関数で外部から取ってくるアクションを定義した。
なので、リロードするたび結果が変わる。
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
--リストの後ろ5つの文字列を見て判定する
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