Monad有没有MonadFix的实例?

时间:2014-09-12 18:23:09

标签: haskell monads monadfix

问题主要在标题中。似乎可以为任何monadic计算定义mfix,即使它可能有所不同:

mfix :: (a -> m a) -> m a
mfix f = fix (join . liftM f)

这种结构有什么问题?另外,为什么MonadMonadFix类型类别是分开的(即什么类型的实例为Monad而不是MonadFix?)

2 个答案:

答案 0 :(得分:16)

<{3}}

mfix (\x -> a >>= \y -> f x y)  =  a >>= \y -> mfix (\x -> f x y)

特别是这意味着

mfix (\x -> a' >> f x)  =  a' >> mfix f

这意味着mfix内的monadic动作必须只评估一次。这是您的版本无法满足的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调用内部部分。

答案 1 :(得分:6)

您对mfix的定义不能保证等同于标准的定义。事实上,至少在monad列表中它更严格:

> take 1 $ mfix (\x -> [1,x])
[1]
> let mfix2 :: Monad m => (a -> m a) -> m a; mfix2 f = fix (join . liftM f)
> take 1 $ mfix2 (\x -> [1,x])
Interrupted.