Generating unique random number - elm

I have an application that I want to generate a list of 5 unique numbers on init three times after reading a json. So basically I want to get something like [31, 59, 62, 72, 2, 16, 2, 38, 94, 15, 55, 46, 83, 2, 10]. My challenge is that I am new to functional programming and elm and I am a bit lost. So I understand that Random.generate takes a msg and a generator and returns a cmd message and it is mostly used in the update function but this is not where I need as it is a helper function and doesn't need to communicate with the client. I think it can be used in init but I don't know how. Again my function is recursive and I don't know how to apply this logic with Random.generate recursively.
I understand my code will not work and I have tried it because Random.int does not generate a random number but a type of generate but still I don't know how to apply this to get what I want.
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)
can be called with:
recursion 50 []
I want to generate a list/array of 5 unique random 3 times.

Great question. There are two parts here:
- generating random numbers, and
- wiring this all up
You will need the Random library for the former, and a little inspection will lead you to something like
get15Randoms = Random.generate OnRandomNumbers <| Random.list 5 (int 0 100)
This has type Cmd Msg - it's an async operation that will return on a Msg.
Wiring it up will be a series of stages. You refer to doing it in 'init' but that's not how Elm is going to work for you here. In the init function you can start off your json request. Then you'll need something like
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 )
In other words, once the json comes back you can attach that, and use that iteration of the update to launch your random number request, and then catch the result in a subsequent iteration

Random number generation is a side-effect because it's not predictable by definition, meaning its output isn't purely determined by its inputs. In Elm all side-effects go through the update function because if side-effects were allowed anywhere there would be no guarantee that any part of your code is pure and predictable. Things might start behaving differently at random, and it would be very hard figure out why since random input can occur anywhere.
That said, init is one place where it might make sense to allow side-effects, since there isn't any state yet. But since most side-effects are not immediate and you would most likely want to present some UI to indicate that your app is loading, I assume the API just hasn't been complicated to allow for a use case so rare. Especially since there are a couple workarounds you can use:
Workaround 1 - an empty representation
Since you're using a list to contain the random numbers, you could probably just use an empty list to represent that you've not received the numbers yet. Otherwise use a Maybe, or a custom type. This might be a bit cumbersome since you have to handle the empty case every time you use it, but depending on your use case it might be acceptable.
Workaround 2 - flags
Elm allows for sending data into your program from the outside on initializtion, and will pass this to your init function. This mechanism is called flags. You can use this to generate the numbers in JavaScript before sending it in as a parameter.
In your index.html you would put:
var app = Elm.Main.init({
node: document.getElementById('elm'),
flags: Array.from({length: 15}, () => Math.floor(Math.random() * 50))
});
And in init you accept the numbers as an ordinary argument:
init : List number -> Model
init numbers =
{ myNumbers = numbes
, ...
}

I want to respond with what I ended up doing motivated by #Simon-h's answer. I had a Msg type RndGen Int and since update is a function I decided to call RndGen recursively with help from the update function and flag it off when I got the number of random numbers I needed.
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)
and
get15Randoms =
Random.generate RndGen (Random.int 0 100)
on init
init questions =
(Model (getQuestions questions) 1 True [] False "", get15Randoms)
I will like to know if my thinking aligns with what the elm community will expect.

Related

Elm Generator Int -> List Int

I want to get List out of Generator
intList : Generator (List Int)
intList =
list 5 (int 0 100)
How could I now get a list out of it?
You cannot get a random list out of Generator because Elm functions are always pure. The only possibility to get a list is to use a command.
A command is a way to tell Elm runtime to do some impure operation. In your case, you can tell it to generate a random list of integers. Then it will return back the result of that operation as an argument of the update function.
To send Elm runtime a command to generate a random value, you can use the function Random.generate:
generate : (a -> msg) -> Generator a -> Cmd msg
You already have Generator a (your intList), so you need to provide a function a -> msg. This function should wrap a (List Int in your case) into a message.
The final code should be something like that:
type Msg =
RandomListMsg (List Int)
| ... other types of messages here
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model = case msg of
... -> ( model, Random.generate RandomListMsg intList)
RandomListMsg yourRandomList -> ...
If you don't know about messages and models yet, you should probably get acquainted with the Elm architecture first.
You can provide your own seed value to Random.step, which will return a tuple containing a list and the next seed value. This retains purity because you will always get the same result when you pass the same seed.
Random.step intList (Random.initialSeed 123)
|> Tuple.first
-- will always yield [69,0,6,93,2]
The answer given by #ZhekaKozlov is typically how you generate random values in an application, but it uses Random.step under the hood with the current time used as the initial seed.

Why does random always return an even number

