What is the minimum code required to produce random numbers in Elm? - random

I just want to see a random number. So here's an example straight out of the docs for the Random library. I expect Random.generate to accept a generator and a seed and return a tuple containing a random value and a new seed, as in:
generate : Generator a -> Seed -> (a, Seed)
-- Main.elm
import Random
seed0 = Random.initialSeed 31415
randomNumber = Random.generate (Random.int 0 10) seed0
main =
-- print result of randomNumber here
The compiler errors show two type mismatches:
-- TYPE MISMATCH ---------------------------------------------------- -----------
The 2nd argument to function `generate` is causing a mismatch.
5| Random.generate (Random.int 0 10) seed0
^^^^^
Function `generate` is expecting the 2nd argument to be:
Random.Generator a
But it is:
Random.Seed
The 1st argument to function `generate` is causing a mismatch.
5| Random.generate (Random.int 0 10) seed0
^^^^^^^^^^^^^^^
Function `generate` is expecting the 1st argument to be:
a -> b
But it is:
Random.Generator Int
What am I missing here?

The version of the docs you refer to is Core 1.0.0, which is old. Current version of Core is 4.0.5. (docs for Random here)
The function with the signature you are looking for is now named step:
step : Generator a -> Seed -> (a, Seed)
So your refactored code would look something like this:
import Html exposing (text)
import Random
seed0 = Random.initialSeed 31415
(randomNumber, nextSeed) = Random.step (Random.int 0 10) seed0
main =
text <| toString randomNumber

Here is the shortest example I can think of.
Because it is giving a constant seed, it will return same boolean.
If you need random number get produced at runtime, then you
have to use Random.generate which produces Cmd
so that elm runtime can get the randomness.
In this case, some form of Platform.Program
is needed because it is the only way to run Cmd.
import Html exposing (text)
import Random exposing (..)
main =
text <| toString <| Tuple.first <| step bool (initialSeed 1)

Elm 2022 (v0.19) answer:
Here's an absolute minimal example for generating a number between 0 and 1000 in Elm 0.19.1, and a runnable Ellie, which depends on elm/random. You wouldn't usually have all the () littered throughout, and instead you'd have Msg and Model, but in the interest of minimizing code:
module Main exposing (main)
import Browser
import Html
import Random
view : () -> Html.Html ()
view model =
let
-- this generates the rng number
generator =
Random.int 0 1000
-- used to seed the generator
seed =
Random.initialSeed 12345
-- Random.step returns the generated value, and a new seed.
-- Usually you store the newSeed on your model so you don't always generate the same value
( value, newSeed ) =
Random.step
generator
seed
in
Html.text <| String.fromInt value
main : Program () () ()
main =
Browser.sandbox
{ init = ()
, view = view
, update = \msg model -> model
}
Other best practices include storing some global seed on the model:
type alias Model = { globalSeed : Random.Seed }
and then using it and updating the one on the model after:
update : Msg -> Model -> (Model, Cmd.none)
update msg model =
case msg of
GenerateValue ->
let
(newValue, newSeed) =
Random.step (Random.int 0 1000) model.globalSeed
_ =
Debug.log "generated a new value" newValue
in
( {model | globalSeed = newSeed}, Cmd.none)

Related

Random number generation problem with meta table

