Can't generate random number F #
I am working on a small project and trying to learn the functional way of F #, for some strange reason I cannot generate a random number and as such was unable to get a random date. here is my F # code
let IfancyHerList = [("Sara",1); ("Saima",2); ("Zoe",3);("Scarlett",4);
("Jennifer",5);("Sandra Bullock",6)]
let MyGirlFriend = List.pick (fun funToNight ->
let n = rand.Next(10)
match funToNight with
| (value,n ) -> Some value
|_ -> None) IfancyHerList
printfn "Your date for tonight is %s lucky fella" MyGirlFriend
Let n = rand.Next (10) actually generate a random number, but not in a match block
any suggestion would be welcome
thank
source to share
Your code doesn't do what you expect it to do. Pattern matching is technically the opposite of data construction. It just decomposes / deconstructs data.
What are you doing here:
match funToNight with
| (value,n ) -> Some value
|_ -> None
has the following meaning:
- Check if
funToNight
tuple is. - Assign the first value to the tuple
value
- Assign the second value to the tuple
n
It seems that what you expected:
- Check if the second value of the tuple is what is inside
n
And that's not how Match Matching works.
You can add conventions such as comparing a value to a given variable by adding a clause when
to match a pattern. Like this:
match funToNight with
| (value,x) when x = n -> Some value
| _ -> None
But in my opinion your case is a use case where Match Matching doesn't make sense to start. You want to check if the second entry is your random number, so use the instruction if
.
let MyGirlFriend =
List.pick (fun funToNight ->
let n = rand.Next(10)
if (snd funToNight) = n
then Some (fst funToNight)
else None
) IfancyHerList
instead of fst
and snd
you can also do this in a lambda.
let MyGirlFriend =
List.pick (fun (name,nr) ->
let n = rand.Next(10)
if nr = n
then Some name
else None
) IfancyHerList
This is a generic picking solution that also works with tuples of other sizes. fst
and snd
only work with tuples that have exactly two elements.
Also, you probably want to use List.tryPick
instead List.pick
. List.pick
throws an exception if it cannot find an element. Upper variables must start with lower case. Upper case values ββare used for types / classes.
So here's a complete working example:
let rand = new System.Random()
let ifancyHerList =
[
("Sara",1); ("Saima",2); ("Zoe",3); ("Scarlett",4);
("Jennifer",5);("Sandra Bullock",6)
]
let myGirlFriend =
List.tryPick (fun (name,nr) ->
let n = rand.Next(10)
if nr = n
then Some name
else None
) ifancyHerList
match myGirlFriend with
| Some name -> printfn "Your date for tonight is %A lucky fella" name
| None -> printfn "You don't have a date tonight!"
Adding
Your call List.pick
returns quite a lot None
and does not select an entry. The reason is that you are generating a random number inside the lambda function you are passing to List.pick
.
Your current "flow" of your code looks like this. You are viewing the list. First choice ("Sara",1)
. You are generating a random case, say 5
. 1
and 5
do not match, so the next entry will be used ("Saima", 2)
. But then you generate a new random number again, say 3
and the next record is selected, because 3
both are 2
not equal. This can continue without any choice of any entry. Even if you change the random generation to rand.Next(6)
.
So the general advice is that you shouldn't add side effects to lambda expressions. I am assuming that you want to generate one random number and then select it from the list. It's easy to change it by extracting a random call outside of the lambda.
let myGirlFriend =
let n = rand.Next(10)
List.tryPick (fun (name,nr) ->
if nr = n
then Some name
else None
) ifancyHerList
So the general advice is to avoid side effects in higher-order functions.
source to share
Your real problem is not with random numbers, but with your statement match
. You are misunderstanding how it works. The short version: match (whatever) with (value, n) -> ...
not doing what you think, does: always match and assigns names value
and n
the two parts of any tuple with whom you are compared.
The longer version is that you are making the same mistake as F #: you don't understand the ..c match , so I'll just point you to that question. read a more detailed answer.
source to share