I want to learn Elm and currently I want to create a random List with tuples containing an index and a random number.
My current approach is to create a list and for each element create a random value:
randomList =
List.map randomEntry (List.range 0 1000)
randomEntry index =
let
seed = Random.initialSeed index
randomResult = Random.step (Random.int 1 10) seed
in
(index, Tuple.first randomResult)
But this only creates even numbers.
Why does it always create even numbers and what is the correct way of doing this?
Strange - using your randomEntry function, the first odd numbers don't start showing up until 53668, and then it's odd numbers for a while. An example from the REPL:
> List.range 0 100000 |> List.map randomEntry |> List.filter (\(a,b) -> b % 2 /= 0) |> List.take 10
[(53668,35),(53669,87),(53670,1),(53671,15),(53672,29),(53673,43),(53674,57),(53675,71),(53676,85),(53677,99)]
: List ( Int, Int )
Now I can't tell you why there is such stickiness in this range (here's the source for the int generator if you're curious), but hopefully I can shed some light on randomness in Elm.
There is really no way to create a truly random number generator using standard computing technology (quantum computers aside), so the typical way of creating randomness is to provide a function that takes a seed value, returns a pseudo-random number and the next seed value to use.
This makes random number generation predictable, since you will always get the same "random" number for the same seed.
This is why you always get identical results for the input you've given: You are using the same seed values of 0 through 1000. In addition, you are ignoring the "next seed" value passed back from the step function, which is returned as the second value of the tuple.
Now, when dealing with random number generators, it is a good rule of thumb to avoid dealing with the seed as much as possible. You can write generators without referring to seeds by building on smaller generators like int, list, and so on.
The way you execute a generator is either by returning a Cmd generated from Random.generate from your update function, which leaves the responsibility of deciding which seed to use to the Elm Architecture (which probably uses some time-based seed), or you can pass in the seed using Random.step, which you've done above.
So, going back to your original example, if you were to write a generator for returning a list of random numbers of a certain size, where each number is within a certain range, it could look something like this:
randomListGenerator : Int -> (Int, Int) -> Random.Generator (List Int)
randomListGenerator size (low, high) =
Random.list size (Random.int low high)
Executing this using step in the REPL shows how it can be used:
> initialSeed 0 |> step (randomListGenerator 20 (1, 10)) |> Tuple.first
[6,6,6,1,3,10,4,4,4,9,6,3,5,3,7,8,3,4,8,5] : List Int
You'll see that this includes some odd numbers, unlike your initial example. The fact that it is different than your example is because the generator returns the next seed to use each consecutive step, whereas your example used the integers 0 through 1000 in order. I still have no explanation to your original question of why there is such a big block of evens using your original input, other than to say it is very odd.

How to modify a List element at a given index

What I've done (with some help from a friend) is create a function that takes a List, Int for the index, and a function to be applied to the element at the specified index. It's similar to Map but instead of applying a function to every element, it applies it to only one element.
So my questions are:
Does this function already exist in the core somewhere? We couldn't find it.
If not, is there a better way of accomplishing this than how we have done it?
Here's the code:
import Html exposing (text)
main =
let
m = {arr=[1,5,3], msg=""}
in
text (toString (getDisplay m 4 (\x -> x + 5)))
type alias Model =
{ arr : List (Int)
, msg : String
}
getDisplay : Model -> Int -> (Int -> Int) -> Model
getDisplay model i f =
let
m = (changeAt model.arr i f)
in
case m of
Ok val ->
{model | arr = val, msg = ""}
Err err ->
{model | arr = [], msg = err}
changeAt : List a -> Int -> (a -> a) -> Result String (List a)
changeAt l i func =
let
f j x = if j==i then func x else x
in
if i < (List.length l) && i >= 0 then
Ok(List.indexedMap f l)
else
Err "Bad index"
NOTE: Elm discourages indexing Lists, as they are linked lists under the hood: to retrieve the 1001th element, you have to first visit all 1000 previous elements. Nonetheless, if you wanted to do it, this is one way.
List.indexedMap is a good way to do what you're describing.
However, since you mention the downside of having to visit all preceding elements in a list, the reality in your example is actually a little worse, if indeed you are super worried about performance.
Your list is actually traversed fully at least two times, regardless of whether the index exists or not. The simple act of asking for the length of a linked list has to traverse the entire list. Check out the source code, length is implemented in terms of a foldl.
Furthermore, List.indexedMap traverses the entire list at least once. I say, at least once, since the source of indexedMap also calls the length function in addition to using map. If we're lucky, the length call is memoized (I'm not familiar enough with Elm internals to know whether it is or not, hence the at least comment). The map itself traverses the entire list when called, unlike Haskell which evaluates things lazily, only as much as necessary.
And if you use indexedMap, the whole list is indexed regardless of the position you are interested in. That is, even if you want to apply the function at index zero, the entire list is indexed.
If you actually want to reduce the number of traversals to a minimum, you're going to (at this time) have to implement your own function and you'll have to do it without relying on length or indexedMap.
Here is an example of a changeAt function which avoids unnecessary traversals and if it finds the position, it stops traversing the list.
changeAt : List a -> Int -> (a -> a) -> Result String (List a)
changeAt l i func =
if i < 0 then
Err "Bad Index"
else
case l of
[] ->
Err "Not found"
(x::xs) ->
if i == 0 then
Ok <| func x :: xs
else
Result.map ((::) x) <| changeAt xs (i - 1) func
It's not terribly pretty, but if you want to avoid unnecessarily walking through the list - multiple times - then you might want to go with something like this.
You're looking for the set function for Arrays. Instead of using a List, which is inefficient as you described, this structure is better suited to your use case.
Here's an efficient implementation of the function you're looking for:
changeAt : Int -> (a -> a) -> Array a -> Array a
changeAt i f array =
case get i array of
Just item ->
set i (f item) array
Nothing ->
array
Also note that the data structure is the last argument in this implementation.
Array is mentioned in the link in your question, but nobody on this thread had explicitly mentioned this option yet.

