产生唯一的随机数

时间:2018-12-25 13:13:36

标签: elm

我有一个应用程序,我想在读取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次的列表/数组。

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)

我想知道我的想法是否与榆树社区的期望相符。