我有一个应用程序,我想在读取json后三遍在init上生成5个唯一数字的列表。所以基本上我想得到类似[31,59,62,72,2,16,2,38,94,15,55,46,83,2,10]的内容。我面临的挑战是我对函数式编程和elm还是陌生的,我有点迷茫。所以我知道Random.generate需要一个味精和一个生成器并返回一个cmd消息,它主要用于更新功能,但这不是我需要的,因为它是一个辅助功能,不需要与客户端进行通信。我认为它可以在init中使用,但我不知道如何使用。同样,我的函数是递归的,我不知道如何使用Random。递归生成来应用此逻辑。
我了解我的代码无法正常工作,并且已经尝试过,因为Random.int不会生成随机数,而是会生成一种类型的随机数,但我仍然不知道如何将其应用于我想要的内容。
recursion : Int -> List a -> List number
recursion a b =
if List.length b > 5
then b
else
let
rand = Random.int 0 a
in
if(List.member rand b)
then recursion a b
else
recursion a (rand :: b)
可以通过以下方式调用:
recursion 50 []
我想生成5次唯一随机3次的列表/数组。
答案 0 :(得分:3)
很好的问题。这里有两个部分: -生成随机数,以及 -全部连接
对于前者,您将需要使用Random库,稍加检查便会发现类似
的内容get15Randoms = Random.generate OnRandomNumbers <| Random.list 5 (int 0 100)
此类型为Cmd Msg
-这是一个异步操作,将在消息上返回。
将其连接起来将经历一系列阶段。您指的是在“ init”中执行此操作,但这不是Elm在这里为您工作的方式。在init函数中,您可以启动json请求。然后您需要类似
的东西init = ( initModel
, Http.get {url =..., expect = Http.expectJson OnJson yourDecoder}
)
update msg model =
case msg of
OnJson (Ok data) ->
-- attach json
( {model | data = data }, get15Randoms )
OnRandomNumbers ints ->
( { model | ints = ints }, Cmd.none )
换句话说,一旦json回来,您可以附加它,并使用该更新的迭代来启动您的随机数请求,然后在后续迭代中捕获结果
答案 1 :(得分:3)
随机数生成是一个副作用,因为根据定义它是不可预测的,这意味着其输出并不完全由其输入确定。在Elm中,所有副作用都会通过更新功能,因为如果在任何地方都允许出现副作用,则无法保证代码的任何部分都是纯净的和可预测的。事情可能会开始随机变化,而很难找出原因,因为随机输入可以在任何地方发生。
也就是说,init
是允许出现副作用的一个地方,因为还没有任何状态。但是由于大多数副作用都不是立即发生的,并且您很可能希望提供一些UI来指示您的应用正在加载,因此我认为API并没有复杂到允许如此罕见的用例。特别是由于有两种解决方法,您可以使用:
解决方法1-空的表示形式
由于您使用的是包含随机数的列表,因此您可能只是使用一个空列表来表示尚未收到数字。否则,请使用Maybe
或自定义类型。这可能有点麻烦,因为每次使用时都必须处理空的情况,但是根据您的使用情况,它可能是可以接受的。
解决方法2-标志
Elm允许在初始化时从外部将数据发送到您的程序,并将其传递给您的init
函数。该机制称为flags。您可以使用它在JavaScript中生成数字,然后再将其作为参数发送。
在您的index.html
中,您应该输入:
var app = Elm.Main.init({
node: document.getElementById('elm'),
flags: Array.from({length: 15}, () => Math.floor(Math.random() * 50))
});
在init
中,您接受数字作为普通参数:
init : List number -> Model
init numbers =
{ myNumbers = numbes
, ...
}
答案 2 :(得分:1)
我想以@ Simon-h的回答为动力,最终做出回应。我有一个Msg类型的RndGen Int,由于update是一个函数,因此我决定在update函数的帮助下递归调用RndGen,并在得到所需的随机数时将其标记为关闭。
update msg model =
case msg of
NoOp ->
(model, get15Randoms)
RndGen rndGen ->
if List.length (model.questions) < 15
then
if List.member rndGen model.questions
then
(model, get15Randoms)
else
({model | questions = rndGen :: model.questions }, get15Randoms)
else
(model, Cmd.none)
和
get15Randoms =
Random.generate RndGen (Random.int 0 100)
在初始化
init questions =
(Model (getQuestions questions) 1 True [] False "", get15Randoms)
我想知道我的想法是否与榆树社区的期望相符。