Generating tree nodes on the fly

I have an ANTLRv3 grammar to transform an AST (generated and consumed by other grammars).
One part of it is to rewrite ranges defined like M:N (i.e. 1:5) into their actual list representation — M, M+1, ..., N (i.e. 1, 2, 3, 4, 5).
So, a node ^(RANGE s=INT e=INT) is transformed into a list of INT tokens.
What I currently do now is the following:
range
: ^(RANGE s=INT e=INT) -> { ToSequence(int.Parse($s.text),int.Parse($e.text)) }
;
and the ToSequence method looks like
private ITree ToSequence(int start, int end)
{
var tree = new CommonTree();
for (int i = start; i <= end; i++)
{
tree.AddChild(new CommonTree(new CommonToken(INT, i.ToString())));
}
return tree;
}
It actually works fine, transforming tree node (TIME 1 2 (RANGE 5 10) 3 4) to (TIME 1 2 5 6 7 8 9 10 3 4), but I somewhat unsure whether it is the correct and idiomatic way to do such a transformation.
So, is there any more civilized way to perform this task?
I don’t think that performing such transformations inside the parser is a good idea at all. Your code lacks any kind of validity check. What if the first number is bigger than the second one? And what if errors are detected at the next stage of processing? At that point you have already lost the knowledge about the true structure of your input so you can’t give useful error messages.
I strongly recommend building a tree reflecting the true structure of your input first and transforming the tree afterwards. The transformed node might keep references to their source nodes then.

Generating a list of lists of Int with QuickCheck

I'm working through Real World
Haskell one of the
exercises of chapter 4 is to implement an foldr based version of
concat. I thought this would be a great candidate for testing with
QuickCheck since there is an existing implementation to validate my
results. This however requires me to define an instance of the
Arbitrary typeclass that can generate arbitrary [[Int]]. So far I have
been unable to figure out how to do this. My first attempt was:
module FoldExcercises_Test
where
import Test.QuickCheck
import Test.QuickCheck.Batch
import FoldExcercises
prop_concat xs =
concat xs == fconcat xs
where types = xs ::[[Int]]
options = TestOptions { no_of_tests = 200
, length_of_tests = 1
, debug_tests = True }
allChecks = [
run (prop_concat)
]
main = do
runTests "simple" options allChecks
This results in no tests being performed. Looking at various bits and
pieces I guessed that an Arbitrary instance declaration was needed and
added
instance Arbitrary a => Arbitrary [[a]] where
arbitrary = sized arb'
where arb' n = vector n (arbitrary :: Gen a)
This resulted in ghci complaining that my instance declaration was
invalid and that adding -XFlexibleInstances might solve my problem.
Adding the {-# OPTIONS_GHC -XFlexibleInstances #-} directive
results in a type mismatch and an overlapping instances warning.
So my question is what's needed to make this work? I'm obviously new
to Haskell and am not finding any resources that help me out.
Any pointers are much appreciated.
Edit
It appears I was misguided by QuickCheck's output when in a test first manner fconcat is defined as
fconcat = undefined
Actually implementing the function correctly indeed gives the expected result. DOOP!
[[Int]] is already an Arbitrary instance (because Int is an Arbitrary instance, so is [a] for all as that are themselves instances of Arbitrary). So that is not the problem.
I ran your code myself (replacing import FoldExcercises with fconcat = concat) and it ran 200 tests as I would have expected, so I am mystified as to why it doesn't do it for you. But you do NOT need to add an Arbitrary instance.