I'm trying to understand how to invoke properly recursive functions in computational expressions and don't get stack overflow exception. As I understand this is quite known issue, but still can't grasp the concept. Maybe somebody have simple explanations or examples for this.
Here my the example
I want trace builder have behavior similar to seq
but not working with seq monad instead with some other one, for example option
and return only latest non None value from recursive loop. Is it possible ?
This is just example, code will run infinitely but there is shouldn't be stackowerflow exception
As I understand problem with stack overflow in Combine method, code just keep invoke f() function in recursive loop, and I want to avoid this and make
this invocation tail recursive, ie code should be compiled in regular loop.
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
Thinking code in comp. expression should is compiled
let iterRec xopt =
combine (None, (fun () ->
bind(xopt, fun x -> iterRec(Some(x+ 1)))
And looks like in this case iterRec invocation is not tail recursive, so whats why stackoveflow, is it possible to implement this logic tail recursive ?
Read these links, still can't figure out the solution :
(How) can I make this monadic bind tail-recursive?
Here suggestion how to resolve issue using FsControl lib, but is it possible to resolve issue using regular computational expressions ?
Recursive functions in computation expressions
Avoiding stack overflow (with F# infinite sequences of sequences)
https://fsharpforfunandprofit.com/posts/computation-expressions-builder-part5/
f()
inCombine
is already tail-recursive. It's not quite clear what your problem is. Perhaps it would help if you could construct a smaller example. – Fyodor Soikin