KnowledgeHub
Questions
Tags
Users
Search
Alex Rivera
|
Logout
Edit Question
Title
Body
Disclosure: this came up in FsCheck, an F# random testing framework I maintain. I have a solution, but I do not like it. Moreover, I do not understand the problem - it was merely circumvented. A fairly standard implementation of (monadic, if we're going to use big words) sequence is: let sequence l = let k m m' = gen { let! x = m let! xs = m' return (x::xs) } List.foldBack k l (gen { return [] }) Where gen can be replaced by a computation builder of choice. Unfortunately, that implementation consumes stack space, and so eventually stack overflows if the list is long enough.The question is: why? I know in principle foldBack is not tail recursive, but the clever bunnies of the F# team have circumvented that in the foldBack implementation. Is there a problem in the computation builder implementation? If I change the implementation to the below, everything is fine: let sequence l = let rec go gs acc size r0 = match gs with | [] -> List.rev acc | (Gen g)::gs' -> let r1,r2 = split r0 let y = g size r1 go gs' (y::acc) size r2 Gen(fun n r -> go l [] n r) For completeness, the Gen type and computation builder can be found in the FsCheck source
Tags (comma-separated)
Save Edits
Cancel