Description
Description
Add a StackSafeMonad
subclass of Monad
, and move requirement for tailRecM
from Monad
to StackSafeMonad
.
Why?
If I'm writing a new custom Monad, tailRecM
is usually the trickiest part to implement. By separating it in another typeclass I can start by writing an instance for Monad
and leave tailRecM
for later.
It can also be helpful for people that are trying to get their head around Monad
for the first time: they will be able to first learn how to implement and use flatMap
and leave the trickier tailRecM
for later.
Counter arguments
Scala's Cats mantainers chose to keep both tailRecM
and flatMap
requirements for Monad
.
One argument was that they didn't want to have every method currently using tailRecM
duplicated in a stack safe and a non stack safe version. I don't think this is a big problem here, since in Bow
we only use tailRecM
in Free.foldMap
, and we can just require a StackSafeMonad
instance. Also, it's ok to not offer non stack safe versions of those methods, at the end, the goal of this PR is not add support for monads that cannot be made tail recursive, but to allow quicker prototyping and learning by allowing users of the library to implement tailRecM
later. We kinda "expect" that tailRecM
will be implement anyway at some point in time to leverage all the functionality on a monad you write.
Another argument they make is that people might use flatMap
for recursion because they don't have tailRecM
available. But people might as well use flatMap
even when tailRecM
is available! In my opinion, what we need to do is add good docs explaining the issue with flatMap
based recursion, rather than trying to "protect" our users.
Modules
Bow
Breaking changes
All current Monads
will be StackSafeMonad
, they'll have tailRecM
but no explicit conformance to StackSafeMonad
. The only thing that will brake until a StackSafeMonad
conformance is added for a particular type is the tailRecM
shortcut in Kind
.