
So that's also why the fix function from Data.Function is defined as
fix f = let x = f x in x
instead of
fix f = f $ fix f
right? But, I think my mfix definition and your mfixLazy definition are still semantically equivalent because they expand to the same thing. See the following example:
import Control.Monad.Identity
-- Strict Identity monad data IdentityS a = IdentityS { runIdentityS :: a } deriving Show instance Monad IdentityS where return = IdentityS (IdentityS m) >>= k = k m
mfix' f = mfix' f >>= f mfixLazy f = let x = x >>= f in x
facFM f = return (\i -> if i == 0 then 1 else i * f (i - 1) )
-- correctly outputs 3! = 6 test = runIdentity (mfix facFM) 3
-- stack overflows test2 = runIdentityS (mfix' facFM) 3
-- hangs test3 = runIdentityS (mfixLazy facFM) 3
Thanks for pointing out the sharing part. My original question is still unanswered: for lazy monads, can we give such a general mfix definition?