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:
k
we applymfix
/myMfix
to is strict.- We apply
mfix
/myMfix
toreturn
.
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?