我试图在F#上学习自己,我担心我不理解我应该做的事情.
我正在尝试重新创建一本我喜欢的书的功能(来自Royal和Panarese的Creative Cursing).
简而言之,您有两个单独的单词列表,可以从中选择两个随机单词,从而产生一个奇怪的短语.够简单吗?
这就是我所拥有的:
#light
open System
open System.IO
let getWordList file =
File.ReadAllLines( file )
let getRandArrElement (arr : string[]) =
let rnd = Random( 0 )
arr |> Seq.nth (rnd.Next arr.Length)
let wordList1 = getWordList "words1.txt"
let wordList2 = getWordList "words2.txt"
let word1 = getRandArrElement wordList1
let word2 = getRandArrElement wordList2
printf "%s %s" word1 word2
Run Code Online (Sandbox Code Playgroud)
它也有效.除了它每次运行时返回相同的短语.
我有一种感觉,它正在做的是在编译时每次调用"getRandArrElement"计算一个随机值,然后使用该值作为THE值(我认为这很奇怪,但我知道什么?).
我的逻辑有什么问题,我该如何解决?
Jul*_*iet 10
你的问题在这里:
let getRandArrElement (arr : string[]) =
let rnd = Random( 0 )
arr |> Seq.nth (rnd.Next arr.Length
Run Code Online (Sandbox Code Playgroud)
Random数字并不是真正随机的.他们取一个种子值,在0.0和之间计算一个随机数1.0; 新值用作下一个种子.换句话说,Random我确切地说是确定性的,所以反复播种相同的值会产生相同的输出序列.
而且由于你总是构造一个具有相同种子的新Random,你每次都得到与输出相同的随机数.
我建议一些改进:
用let rnd = Random().默认构造函数使用系统时钟作为种子,因此您将获得不同的序列.(它仍然可以获得相同的序列.系统时钟具有大约10毫秒的分辨率,因此在该间隔中构造两个Random将很可能以相同的值播种.
如果您使用let rnd = Random(0),即使rnd不在您的功能范围内,每次运行程序时,您都会以完全相同的顺序获得相同的句子.
您可以移动rnd函数外部的声明,这样您就不会一遍又一遍地构造它.作为替代方案,您可以这样写:
let getRandArrElement =
let rnd = Random()
fun (arr : string[]) -> ...
Run Code Online (Sandbox Code Playgroud)
打开模块时,F#执行所有无参数值,因此rnd将立即分配,并getRandArrElement赋值为fun (arr : string[]) -> ....
用arr.[index]而不是arr |> Seq.nth (rnd.Next arr.Length).它不仅更简洁,而且还是O(1).Seq.nth将它视为一个序列,它一次遍历一个元素,直到它到达与给定索引匹配的元素,从而进行操作O(n).
最终结果应该是这样的:
let getRandArrElement =
let rnd = Random()
fun (arr : string[]) -> arr.[rnd.Next(arr.Length)]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1717 次 |
| 最近记录: |