Как добавить вторую копию к этому примеру?

Я новичок в Elm и смотрю на следующий пример (обратите внимание, что это под новой архитектурой 0.17, где Action теперь Command): http://elm-lang.org/examples/random

Существует следующий вызов, чтобы добавить вторую фигуру к примеру, так что одним нажатием кнопки катит новое значение для каждого штампа. Моя идея состоит в том, чтобы изменить модель на наличие двух отдельных значений, по одному для каждой матрицы, ала

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) → Генератор a → Cmd msg

Создайте команду, которая будет генерировать случайные значения.

Это даже правильный подход к обработке двух кубиков, или есть лучший способ? Я влю, ну, пожалуйста, будь милым :)

Ответы

Ответ 1

Random.int - это примитивный генератор, который дает вам один случайный int. Вам нужен генератор, который дает вам ровно два случайных числа.

Генераторы случайных чисел могут быть созданы из более примитивных генераторов для создания более сложных генераторов. К счастью, у Elm есть такая функция Random.pair которая позволяет вам указать, какие два генератора вы хотите для каждой части кортежа.

Пусть вытащите генератор штампа в его собственную функцию, чтобы избежать повторения:

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

Теперь мы можем построить еще один генератор, который дает нам случайное значение пары die:

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

Поскольку мы имеем дело с кортежем ints, давайте обновим ваше Msg определение NewFace Int Int до NewFaces (Int, Int). Это позволит вашему Roll механизму быть красивым и чистым:

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

Если вы хотите попробовать выйти за рамки этого, подумайте о том, что потребуется, чтобы можно было прокатить любое количество штампов. Возьмите эту идею построения сложных генераторов из более примитивных генераторов и используйте документацию для модуля Random мы руководство.

Ответ 2

Один из подходов - использовать batch например https://gist.github.com/davidchase/40c27042bccfb00d786af0360b5bc3ea.

Другим является использование Random.pair или Random.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)
  }

-- http://stackoverflow.com/questions/23199398/how-do-i-get-a-list-item-by-index-in-elm#comment56252508_23201661
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

Ответ 3

Помимо изменений, описанных в принятом ответе @ChadGilbert, мне также пришлось менять NewFaces обновления NewFaces (используя elm 0.18.0).

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