Add ChainRec type class
See original GitHub issueTailRec - A type class which captures stack-safe monadic tail recursion.
It would be nice to have a common specification for Tail Recursive Monads in JS community, so that libraries like Free could use the interface to be stack safe.
in PS MonadRec
type class looks like this:
class Monad m <= MonadRec m where
tailRecM :: forall a b. (a -> m (Either a b)) -> a -> m b
So we could have something like this without stack overflow:
Identity.tailRecM((n) => {
if (n == 0) {
return Identity(Either.Right("DONE"))
}
return Identity(Either.Left(n - 1))
})(20000)
one thing is that there are multiple Either
implementations in js and this spec should depend on bare minimum from any Either
type. from what I have found the minimum api from Either type is to have a cata
method. but before that let’s see an implementation of tailRecM
of Identity
:
const tailRec = (f) => (a) => {
let v = f(a)
while (!isDone(v)) {
v = f(getValue(v))
}
return getValue(v)
}
const runIdentity = (i) => i.x
Identity.tailRecM = (f) => (a) => Identity(tailRec((v) => runIdentity(f(v)))(a))
So we have seen usage of it and part of it’s implementation. now what we have left is implement isDone
and getValue
so that they are as generic as possible.
const isDone = (e) => e.cata({
Right: () => true,
Left: () => false,
})
const getValue = (e) => e.cata({
Right: (v) => v,
Left: (v) => v,
})
so as it looks any Either with cata
would work so users shouldn’t be tied to some particular Either implementation (as long as it has cata
).
To note this Either implementation would work with tailRecM
.
const Either = {
Right: (v) => ({ cata: (c) => c.Right(v) }),
Left: (v) => ({ cata: (c) => c.Left(v) }),
}
The hardest was to implement tailRecM
for Task/Future
but i have made it and after we agree on some interface I would create PRs for some popular Task/Future
implementations
Issue Analytics
- State:
- Created 7 years ago
- Comments:65 (63 by maintainers)
Top GitHub Comments
I like how we’ve managed to rope @garyb into this. Welcome to the darkside! 👋
Another option would be to provide the
Left
&Right
constructors as arguments to the function given totailRecM
.Which would look like the following to a user:
This has the advantage of avoiding naming things all together, though at the expense of being a little more difficult to describe in the spec.