【问题标题】:Is there an instance of Monad but not of MonadFix?是否有 Monad 的实例但没有 MonadFix 的实例?
【发布时间】:2014-11-06 23:58:22
【问题描述】:
问题主要在标题中。似乎mfix 可以为任何一元计算定义,即使它可能会发散:
mfix :: (a -> m a) -> m a
mfix f = fix (join . liftM f)
这个结构有什么问题?另外,为什么Monad 和MonadFix 类型类是分开的(即,什么类型有Monad 的实例,但没有MonadFix 的实例)?
【问题讨论】:
标签:
haskell
monads
monadfix
【解决方案1】:
left shrinking (or tightening) law says那个
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 调用内部部分。
【解决方案2】:
不保证您对mfix 的定义等同于标准定义。事实上,至少在 list 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.