Ответ 1
Закон левого сокращения (или ужесточения) говорит, что
mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)
В частности, это означает, что
mfix (\x -> a' >> f x) = a' >> mfix f
что означает, что монадическое действие внутри mfix
должно оцениваться ровно один раз. Это одно из основных свойств MonadFix
, которое ваша версия не удовлетворяет.
Рассмотрим этот пример, который создает циклический изменяемый список (пусть не учитывает тот факт, что вы можете сделать это без mfix
благодаря изменчивости):
import Control.Monad
import Control.Monad.Fix
import Data.IORef
data MList a = Nil | Cons a (IORef (MList a))
mrepeat :: a -> IO (MList a)
mrepeat x = mfix (liftM (Cons x) . newIORef)
main = do
(Cons x _) <- mrepeat 1
print x
С вашим вариантом mfix
вызов mrepeat
никогда не заканчивается, так как вы вызываете внутреннюю часть с помощью newIORef
неопределенно.