I am working on a small project and am trying to learn F# the functional way ,for some strange reason I am unable to generate a random number and as such 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
The let n = rand.Next(10) does generate a random number but not in match block
any suggestion would be most welcome
thanks
Your code doesn't do what you expect it to do. Pattern Matching is technically the opposite of constructing data. It just decompose/de-construct data.
What you do here:
match funToNight with
| (value,n ) -> Some value
|_ -> None
has the following meaning:
funToNight
is a tuple. value
n
It seems what you expected was:
n
And that isn't how Pattern Matching works.
You can add conditionals like comparing a value with a pre-defined variable by adding a when
clause to the Pattern Matching. Like this:
match funToNight with
| (value,x) when x = n -> Some value
| _ -> None
But in my opinion, your case is exactly a use-case where Pattern Matching don't make sense to begin with. You want to check if the second entry is your random number, so use an if
statement instead.
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 also can do it in the lambda.
let MyGirlFriend =
List.pick (fun (name,nr) ->
let n = rand.Next(10)
if nr = n
then Some name
else None
) IfancyHerList
This is the general solution to pick that also works with tuples of other sizes. fst
and snd
only work with tuples that has exactly two elements.
Besides that you probably want to use List.tryPick
instead of List.pick
. List.pick
throws an exception if it cannot find an element. On top variables should start with a lower-case. Upper-case values are used for Types/Classes.
So here is 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!"
Your List.pick
call returns quite a lot None
and doesn't pick an entry. The reason is that you generate the random number inside the lambda function you pass to List.pick
.
Your current "flow" of your code is like this. You go through the list. First picking ("Sara",1)
. You generate a random, let's say 5
. 1
and 5
doesn't match so the next entry ("Saima", 2)
will be used. But then you generate again a new random number, let's say 3
and the next entry is picked because 3
and 2
are not equal. This can go on without every picking any entry. Even if you change the random generation to rand.Next(6)
.
So a general advice is that you shouldn't add side-effects to lambda expressions. I assume you want to generate one random number and then pick it from the list. Its easy to change by extracting the random call outside the lambda.
let myGirlFriend =
let n = rand.Next(10)
List.tryPick (fun (name,nr) ->
if nr = n
then Some name
else None
) ifancyHerList
So a general advice, avoid side-effects in Higher-Order functions.
Your real issue isn't with random numbers at all, it's with your match
statement. You misunderstand how it works. Short version: match (whatever) with (value, n) -> ...
doesn't do what you think it does: it always matches, and assigns the names value
and n
to the two parts of whatever tuple you matched against.
The longer version is that you're making the same mistake as F#: Not understanding match .. with , so I'll just point you to that question to read the more in-depth answer.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.