随机

到目前为止,我们仅看到用于发出 HTTP 请求的命令,我们还可以命令其他内容,如生成随机值!因此,我们将创建一个掷骰子的应用程序,生成 1 和 6 之间的随机数。

单击蓝色的“编辑”按钮以查看此示例中的操作。生成几个随机数,然后查看代码以尝试找出其工作方式。现在单击蓝色按钮!

import Browser
import Html exposing (..)
import Html.Events exposing (..)
import Random



-- MAIN


main =
  Browser.element
    { init = init
    , update = update
    , subscriptions = subscriptions
    , view = view
    }



-- MODEL


type alias Model =
  { dieFace : Int
  }


init : () -> (Model, Cmd Msg)
init _ =
  ( Model 1
  , Cmd.none
  )



-- UPDATE


type Msg
  = Roll
  | NewFace Int


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Roll ->
      ( model
      , Random.generate NewFace (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 []
    [ h1 [] [ text (String.fromInt model.dieFace) ]
    , button [ onClick Roll ] [ text "Roll" ]
    ]

这里的更新是 update 函数中发出的命令

Random.generate NewFace (Random.int 1 6)

生成随机值与 JavaScript、Python、Java 等语言中生成随机值的工作方式略有不同。下面让我们看看它在 Elm 中的工作方式!

随机生成器

为此,我们使用 elm/random 包。特别是,Random 模块。

核心思想是我们有随机 Generator,它描述了如何生成随机值。例如:

import Random

probability : Random.Generator Float
probability =
  Random.float 0 1

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

usuallyTrue : Random.Generator Bool
usuallyTrue =
  Random.weighted (80, True) [ (20, False) ]

所以这里我们有三个随机生成器。roll 生成器表示它会生成一个 Int,更具体地说,它会生成一个介于 16(包括 16)之间的整数。同样,usuallyTrue 生成器表示它会生成一个 Bool,更具体地说,它在 80% 的情况下为 true。

关键是我们实际上还没有生成值。我们只是描述了如何生成它们。然后使用 Random.generate 将其转换为命令

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

执行命令时,Generator 会生成一些值,然后将其转换为 update 函数的消息。所以,在我们的示例中,Generator 生成了介于 1 和 6 之间的值,然后变成了 NewFace 1NewFace 4 之类的消息。这是我们需要知道的关于获取随机骰子点数的所有信息,但生成器还可以完成更多操作!

组合生成器

一旦生成出一些简单的生成器,如 probabilityusuallyTrue,我们就可以开始使用诸如 map3 之类的函数将它们组合在一起。假设我们要制作一个简单的老虎机。我们可以创建一个这样的生成器

import Random

type Symbol = Cherry | Seven | Bar | Grapes

symbol : Random.Generator Symbol
symbol =
  Random.uniform Cherry [ Seven, Bar, Grapes ]

type alias Spin =
  { one : Symbol
  , two : Symbol
  , three : Symbol
  }

spin : Random.Generator Spin
spin =
  Random.map3 Spin symbol symbol symbol

我们首先创建 Symbol 来描述老虎机上可能出现的图片。然后我们创建一个随机生成器,以相等的概率生成每个符号。

然后我们使用 map3 将它们组合成一个新的 spin 生成器。它表示生成三个符号,然后将它们聚合到一个 Spin 中。

这里的重要一点是,我们能够从小构建模块开始创建一个描述了非常复杂行为的 Generator。然后在我们的应用程序中,我们只需像调用 Random.generate NewSpin spin 这样来获取下一个随机值即可。

练习:这里有一些想法,可以将本页中的示例代码变得更有趣!

  • 不要显示数字,而显示骰子面作为图像。
  • 不要显示骰子面的图像,而是使用 elm/svg 自己绘制它。
  • 使用 Random.weighted 创建一个带权重的骰子。
  • 添加一个第二个骰子,让它们同时滚动。
  • 让骰子在一个最终值上稳定下来之前随机地翻滚几次。

个符合"" 的结果

    没有符合"" 的结果