为何调用两次F#函数oneRun仅执行一次?求排查方案
蒙特卡洛测试代码问题排查与解决
嘿,我来帮你理清这个问题的根源和解决办法!
核心问题:你把oneRun定义成了「值」,不是「函数」
在F#里,let oneRun = ...这种写法是值绑定——它只会在第一次被引用的时候执行一次,然后把结果缓存起来。后面你再写let a = oneRun、let b = oneRun,其实都是在拿第一次执行后的缓存结果,根本没重新跑里面的逻辑,这就是为什么genRandomNumbers只输出了一次"oi"和随机数。
快速排查验证
你可以在oneRun的代码块开头加一句printfn "Running oneRun...",运行后会发现这句话只打印一次,直接坐实了「值只会计算一次」的行为。
解决办法:把oneRun改成函数
只需要给它加个空参数(),让F#把它识别成函数,这样每次调用都会重新执行内部逻辑:
修改后的完整代码:
let genRandomNumbers count = let rnd = System.Random() printf "oi " List.init count (fun _ -> rnd.NextDouble ()) // 改成函数,添加()作为参数 let oneRun () = let numberofClicks = 0 let randomNumber = genRandomNumbers 50 let action numberofClicks random = if random <= 0.10 then numberofClicks+1 else numberofClicks randomNumber |> Seq.iter (printf "%f ") randomNumber |> List.fold action numberofClicks [<EntryPoint>] let main argv = let a = oneRun () // 调用函数时要加() printf "%d " a let b = oneRun () // 再次调用,会重新执行所有逻辑 printf "%d " b let key_info = System.Console.ReadKey() 0
额外小提示
如果你的代码调用genRandomNumbers的间隔特别短,可能会因为System.Random的种子基于系统时间,导致生成重复的随机序列。这种情况下可以把rnd实例提到genRandomNumbers外面,做成一个共享的生成器,不过这是优化项,和当前的核心问题无关啦。
内容的提问来源于stack exchange,提问作者Camilo Telles
相关产品推荐
相关产品推荐

