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)
Related
I'm new to rust and am trying to make use of the windows cargo. But I don't understand what I should set the &self parameter in the FindAppointmentsAsync function.
This is Cargo.toml:
[package]
name = "rust-test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dependencies.windows]
version = "0.43.0"
features = [
"ApplicationModel",
"ApplicationModel_Appointments",
"Foundation_Collections",
]
This is main.rs:
use std::time::Duration;
use windows::{
core::*, ApplicationModel::Appointments::*, Foundation::{DateTime, TimeSpan},
};
fn main() -> Result<()> {
let rangestart = DateTime::default();
let rangelength = TimeSpan::from(Duration::new(60 * 60 * 24 * 30, 0));
println!("test");
unsafe {
let store = AppointmentStore();
let result = AppointmentStore::FindAppointmentsAsync(&store, rangestart, rangelength);
}
Ok(())
}
If let store = AppointmentStore::new(); the error is no function or associated item named 'new' found
If let store = AppointmentStore();, the error is expected 1 argument, found 0
If let store = AppointmentStore(""); the error is cannot initialize a tuple struct which contains private fields
You cannot create an AppointmentStore directly, as it has private fields and does not expose a constructor function.
Looking at the docs, there are two ways to get an AppointmentStore:
By calling clone on an existing one.
By calling RequestStoreAsync on an AppointmentManager or AppointmentManagerForUser.
AppointmentManager is a struct with no fields, so you can create one by simply doing:
let foo = AppointmentManager;
let bar = foo.RequestStoreAsync(/* insert params here */);
AppointmentManagerForUser also cannot be constructed directly, and is obtained by calling GetForUser on an AppointmentManager.
While refactoring my F# code, I found a record with a field of type bool ref:
type MyType =
{
Enabled : bool ref
// other, irrelevant fields here
}
I decided to try changing it to a mutable field instead
// Refactored version
type MyType =
{
mutable Enabled : bool
// other fields unchanged
}
Also, I applied all the changes required to make the code compile (i.e. changing := to <-, removing incr and decr functions, etc).
I noticed that after the changes some of the unit tests started to fail.
As the code is pretty large, I can't really see what exactly changed.
Is there a significant difference in implementation of the two that could change the behavior of my program?
Yes, there is a difference. Refs are first-class values, while mutable variables are a language construct.
Or, from a different perspective, you might say that ref cells are passed by reference, while mutable variables are passed by value.
Consider this:
type T = { mutable x : int }
type U = { y : int ref }
let t = { x = 5 }
let u = { y = ref 5 }
let mutable xx = t.x
xx <- 10
printfn "%d" t.x // Prints 5
let mutable yy = u.y
yy := 10
printfn "%d" !u.y // Prints 10
This happens because xx is a completely new mutable variable, unrelated to t.x, so that mutating xx has no effect on x.
But yy is a reference to the exact same ref cell as u.y, so that pushing a new value into that cell while referring to it via yy has the same effect as if referring to it via u.y.
If you "copy" a ref, the copy ends up pointing to the same ref, but if you copy a mutable variable, only its value gets copied.
You have the difference not because one is first-value, passed by reference/value or other things. It's because a ref is just a container (class) on its own.
The difference is more obvious when you implement a ref by yourself. You could do it like this:
type Reference<'a> = {
mutable Value: 'a
}
Now look at both definitions.
type MyTypeA = {
mutable Enabled: bool
}
type MyTypeB = {
Enabled: Reference<bool>
}
MyTypeA has a Enabled field that can be directly changed or with other word is mutable.
On the other-side you have MyTypeB that is theoretically immutable but has a Enabled that reference to a mutable class.
The Enabled from MyTypeB just reference to an object that is mutable like the millions of other classes in .NET. From the above type definitions, you can create objects like these.
let t = { MyTypeA.Enabled = true }
let u = { MyTypeB.Enabled = { Value = true }}
Creating the types makes it more obvious, that the first is a mutable field, and the second contains an object with a mutable field.
You find the implementation of ref in FSharp.Core/prim-types.fs it looks like this:
[<DebuggerDisplay("{contents}")>]
[<StructuralEquality; StructuralComparison>]
[<CompiledName("FSharpRef`1")>]
type Ref<'T> =
{
[<DebuggerBrowsable(DebuggerBrowsableState.Never)>]
mutable contents: 'T }
member x.Value
with get() = x.contents
and set v = x.contents <- v
and 'T ref = Ref<'T>
The ref keyword in F# is just the built-in way to create such a pre-defined mutable Reference object, instead that you create your own type for this. And it has some benefits that it works well whenever you need to pass byref, in or out values in .NET. So you should use ref. But you also can use a mutable for this. For example, both code examples do the same.
With a reference
let parsed =
let result = ref 0
match System.Int32.TryParse("1234", result) with
| true -> result.Value
| false -> result.Value
With a mutable
let parsed =
let mutable result = 0
match System.Int32.TryParse("1234", &result) with
| true -> result
| false -> result
In both examples you get a 1234 as an int parsed. But the first example will create a FSharpRef and pass it to Int32.TryParse while the second example creates a field or variable and passes it with out to Int32.TryParse
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.
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)
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
}