随机
到目前为止,我们仅看到用于发出 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
,更具体地说,它会生成一个介于 1
和 6
(包括 1
和 6
)之间的整数。同样,usuallyTrue
生成器表示它会生成一个 Bool
,更具体地说,它在 80% 的情况下为 true。
关键是我们实际上还没有生成值。我们只是描述了如何生成它们。然后使用 Random.generate
将其转换为命令
generate : (a -> msg) -> Generator a -> Cmd msg
执行命令时,Generator
会生成一些值,然后将其转换为 update
函数的消息。所以,在我们的示例中,Generator
生成了介于 1 和 6 之间的值,然后变成了 NewFace 1
或 NewFace 4
之类的消息。这是我们需要知道的关于获取随机骰子点数的所有信息,但生成器还可以完成更多操作!
组合生成器
一旦生成出一些简单的生成器,如 probability
和 usuallyTrue
,我们就可以开始使用诸如 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
创建一个带权重的骰子。- 添加一个第二个骰子,让它们同时滚动。
- 让骰子在一个最终值上稳定下来之前随机地翻滚几次。