可以为“免费”实现MonadFix吗?

时间:2013-01-31 22:07:16

标签: haskell monadfix free-monad

Control.Monad.Free.Free中的

http://hackage.haskell.org/package/free允许用户访问任何给定Functor的“免费monad”。但是,它没有MonadFix个实例。这是因为这样的实例无法编写,还是只是被遗漏了?

如果不能写这样的实例,为什么不呢?

3 个答案:

答案 0 :(得分:14)

考虑mfix做什么的描述:

  

monadic计算的固定点。 mfix f仅执行一次操作f,最终输出作为输入反馈。

Free的上下文中,“执行”一词意味着创建Functor的图层。因此,“只有一次”意味着在评估mfix f的结果中,Pure构造函数中保存的值必须完全确定创建了多少层仿函数。

现在,假设我们有一个特定的函数once,我们知道它总是只创建一个Free构造函数,但是需要很多Pure构造函数来保存叶值。那么,'once'的输出将只是Free f a类型的值,它们与f a类型的某些值同构。有了这些知识,我们可以安全地取消Free once的输出,以获得f a类型的值。

现在,请注意,因为mfix只需要“执行一次”操作,因此对于符合要求的实例,mfix once的结果不应包含除once之外的其他monadic结构在单个应用程序中创建。因此,我们可以推断从mfix once获得的值也必须与f a类型的值同构。

对于某些a -> f a Functor,如果给出f类型的任何函数,我们可以使用单个Free包装结果并获取类型为a -> Free f a的函数它满足上面once的描述,我们已经确定我们可以打开mfix once的结果来获得类型f a的值。

因此,符合条件的实例(Functor f) => MonadFix (Free f)意味着能够通过上述包装和展开来编写适用于ffix :: (Functor f) => (a -> f a) -> f a的所有实例的函数Functor

这显然不是无法编写此类实例的证明......但如果可能,MonadFix将完全是多余的,因为您可以轻松地写ffix直接。 (我想使用mfix重新实现Monad liftM约束,使用{{1}}。呃。)

答案 1 :(得分:5)

好吧,受到MonadFix Maybe实例的启发,我尝试了这个实例(使用Free的以下定义):

data Free f a
    = Pure a
    | Impure (f (Free f a))

instance (Functor f) => Monad (Free f) where
    return = Pure
    Pure x >>= f = f x
    Impure x >>= f = Impure (fmap (>>= f) x)

instance (Functor f) => MonadFix (Free f) where
    mfix f = let Pure x = f x in Pure x

The laws是:

  • 纯度:mfix (return . h) = return (fix h)
  • 左萎缩:mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)
  • 滑动:mfix (liftM h . f) = liftM h (mfix (f . h)),严格h
  • 嵌套:mfix (\x -> mfix (f x)) = mfix (\x -> f x x)

纯度很容易证明 - 但是当我试图证明左萎缩时我遇到了一个问题:

mfix (\x -> a >>= \y -> f x y)
= let Pure x = (\x -> a >>= \y -> f x y) x in Pure x
= let Pure x = a >>= \y -> f x y in Pure x
-- case a = Pure z
  = let Pure x = Pure z >>= \y -> f x y in Pure x
  = let Pure x = f x z in Pure x
  = let Pure x = (\x -> f x z) x in Pure x
  = mfix (\x -> f x z)
  = Pure z >>= \y -> mfix (\x -> f x y)
-- case a = Impure t
  = let Pure x = Impure t >>= \y -> f x y in Pure x
  = let Pure x = Impure (fmap (>>= \y -> f x y) t) in Pure x
  = Pure _|_

  Impure t >>= \y -> mfix (\x -> f x y)
  = Impure (fmap (>>= \y -> mfix (\x -> f x y)) t)
  /= Pure _|_

所以,至少,如果PureImpure构造函数是可区分的,那么mfix的实现不符合法律。我想不出任何其他实现,但这并不意味着它不存在。对不起,我无法进一步说明。

答案 2 :(得分:3)

不,它一般不能写,因为不是每个Monad都是MonadFix的实例。 每个Monad都可以使用下面的FreeMonad实现。如果您可以免费实现MonadFix,那么您将能够从任何Monad派生MonadFix,这是不可能的。 但是,当然,您可以为MonadFix类定义FreeFix。

我认为它可能看起来像这样,但这只是第三次猜测(仍未经过测试):

data FreeFix m a = FreeFix { runFreeFix :: (forall r. (r -> m r) -> m r) -> m a }

instance (Monad m) => Monad (FreeFix m) where
    return a = FreeFix $ \_-> do
        return a
    f >>= g = FreeFix $ \mfx -> do
        x <- runFreeFix f mfx
        runFreeFix (g x) mfx

instance (Monad m) => MonadFix (FreeFix m) where
    mfix f = FreeFix $ \mfx -> do
        mfx (\r->runFreeFix (f r) mfx)

这个想法是m是Monad,缺少mfix的实现;所以当FreeFix减少时,mfix必须是一个参数。