gpt4 book ai didi

f# - 使用“最终”工作流程时,缺少尾部调用优化是否会成为障碍?

转载 作者:行者123 更新时间:2023-12-04 03:13:24 28 4
gpt4 key购买 nike

在Xbox上进行开发时,我使用的是F#规范中最终工作流程的修改版。 Xbox上的.net框架似乎不支持尾部调用。因此,我必须在编译时禁用尾部调用优化。

尽管起初看来这种限制会阻止在计算表达式中使用任何形式的循环,但我最初认为“步进”可以避免该问题:计算表达式中的递归函数f不会直接调用自身,而是返回最终值,该值包含调用f的lambda。

实验表明,我对while循环是正确的(在计算表达式中使用它们不会引起堆栈溢出),但对于递归函数却不正确。

澄清一下,这可行:

// Wait until "start" or "A" is pressed on one of the gamepads.
// Set "player" when that happens.
let player : PlayerIndex option ref = ref None
while (!player).IsNone do
for p in all_players do
let state = GamePad.GetState(p)
if state.IsConnected
&& (state.Buttons.Start = ButtonState.Pressed
|| state.Buttons.A = ButtonState.Pressed) then
player := Some p
do! sys.WaitNextFrame()

这会导致堆栈溢出:
// Wait until "start" is pressed on the controlling gamepad.
let rec wait() = task {
input.Update()
if not (input.IsStartPressed()) then
do! sys.WaitNextFrame()
do! wait()
}

在第二种情况下,堆栈跟踪显示了对“bind @ 17-1”的一长串调用,其代码如下所示。出现在堆栈跟踪中的行号是第17行。
let rec bind k e =
match e with
| Completed r ->
Running(fun () -> k r)
| Running f ->
Running(fun () -> f() |> bind k) // line 17
| Blocked(dt, f) ->
Blocked(dt, fun () -> f() |> bind k)
| BlockedNextFrame f ->
BlockedNextFrame(fun () -> f() |> bind k)
| Yield f ->
Yield(fun () -> f() |> bind k)

我哪里错了?我的理由是“步进式递归”无害。堆栈溢出不正确?我的bind实现存在问题吗?

哦,我的头!递归的连续传递让我头疼...

编辑:“步进式递归是无害的,而W.r.t.堆栈溢出”已经有了一个名字,我刚刚学到了。叫做蹦床。

最佳答案

替换最后的做! 返回! :

// Wait until "start" is pressed on the controlling gamepad.
let rec wait() = task {
input.Update()
if not (input.IsStartPressed()) then
do! sys.WaitNextFrame()
return! wait()
}

编辑

根据F#规范, 做! wait()将转换为Bind(wait(),fun()-> Zero()),因此每个递归调用都会增加Bind嵌套的级别(如您在stacktrace中看到的)

在对面 返回! wait()将立即返回新的“最终”计算,可以在下一步中使用。

关于f# - 使用“最终”工作流程时,缺少尾部调用优化是否会成为障碍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4900451/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com