如何向这个榆树效果示例添加第二个骰子?

How do I add a second die to this elm effects example?

我是 Elm 的新手,一直在看下面的例子(注意这是在较新的 0.17 架构下,Action 现在是 Command): http://elm-lang.org/examples/random

接下来的挑战是向示例中添加第二个骰子,这样单击按钮就会为每个骰子滚动一个新值。我的想法是更改模型以保存两个单独的值,每个值一个,ala

type alias Model =
       { dieFace1 : Int
       , dieFace2 : Int
       }

在我到达更新块之前,这一切正常。我不确定如何更新随机数生成器以创建两个值。这个功能让我有点困惑。

type Msg
  = Roll
  | NewFace Int Int


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Roll ->
      **(model, Random.generate NewFace (Random.int 1 6))** <-- not sure what to do here

    NewFace newFace1 newFace2 ->
      (Model newFace1 newFace2, Cmd.none)

Random.generate 函数的文档有点简单 -

generate : (a -> msg) -> Generator a -> Cmd msg

Create a command that will generate random values.

这是处理两个骰子的正确方法,还是有更好的方法?我是榆木小白,请大家多多关照:)

Random.int 是一个原始生成器,它给你一个随机整数。你需要一个能给你恰好两个随机整数的生成器。

可以从更原始的生成器构建随机数生成器来创建更复杂的生成器。幸运的是,Elm 有这样一个函数,Random.pair 可以让你为元组的每个部分指定你想要的两个生成器。

让我们把模具生成器拉到它自己的函数中,以避免重复我们自己:

dieGenerator : Random.Generator Int
dieGenerator =
  Random.int 1 6

现在我们可以构建另一个生成器,为我们提供一对骰子的随机值:

diePairGenerator : Random.Generator (Int, Int)
diePairGenerator =
  Random.pair dieGenerator dieGenerator

由于我们正在处理整数元组,让我们将 NewFace Int IntMsg 定义更新为 NewFaces (Int, Int)。这将使您的 Roll 处理程序变得干净整洁:

Roll ->
  (model, Random.generate NewFaces diePairGenerator)

如果您想尝试超越这一点,请考虑允许滚动任意数量的骰子需要什么。采取从更原始的生成器构建复杂生成器的想法,并使用 Random 模块的文档作为指南。

一种方法是使用 batch 就像这里 https://gist.github.com/davidchase/40c27042bccfb00d786af0360b5bc3ea.

另一种方法是使用 Random.pairRandom.list 如果您需要超过 2 个:

import Html exposing (..)
import Html.App as Html
import Html.Events exposing (..)
import Html.Attributes exposing (..)
import Random


main : Program Never
main =
  Html.program
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

-- MODEL

type alias Model =
  { dieFaces : (List Int)
  }

-- 
get : Int -> List a -> Maybe a
get n xs = List.head (List.drop n xs)

-- http://rundis.github.io/blog/2016/elm_maybe.html
getOrOne : Int -> List Int -> Int
getOrOne n xs = Maybe.withDefault 1 (get n xs)

init : (Model, Cmd Msg)
init =
  (Model [1, 1], Cmd.none)

-- UPDATE

type Msg
  = Roll
  | NewFace (List Int)

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Roll ->
      (model, Random.generate NewFace (Random.list 2 (Random.int 1 6)))

    NewFace newFace ->
      (Model newFace, Cmd.none)

-- SUBSCRIPTIONS

subscriptions : Model -> Sub Msg
subscriptions model =
  Sub.none

-- VIEW

view : Model -> Html Msg
view model =
  div []
    [ img [ src ("/img/Alea_" ++ toString (getOrOne 0 model.dieFaces) ++ ".png")] []
    , img [ src ("/img/Alea_" ++ toString (getOrOne 1 model.dieFaces) ++ ".png")] []
    , button [ onClick Roll ] [ text "Roll" ]
    ]

还有一个https://github.com/jcollard/random-examples/blob/master/src/Dice.elm

除了@ChadGilbert 接受的答案中描述的更改外,我还必须更改 NewFaces 更新大小写(使用 elm 0.18.0)。

NewFaces newFaces ->
  let
    (newFace1, newFace2) = newFaces
  in
    (Model newFace1 newFace2, Cmd.none)