Please look at the next code, Lua.
randomNumber = {
new = function(self,o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end,
math.randomseed(os.time()),
getNum = math.random()
}
for i = 1, 10 do
x = randomNumber:new()
print(x.getNum)
end
The output results are as follows.
0.13782639400248
0.13782639400248
0.13782639400248
0.13782639400248
0.13782639400248
0.13782639400248
0.13782639400248
0.13782639400248
0.13782639400248
0.13782639400248
I want to get 10 different numbers. Can someone help me? Thank you in advance.
Let's take a look at your table constructor
randomNumber = {
new = function(self,o) -- this assigns a function to randomNumber["new"]
o = o or {} -- that will return a new instance of your class
setmetatable(o, self)
self.__index = self
return o
end,
math.randomseed(os.time()), -- this assigns the first of two random seed components
-- returned by math.randomseed to randomNumber[1]
getNum = math.random() -- this assings a random number [0,1) to randomNumber["getNum"]
}
In the loop
for i = 1, 10 do
x = randomNumber:new()
print(x.getNum)
end
You create a new instance named x of randomNumber 10 times.
You then print x.getNum.
x.getNum is a nil value so Lua will check wether x has a metatable with a __index field. __index refers to randomNumber so Lua will print randomNumber.getNum which is the random number [0,1) which has not changed since we constructed randomNumber.
You need to call math.random every time you want a new random number.
If you want each instance of randomNumber to be constructed with a random number you need to assign o.rn = math.random() in your new function and either access it via x.rn later or add a function getNum to randomNumber.
getNum = function (self) return self.rn end`
so you can print(x:getNum())
I'm not sure if this is more than a exercise with metatables. But having a dedicated class that just holds a single number doesn't make too much sense to me. Just use a number value.
The main problem with your code is simply...
In a very fast Lua loop os.time() is not fast enough to set a good random seed.
You have to use something that is faster, like...
-- Lua 5.3 - 5.4
for i = 1, 10 do
math.randomseed(math.random(math.mininteger, math.maxinteger)) -- Set seed before print()
print('Seed: ' .. math.randomseed(math.random(math.mininteger, math.maxinteger)), '\nRandom: ' .. math.random(math.maxinteger)) -- Set seed in print()
math.randomseed(math.random(math.mininteger, math.maxinteger)) -- Set seed after print()
end
That puts out something like...
Seed: -634325252416746990
Random: 5554602367968798340
Seed: 574322306421972413
Random: 3317370212892010822
Seed: -5465512503977683870
Random: 6616070635043877067
Seed: -2566820481734265082
Random: 2581377472505137533
Seed: -8408106760854456996
Random: 708876515734960246
Seed: 5641371185711405705
Random: 4259990225803106481
Seed: -3172432877848732304
Random: 5472223279668970440
Seed: 5842301042132325387
Random: 6912957407189525897
Seed: 2126448976574029213
Random: 6156943198274398962
Seed: 4832369017575479065
Random: 6054703131408226582
Lua 5.1
-- Lua 5.1
math.randomseed(math.random(os.time()))
for i = 1, 10 do
math.randomseed(math.random(-99999999, 999999999)) -- Set seed before print()
print('Random: ' .. tostring(math.random(-999999999, 999999999)))
math.randomseed(math.random(-999999999, 999999999)) -- Set seed after print()
end

Generate random UUIDv4 with Elm

I'm trying to generate random UUID's v4 within a loop:
randomUuid =
-- TODO: find a way to generate random uuid for variableId
updatedVariables =
group.variables |> List.map (\variable -> { variable | id = randomUuid })
I read the doc of elm/random and elm/uuid but could not find how to generate an UUID without using a seed.
The only thing I could do is:
newUuid : Random.Seed -> ( String, Random.Seed )
newUuid seed =
seed
|> Random.step UUID.generator
|> Tuple.mapFirst UUID.toString
I see that elm/random as an independentSeed function but I cannot get it to generate a seed.
The node equivalent of what I'm trying to achieve with randomUuid is:
const { uuid } = require('uuidv4');
const randomUuid = uuid();
I feel like I might be missing some important concept in Elm here but cannot figure that one on my own. Any help or pointer would be greatly appreciated.
Generating random values is an effect and as such a pure language cannot just perform it.
However, there is a pure version of randomness, which is using random seeds. These have the property that every time you generate a value using the same seed, you get the same value - hence this is just a pure computation and is completely ok in a pure context.
Elm allows you to execute effects as Cmd, the thing you return from your init and update functions. So one option you have is to always return Random.generate GotANewUUID UUID.generator before you need it, then perform your computation when you handle the GotANewUUID msg.
The other option is to keep track of the random seed. You either start with a deterministic one with Random.initialSeed (probably not what you want with UUIDs, as they would be exactly the same on every run of your program), or in your init function you return Random.generate GotNewSeed Random.independentSeed. Then you store the seed in your model.
Every time you need to generate a new UUID, you use your newUuid function above, making sure to store the new seed.
Here's an example:
import Random
import UUID
type alias Thing =
{ id : String
-- , some other stuff
}
type alias Model =
{ seed : Random.Seed
, stuff : List Thing
}
type Msg
= GotNewSeed Random.Seed
| AddAThing Thing
| AddABunchOfThings (List Thing)
init : () -> (Model, Cmd Msg)
init flags =
({ seed = Random.initialSeed 567876567
-- Let's start with a deterministic seed
-- so you don't need to deal with Maybe Seed later
, stuff = []
}, Random.generate GotNewSeed Random.independentSeed
)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
GotNewSeed seed ->
({model | seed = seed}, Cmd.none)
AddAThing thing ->
let
(newId, newSeed) =
newUuid model.seed
in
({ model | stuff = { thing | id = newId } :: model.stuff
, seed = newSeed }
, Cmd.none
)
AddABunchOfThings things ->
let
(newStuff, newSeed) =
List.foldl (\thing (stuff, seed) ->
newUuid seed
|> Tuple.mapFirst (\id ->
{ thing | id = id } :: stuff
)
) (model.stuff, model.seed) things
in
({model | stuff = newStuff, seed = newSeed}, Cmd.none)

How can I factor multiples function that gets their result process by another function?

I would like to factorize this code :
(* This function is applied to the result of functions below *)
let manage_result r s =
match r with
| Error ( `Msg e ) -> Tsdl.Sdl.log s e;exit 1
| Ok a -> a
(* Examples of function I want to factorize, let's call them f_functions, f for factorize *)
let init () =
let flag = Tsdl.Sdl.Init.everything in
let result = Tsdl.Sdl.init flag in
manage_result result "Init error : %s"
let create_window title w h =
let flag = Tsdl.Sdl.Window.windowed in
let result = Tsdl.Sdl.create_window title ~w:w ~h:h flag in
manage_result result "Create window error : %s"
let get_window_surface window =
let result = Tsdl.Sdl.get_window_surface window in
manage_result result "Get window surface error : %s"
As you can see, the two last lines of all of these f_functions are very similar. I would like to make a function that takes as argument a function ( for example, if I wanted to factorize init, the function passed as a parameter would be Tsdl.Sdl.init) and return a function that return the return value of function passed as an argument AND processed through manage_result.
The difficulty is that I don't know how many argument can the f_functions take.
Any other recommendations is appreciated!
Thank you.
A potential solution might be to use the pipe operator rather than naming the intermediary result
let on_error s r = manage_result r s
let create_window title w h =
let flag = Tsdl.Sdl.Window.windowed in
Tsdl.Sdl.create_window title ~w:w ~h:h flag
|> on_error "Create window error : %s"
Going one step further, we could define a custom operator for the error handling
let ( <!> ) = manage_result
which may make your definition lightweight enough
let create_window title w h =
let flag = Tsdl.Sdl.Window.windowed in
Tsdl.Sdl.create_window title ~w:w ~h:h flag
<!> "Create window error : %s"

Change widget model from parent in Elm

I am using the "compose" pattern in Elm.
In Main.elm, I am generating an initial seed for Random using the following:
type alias Model =
{ ...
, seed : Seed
}
initialModel : Model
initialModel =
{ ...
, seed = initialSeed 0
}
init : ( Model, Cmd Msg )
init =
( initialModel, generate InitializeSeed (int minInt maxInt) )
type Msg
= ...
| InitializeSeed Int
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
...
InitializeSeed value ->
( { model | seed = Random.initialSeed value }, Cmd.none )
which seems to work well for initializing the random number generator seed to a random starting value.
I have an "independent" widget that is used in the main application. I would like to pass the seed down to that widget on receipt of the InitializeSeed message and then retrieve the value as it changes in the child widget (using Random.step) so that I can then update other widgets' seeds as they need the generator.
How can I generate a message for the child widget from the update function in Main so that I can pass the seed down to the child? How can the child return the updated seed back to the parent?
UPDATE:
I figured out how to pass the seed down to the child widget, although I am not certain that this is best way.
The child code looks like this:
type alias Model =
{ ...
, seed : Seed
}
replaceSeed : Model -> Seed -> Model
replaceSeed model seed =
{ model | seed = seed }
and in the parent, I modified the update function like this:
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
...
InitializeSeed value ->
let
seed =
Random.initialSeed value
child_ =
Child.replaceSeed model.child seed
in
( { model
| seed = seed
, child = child_
}
, Cmd.none
)
I am still looking for a way to have the child return the updated seed.
While the top level update function in any Elm program must be
update : Msg -> Model -> (Model, Cmd Msg)
there are no limitations on the shape of any of its descendents. So nothing prevents you defining for your child
update : Seed -> Msg -> Model -> (Model, Cmd Msg, Seed)
or, if the child never returns any commands
update : Seed -> Msg -> Model -> (Model, Seed)
Maybe you have several things to pass down, including for example a parent message. Then you could go as far as
type alias Config msg =
{ seed : Seed
, someParentMessage : String -> msg
}
update : Config msg -> Msg -> Model -> (Model, Maybe (Cmd msg), Seed)
You need to wire these all up appropriately in Main of course, but the compiler will help with that.

What is the correct way of initializing an elm application

The documentation for Elm's Random module states:
A good way to get an unexpected seed is to use the current time.
http://package.elm-lang.org/packages/elm-lang/core/1.1.0/Random
I don't see however a good example of how to perform such initialization logic in FRP application. What signal should I react to? How to do this with a minimum of code and maximum of clarity.
There are different ways to do this. Each has it's own benefits. I'll give you the three that I know with a similar example for each.
1) Add a time ticker input
One thing you could do is add time to the inputs of your program. An example of a tiny program using the current time every second for a random number:
import Time
import Time (Time, second)
import Text (asText)
import Mouse
import Signal
import Signal (Signal, (<~), (~))
import Random
import Random (Seed)
import Graphics.Element (Element)
randomInt : Seed -> Int
randomInt seed = seed |> (Random.generate <| Random.int 1 10) |> fst
otherInput : Signal (Int,Int)
otherInput = Mouse.position
timeSeed : Signal Seed
timeSeed = Random.initialSeed << round <~ Time.every second
inputs : Signal (Seed,(Int,Int))
inputs = (,) <~ timeSeed ~ otherInput
update : (Seed, (Int,Int)) -> (Int,Int) -> (Int,Int)
update (seed,(x,y)) (x',y') =
let num = randomInt seed
in (x-x'-num,y'-y+num) -- this update function is nonsense
main : Signal Element
main = asText <~ Signal.foldp update (0,0) inputs
If you need time as an input anyway, and sample your other inputs based on this time, it's the easiest way. (If you already use Time.fps for this, use Time.timestamp to get the actual time with it)
2) At startup with a signal
If you don't normally need time as an input to your program, the previous solution is not ideal. You may prefer to initialise your program state with the start time of the program and not have to ignore a time ticker for the rest of the time the program runs.
It's probably easiest to do this with the signal-extra package*. Use Signal.Time.startTime to get a signal that doesn't tick but only has the start time of the program as the initial value. Use Signal.Extra.foldp' so you can use the initial value of your inputs.
import Time
import Time (Time, second)
import Text (asText)
import Mouse
import Signal
import Signal (Signal, (<~), (~))
import Random
import Random (Seed)
import Graphics.Element (Element)
import Signal.Extra as SignalE
import Signal.Time as Time
randomInt : Seed -> (Int,Seed)
randomInt seed = (Random.generate <| Random.int 1 10) |> fst
otherInput : Signal (Int,Int)
otherInput = Mouse.position
startTimeSeed : Signal Seed
startTimeSeed = Random.initialSeed << round <~ Time.startTime
inputs : Signal (Seed,(Int,Int))
inputs = (,) <~ startTimeSeed ~ otherInput
update (x,y) (seed,(x',y')) =
let (num,seed') = randomInt seed
in (seed',(x-x'-num,y'-y+num))
main : Signal Element
main = asText <~ SignalE.foldp' (snd >> update) identity inputs
*I may be biased because I'm the author of the linked package. But I don't know of other packages offering the same functionality.
3) At startup with a port
If you find the previous solution unsatisfactory, because you have this not-changing Signal to add to your input, this solution is for you. Here we use JavaScript interop to get the program startup time, and Elm will accept it as a constant value (no Signal). The Elm code looks like so:
import Time
import Time (Time, second)
import Text (asText)
import Mouse
import Signal (Signal, (<~))
import Random
import Random (Seed)
import Graphics.Element (Element)
port startTime : Float
randomInt : Seed -> (Int,Seed)
randomInt seed = (Random.generate <| Random.int 1 10) |> fst
startTimeSeed : Seed
startTimeSeed = Random.initialSeed <| round startTime
update (x,y) (seed,(x',y')) =
let (num,seed') = randomInt seed
in (seed',(x-x'-num,y'-y+num))
main : Signal Element
main = asText <~ Signal.foldp update (startTimeSeed, (0,0)) Mouse.position
So what's the downside here? You need to write some JavaScript. Instead of the standard
<script>Elm.fullscreen(Elm.<YourModule>)</script>
, you need something like this in your html file:
<script>Elm.fullscreen(Elm.<YourModule>, {startTime: Date.now()})</script>
If you choose this way, perhaps it's a good idea to use a random number from JavaScript as your initial seed. I've read that that's more cryptographically secure (disclaimer: I don't know much about crypto). So you'd have a port aRandomNumber : Int and {aRandomNumber: Math.floor((Math.random() - 0.5) * 4294967295)}.
I reworked the third example from #Apanatshka above, trying to get to simpler code that feels more like the standard architecture, at least as seen in Mike Clark's training videos, and runs under Elm 0.16. Here is the refactored version I came up with:
module PortBasedRandom where
import Mouse
import Signal exposing (Signal, map)
import Random exposing (Seed)
import Graphics.Element exposing (Element, show)
port primer : Float
firstSeed : Seed
firstSeed =
Random.initialSeed <| round primer
type alias Model =
{ nextSeed : Seed
, currentInt : Int
}
initialModel : Model
initialModel =
{ nextSeed = firstSeed
, currentInt = 0
}
randomInt : Model -> Model
randomInt model =
let
(i, s) = Random.generate (Random.int 1 10) model.nextSeed
in
{ model | nextSeed = s, currentInt = i }
update : (Int, Int) -> Model -> Model
update (_, _) model =
randomInt model
main : Signal Element
main =
Signal.foldp update initialModel Mouse.position
|> map (\m -> show m.currentInt)
This needs special help in the HTML file, so here's a file containing two examples:
<html>
<head>
<title></title>
<script src="port_based_random.js"></script>
</head>
<body>
<p>Move your mouse to generate new random numbers between 1 and 10 inclusive.</p>
<script>Elm.fullscreen(Elm.PortBasedRandom, {primer: Date.now()})</script>
<script>Elm.fullscreen(Elm.PortBasedRandom, {primer: Math.floor((Math.random() - 0.5) * 4294967295)})</script>
</body>
</html>
If you are using the StartApp then you'll need to use a custom HTML file with
<script type="text/javascript">
var yourPgm = Elm.fullscreen(Elm.Main, {startTime: Date.now()});
</script>
Then to use the startTime as a seed:
startTimeSeed : Seed
startTimeSeed = Random.initialSeed <| round startTime
app =
StartApp.start
{ init = (init startTimeSeed, Effects.none)
, update = update
, view = view
, inputs = []
}
And then in the code you'll be doing something like
init : Seed -> List Int
init seed = fst <| Random.generate intList seed
where, for example:
intList : Random.Generator (List Int)
intList =
Random.list 5 (Random.int 0 100)
Just an update for people who got here from Google like I did: the recommended way to do this now is with flags instead of ports. The code in the other answers will not even compile now.
https://guide.elm-lang.org/interop/javascript.html
HTML
<script>
var app = Elm.Main.fullscreen({myRandomValue: Date.now()});
</script>
Elm
type alias Model = {
mySeed : String
}
type alias Flags = {
myRandomValue : String
}
init : Flags -> ( Model, Cmd Msg )
init flags =
{
mySeed = flags.myRandomValue
}
...
main : Program Flags Model Msg
main = programWithFlags
{
view = view,
init = init,
update = update
}

Resources