Recursion of functions that directly have a HasCallStack constraint can grow the stack really fast. This makes the stack both hard to read as well as creates up an enormous amount of thunks. If you do end up forcing the CallStack, its even worse as you have to now print the giant thing...
Instead, recursive calls should have an inner worker function that does not have to constraint, but captures it in a closure. Alternatively, a helper function may be used that gets the CallStack data type instead of the HasCallStack implicit parameter (kind of like a typeclass). This last solution would also work for mutually recursive functions. Do note that they would need to call withCallstack cs immediately to ensure that calls other than the mutually recursive one do end up on the callstack!
Recursion of functions that directly have a
HasCallStackconstraint can grow the stack really fast. This makes the stack both hard to read as well as creates up an enormous amount of thunks. If you do end up forcing theCallStack, its even worse as you have to now print the giant thing...Instead, recursive calls should have an inner worker function that does not have to constraint, but captures it in a closure. Alternatively, a helper function may be used that gets the
CallStackdata type instead of theHasCallStackimplicit parameter (kind of like a typeclass). This last solution would also work for mutually recursive functions. Do note that they would need to callwithCallstack csimmediately to ensure that calls other than the mutually recursive one do end up on the callstack!