Я пытаюсь понять, как правильно вызывать рекурсивные функции в вычислительных выражениях и не получать исключение переполнения стека. Насколько я понимаю, это довольно известная проблема, но до сих пор не могу понять суть. Может быть, у кого-нибудь есть простые объяснения или примеры для этого.
Вот мой пример. Я хочу, чтобы построитель трассировки имел поведение, подобное seq
, но не работающее с монадой seq вместо какой-либо другой, например option
, и возвращало только последнее значение, отличное от None, из рекурсивного цикла. Является ли это возможным ?
Это всего лишь пример, код будет работать бесконечно, но не должно быть исключения stackowerflow.
Насколько я понимаю, проблема с переполнением стека в методе Combine, код просто продолжает вызывать функцию f () в рекурсивном цикле, и я хочу избежать этого и сделать этот хвост вызова рекурсивным, т.е. код должен компилироваться в обычном цикле. удар>
type TraceBuilder() =
member __.Bind (m: int Option, f: int -> int Option) : int Option =
match m with
| Some(v) -> f v
| None -> None
member this.Yield(x) = Some x
member this.YieldFrom(x) = x
member __.Delay(f) = f
member __.Run(f) = f()
member __.Combine (a, f) =
match a with
| Some _ -> a
| None -> f()
let trace = new TraceBuilder()
let rec iterRec (xopt: int Option) =
trace {
yield! None
let! x = xopt
yield! iterRec(Some(x + 1))
}
[<EntryPoint>]
let main argv =
let x = iterRec(Some(0))
//x = startFrom(0) |> Seq.take(5000) |> Seq.toList |> ignore
printfn "%A" x
Код мышления в комп. выражение должно быть скомпилировано
let iterRec xopt =
combine (None, (fun () ->
bind(xopt, fun x -> iterRec(Some(x+ 1)))
И похоже, что в этом случае вызов iterRec не является хвостовым рекурсивным, так что почему stackoveflow, возможно ли реализовать эту рекурсивную логику хвоста?
Прочтите эти ссылки, все еще не могу понять решение:
(Как) я могу сделать эту монадическую привязку хвостовой рекурсивной? < / а>
Вот предложение, как решить проблему с помощью FsControl lib, но можно ли решить проблему с помощью регулярных вычислительных выражений?
Рекурсивные функции в вычислительных выражениях
Предотвращение переполнения стека (с бесконечными последовательностями последовательностей F #)
https://fsharpforfunandprofit.com/posts/computation-expressions-builder-part5/ < / а>
f()
вCombine
уже хвостовой рекурсии. Не совсем понятно, в чем ваша проблема. Возможно, вам поможет, если вы сможете построить меньший пример. - person Fyodor Soikin   schedule 16.10.2016iterRec
функция мне кажется странной. В какой момент он когда-либо даст какое-либо значение, кроме None? Возможно, вам не хватает строкиyield x
сразу под строкойlet! x = xopt
? - person rmunn   schedule 17.10.2016iterRec
последний вызов функцииfun x -> iterRec( ... )
. Итак, у вас переполнение стека? Хорошо, теперь мы к чему-то приближаемся. Где ТАК происходит? Какая функция является точкой рекурсии? Также интересно: какая у вас ОС и время выполнения? - person Fyodor Soikin   schedule 17.10.2016