【发布时间】:2016-06-15 13:11:33
【问题描述】:
源自this question,我有这个小F#代码(github)根据正态分布生成随机值:
// val nextSingle : (unit -> float32)
let nextSingle =
let r = System.Random()
r.NextDouble >> float32
// val gauss : (float32 -> float32 -> seq<float32>)
let gauss mean stdDev =
let rec gauss ready = seq {
match ready with
| Some spare ->
yield spare * stdDev + mean
yield! gauss None
| _ ->
let rec loop () =
let u = nextSingle() * 2.f - 1.f
let v = nextSingle() * 2.f - 1.f
let s = pown u 2 + pown v 2
if s >= 1.f || s = 0.f then loop() else
u, v, s
let u, v, s = loop()
let mul = (*)(sqrt(-2.f * log s / s))
yield mul u * stdDev + mean
yield! mul v |> Some |> gauss
}
gauss None
在我看来,这似乎只应在尾调用位置调用自身,因此在启用 TCO 时永远不会导致StackOverflowException。但在运行 64 位 时它确实。 不在运行 32 位(即项目设置中的“首选 32 位”复选框)时。
我正在使用 .NET Framework 4.5.2 和 F# 4.4.0.0。
谁能解释造成问题的原因?
【问题讨论】:
-
您使用的是哪个 .NET 版本?
-
我发现这些文章谈论的是尾调用优化using .NET 2.0 vs using .NET 4.0,也许他们可以提供帮助。
-
另外,您使用的是什么版本的 F#?我使用 F#4,在调试时我根本看不到堆栈增长。我反汇编了 IL 代码,看起来 F#4 生成的代码不应该 stackoverflow。
-
请附上完整的复制品。调用代码是什么样的?序列表达式中的“尾递归”可能会令人困惑,因为序列实际上并没有自行推进,其他一些代码会。
标签: f# 64-bit stack-overflow 32-bit tail-recursion