The transformers implementation of MonadFix for MaybeT fails if the function ever evaluates to Nothing. Why is Nothing not propagating over mfix?
mfix' :: MonadFix m => (a -> MaybeT m a) -> MaybeT m a
mfix' f = MaybeT $ mfix $ \case
Nothing -> return Nothing
Just x -> runMaybeT $ f x
There must be a good reason that I do not see because ListT does not implement MonadFix at all, and Maybe implements it in the same way as above.
I think the issue is just that the
errormessage is misleading. Let's just focus onMonadFix Maybe. The argument tomfixcan be one of four things.It can be strict in the input:
f _|_ = _|_or "fneeds to evaluate its input to decide whether it will returnNothingorJust"It can be
const Nothing.It can be
Just . fwherefis not strict.It can be
Just . fwherefis strict.If the function is strict, then the whole thing blows up in an infinite loop (just like
fix), and the error isn't seen because we don't know whether we would have had aNothingor aJust. If it isconst Nothing, the function never actually tries to evaluate theerrorand nothing happens. If it isJust . fandfis not strict, then it's justJust $ fix f(as per the laws:mfix $ return . f = return $ fix f). And, iffis strict, we getJust _|_(again, per the laws). Notice that we never see theerrortriggered.Similar reasoning works for
MonadFix (MaybeT m). I think this time it's better just with an example:Each of the four cases I listed above are in that list. The first element of the result is an infinite loop. The second is
Nothing. The third isrepeat 1, and the fourth isJustan infinite loop. Trying to access the "elements" beyond that triggers another infinite loop, this time caused by[]'sMonadFixand notMaybeT's. Again, I don't believe it's possible to trigger theerror, because the function would have to force the argument after already deciding that the result wasNothing.