fmap for Monads often defaults to liftM:
liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1 = do { x1 <- m1; return (f x1) }
Yet, as one can see it uses binding (as the right hand desugars into m1 >>= \ x1 -> return (f x1)). I wonder whether such a fmap can be used for writing down mfix down for monads which have a strict >>= operator. To be more precise, I wonder about the following implementation with Control.Arrow.loop (again).
The monad I use is Identity, yet it forces whatever is inside it whenever binding takes place with seq.
newtype Id' a = Id' { runId' :: a } deriving ...
instance Functor Id' where
fmap = liftM -- instead of `f <$> (Id' x) = Id' (f x)`.
instance Applicative Id' where
pure = return
(<*>) = ap
instance Monad Id' where
return = Id'
(Id' x) >>= k = x `seq` k x
instance MonadFix Id' where
mfix f = let a = f (runId' a) in a
myMfix :: MonadFix m => (a -> m a) -> m a
myMfix k = let f ~(_, d) = ((,) d) <$> k d
in (flip runKleisli () . loop . Kleisli) f
My intuition is yes, it can be used. I reckon that we run into problems only in two cases:
kwe applymfix/myMfixto is strict.- We apply
mfix/myMfixtoreturn.
Both cases are fairly simple and we do not expect any converging result in the first place. I believe that other cases could be forced to WHNF without forcing the feedback.
Is my intuition correct? If not, can one show an example where it fails?