This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

Elmでランダムな結果を出す処理をどうやるか

Last updated at Posted at 2016-12-07

結果をランダムに返す処理をElmで書く

  • ボタン押したらサイコロを振る、とか
    • jsならMath.random()だけ済んでるところで、違いを実感できる側面
  • 型定義はどのように書くのか
  • Elmの関数は純粋関数
    • 同じ引数渡せば戻り値は毎回同じ
  • 「呼び出すたびに戻り値が毎回違う」関数は言語設計上禁止されてる
    • であれば、どうやって「サイコロ」を実装できるのか?

ElmのRandomモジュール

「ランダムな○○」をElmで実現させるために必ず使うもの。コアモジュールの1つ

  • 乱数生成器を作るために使う関数がRandomモジュールにまとめられてる
    • 乱数生成器は、generatorと呼ばれてるらしい
  • ランダムに生成させる値としては、数値、文字列、Record、とか色々
  • ドキュメントに少し玄人向けのNoteがついてる
    • HaskellのSystem.Randomの移植

ランダムな結果をthe Elm Architectureで使えるようにするための流れ

今ひとつな説明だがこんな感じ
- 関数の式の評価はElmランタイムだが、Cmd a型が戻り値である関数式の評価をするときはElmランタイム側で何をしてるのかが、不明

  • コマンド(Cmd a型データ)を返す関数を作るor用意する
    • 評価されるとCmd a型データを取り出せる関数式
    • ランダムな結果を生成する方法を記述したもの、という位置付け
  • 式の評価は通常通りElmランタイムの仕事
  • 式の評価の結果、Cmd a型データを取り出した時、generatorがランライム上で実行される
  • 実行結果をメッセージにラップして、update関数へフィードバックする
    • このフィードバックされたメッセージ中に実行結果(1〜3のうちの1つの数字、とか)がラップされてる

Cmd a型データを使うときに頭使うとこ、難しいなと感じるとこ

  • Cmd a型を返す関数がどれかを把握すること
  • Cmd a型を返す関数が求める引数にはややこしいものが多い
generate : (a -> msg) -> Generator a -> Cmd msg
  • このRandom.generateだけが、Randomモジュールの中では、Cmd a型を返す
  • 2つの引数をとる
    • 1つは、受け取った引数をmsg型に返し、このmsg型のデータは、戻り値にラップされる
    • 2つめは、Generator a型という、Randomモジュールで定義されたデータ型
  • Generator aの型変数aが、生成されるデータの型を指定する
    • 「1から3までの数字のどれか」、であれば、Generator Int型と指定する
  • そしてGenerator a型のデータはどうやって作るかというと、Generator aを戻り値とする関数がRandomモジュールには複数存在する
    • ランダムにInt生成させたいなら、Random.init
      • Random.init 1 3と範囲を指定
    • True, False なら、Random.bool
    • StringRecordとかリストになると、Generator aを加工する関数を使う
      • union typeとRandom.initとか組み合わせるやつとか

実装例を読む

例はElm in Actionから、

randomPhotoPicker : Random.Generator Int
randomPhotoPicker =
    Random.int 0 (Array.length photoArray - 1)
 
 
type Msg
    | SelectByIndex Int
    | SurpriseMe
 
 
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        SelectByIndex index ->
            ( { model | selectedUrl = getPhotoUrl index }, Cmd.none )
 
        SurpriseMe ->
            ( model, Random.generate SelectByIndex randomPhotoPicker )
 
  • update関数
    • ( Model, Cmd Msg )返す
  • update関数のcase...ofSurpriseMeブランチで、Cmd Msg型データを返してる
  • Msg型はunion typesとして定義
  • Random.generate SelectByIndex randomPhotoPickerがメイン部分
    • randomPhotoPickerは、Generator Int
    • SelectByIndexは、Msg型定義を変形した、Int -> Msg
  • update関数はtype constructor SurpriseMeというMsg型のデータを受け取ると、Cmd (SelectByIndex Int)をElmランタイムに投げる。
  • type constructorSelectByIndex IntのメッセージをElmランタイムからupdate関数は受け取る

参考ページ

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up