简体   繁体   English

无法生成随机数F#

[英]Unable to generate random number F#

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. 我正在研究一个小项目,我正在尝试学习F#的功能方式,由于一些奇怪的原因,我无法生成随机数,因此无法获得随机日期。 here is my F# code 这是我的F#代码

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 let n = rand.Next(10)确实生成一个随机数但不在匹配块中

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: 具有以下含义:

  1. Check if funToNight is a tuple. 检查funToNight是否为元组。
  2. Assign the first value of the tuple to value 将元组的第一个值赋给value
  3. Assign the second value of the tuple to n 将元组的第二个值赋给n

It seems what you expected was: 看起来你的期望是:

  1. Check if the second value of a tuple is what is inside n 检查元组的第二个值是否在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. 您可以通过向模式匹配添加when子句来添加条件,例如将值与预定义变量进行比较。 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. 您想检查第二个条目是否是随机数,因此请改用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 also can do it in the lambda. 而不是fstsnd你也可以在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. fstsnd只适用于具有两个元素的元组。

Besides that you probably want to use List.tryPick instead of List.pick . 除此之外,您可能希望使用List.tryPick而不是List.pick List.pick throws an exception if it cannot find an element. 如果List.pick找不到元素,则抛出异常。 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!"

Addendum 附录

Your List.pick call returns quite a lot None and doesn't pick an entry. List.pick调用返回了不少None ,并且不挑一个条目。 The reason is that you generate the random number inside the lambda function you pass to List.pick . 原因是您在传递给List.pick的lambda函数中生成随机数。

Your current "flow" of your code is like this. 您当前的代码“流”是这样的。 You go through the list. 你仔细阅读清单。 First picking ("Sara",1) . 首先采摘("Sara",1) You generate a random, let's say 5 . 你生成一个随机的,比方说5 1 and 5 doesn't match so the next entry ("Saima", 2) will be used. 15不匹配,因此将使用下一个条目("Saima", 2) 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. 但是你再次生成一个新的随机数,让我们说3并且选择下一个条目,因为32不相等。 This can go on without every picking any entry. 这可以继续,而不是每次选择任何条目。 Even if you change the random generation to rand.Next(6) . 即使你将随机生成更改为rand.Next(6)

So a general advice is that you shouldn't add side-effects to lambda expressions. 所以一般的建议是你不应该为lambda表达式添加副作用。 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. 通过提取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. 你真正的问题根本不是随机数,而是你的match声明。 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. 短版本: match (whatever) with (value, n) -> ...不会做你认为它做的事情:它总是匹配,并将名称valuen分配给你匹配的任何元组的两个部分。

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. 较长的版本是你犯了与F#相同的错误:不理解匹配..所以我只是指出你的问题来阅读更深入的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM