The best way to generate a list of random numbers?

There is an example in the official Elm guide, how to generate a single random number through a Command, e.g. event onClick.
How about, if I want length 100 list of randoms generated either per one click instead of 100 times onClick or without any click. It seems to be incredibly difficult to do in Elm, if not impossible. Elm random produces in the first stage just a random generator - not a random number like Python, JS,…
Using JavaScript function Math.random(), the same is astonishing simple like this:

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript Math</h1>
<h2>The Math.random() Method</h2>
<p>Math.random()*100 returns a random number between 0 and 100:</p>

<p id="demo"></p>

<script>
acc = ""

for (let i = 0; i < 50; i++) {
  let x = Math.floor((Math.random() * 100) + 1);
  acc += x + " "
}

document.getElementById("demo").innerHTML = acc;

</script>

</body>
</html>

Output:

JavaScript Math

The Math.random() Method

Math.random()*100 returns a random number between 0 and 100:

39 17 97 24 89 3 43 90 57 57 55 34 12 89 62 26 20 88 14 91 82 66 8 29 39 60 77 89 33 52 75 8 50 9 47 6 94 25 93 65 30 1 93 57 90 10 44 10 10 33

Maybe the practical method is using ports, sending the task from elm to and receiving the list returned by JavaScript.

Is this what you are looking for? Random - random 1.0.0

1 Like

Probably yes, howcome has it the same package name and the version number as this random 1.0.0? I found that using Try Elm! package search.
Different quite extensive contents as compared to other one - and interesting.
Thanks for helping!

This talk gives a very nice introduction to random numbers in Elm. Well worth a watch!

1 Like

Those are part of the same package — one is the README page (your link) and one is the detailed API documentation, which you can find on the right-hand sidebar under Modules > Random.

The talk that @dillonkearns posted above is extremely helpful and taught me how to really use the random module.

To your original question, in Elm you combine and modify generators using pair, list, and map. So even though the primitive generators only yield one value at a time, when you combine them you can get a generator with whatever sort of values and however many you want, all at once.

1 Like

Randomness is a bit of a tricky thing in Elm.

I tend to write myself a little helper function that makes my life easier:

applyGenerator : 
  { model | seed : Seed} 
  -> Generator { model | seed : Seed} 
  -> { model | seed : Seed}
applyGenerator model gen =
  let
    (newModel,seed) = Random.step gen model.seed
  in
  {newModel|seed = seed}

({model | seed : Seed} means i have a record with a field seed: Seed. That’s usually my Model.)

I then use Random.map and Random.andThen to slowly build a Generator Model and use applyGenerator at the end.

@Lucas_Payr I would recommend against this, especially for beginners I think this could be confusing. My advice to newcomers to random generators in Elm would be that if you are using Random.step or Seed anywhere in your code then you are probably going down the wrong path as those are low-level helpers that are only useful in rare and more advanced use cases.

99% of the time, random values in Elm are generated by building up a single value of type Random.Generator MyTargetGeneratedType and then passing that to Random.generate.

Manually managing a Seed value is not needed because the Elm runtime does that for you behind the scenes. The mental model is that you cannot get random values by calling an Elm function alone because all Elm code is pure functions (a given input always yields the exact same output, and random does not fit that description). Anything that is not pure in that way goes outside of just calling an Elm function by doing impure things through The Elm Architecture (init, update, Msg, Cmd).

So there is no need to use Random.Seed values anywhere in your code, but rather you can let Elm do that for you by using Random.generate to get a Cmd, pass that to init or update, and then let Elm manage all the details of how to get you a random value following the description you defined in your Random.Generator. Hope that is helpful, just wanted to make sure newcomers to randomness in Elm don’t go down the path of using some of these low-level helpers.

I have skipped first all writings before elm 0.19.0 but now random package seems to be similar as before and thus still valid. In that respect the six years old article by Charlie Koster is still worth reading. After reading it I shall try to modify the example of elm guide to use different generators. I guess it helps me to understand the function of more advanced generators, while seeing the results in practice.

It’s not clear for me, why to use step and set the seed ahead. Is it the reason that you get pure functions with the given seeds while the results are then always same? Does it help testing?
Shall the fixed seed be hidden in the production version?
Is it still possible to optimize and to minifye the code compiled in both cases if pure or impure?

Here are two cases where I’ve used a seed instead of the Random.generate function (which returns a Cmd):

  1. A game. While playing it, I hit a weird bug. I saved the starting seed, and all inputs. Using those I was able to consistently reproduce the bug so I could fix it.
  2. A weird case. I ended up needing randomness in a place where it would be very, very inconvenient if I had to support being able to use a Cmd. I already had access to the current time and used that as the starting seed. Then I could add the randomness in a synchronous way that didn’t require a big refactor.
1 Like

Thanks to all about good advices!
I can now generate random float numbers at least if nothing else, see in Ellie.

All of the Elm code that you write in Elm is pure. You can optimize and minify it, and you can test it with the same results on every test run.

The code in init and update lets you do impure things (mutate the Model, and perform Cmds). However, all of the code you write to build up your Cmds and respond to Msgs they produce are pure. So that’s the breakdown of an Elm app. The runtime does all of the impure things for you, but your code is built from only pure functions. That’s the beauty of it. If an app was only pure then it wouldn’t do anything in the realworld or put anything on the screen so it wouldn’t be interesting. What makes The Elm Architecture interesting is that there is a very clear separation between the pure parts (all of the Elm code you write), and impure (things the runtime does for you). That means that testing your Elm app will give you reliable results out of the box. This is one of the things I love about Elm, you don’t need to use any special architecture techniques to make your code testable, the design of the language gives you that for free.

All random generation uses seeds. It’s only a question of whether you let it choose a seed for you, or if you want to pass one in. The suggestions on this thread are some advanced uses to have a random generator to generate a random seed. Again, passing in a Random.Seed value manually is a more advanced use and I would recommend that you ignore this for your use case and when you are starting out with random generation in Elm. You won’t need it until you get more comfortable with the basics. For the purpose of generating a random list of numbers you won’t need to manage a Random.Seed manually.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.