Я использую модифицированную версию рабочего процесса Eventually из спецификации F # для своей разработки на Xbox. .NET Framework на Xbox, кажется, не поддерживает хвостовые вызовы. Из-за этого я должен отключить оптимизацию хвостового вызова при компиляции.
Хотя на первый взгляд может показаться, что это ограничение предотвратит использование любой формы зацикливания в выражениях вычислений, я изначально думал, что «шагание» позволит избежать этой проблемы: рекурсивная функция f в выражении вычисления не вызывает себя напрямую вместо этого он возвращает значение «В конце концов», содержащее лямбду, которое вызывает f.
Эксперименты показывают, что я был прав насчет циклов 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)
Где я не прав? Являются ли мои рассуждения о "степной рекурсии" безвредными в отношении W.r.t. переполнение стека неверно? Что-то не так с моей реализацией bind?
О, моя голова! Продолжение прохождения с рекурсией вызывает головную боль ...
РЕДАКТИРОВАТЬ: «степпируемая рекурсия безвредна при переполнении стека». У меня есть имя, которое я только что узнал. Это называется батут.