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

+3


source to share


2 answers


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.

+6


source


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.

+5


source







All Articles