为什么我不能将这从Monad推广到Applicative?

时间:2013-10-27 00:01:03

标签: haskell monads applicative

我将hoistFree包中的free概括为hoistFreeM,类似于如何将fmap概括为Data.Traversable.mapM

import Control.Monad
import Control.Monad.Free
import Data.Traversable as T

hoistFreeM :: (Traversable g, Monad m) =>
              (forall a. f a -> m (g a)) -> Free f b -> m (Free g b)
hoistFreeM f = go
  where go (Pure x)  = return $ Pure x
        go (Free xs) = liftM Free $ T.mapM go =<< f xs

但是,我认为没有办法进一步推广它与任何Applicative一起使用,类似于如何将Data.Traversable.mapM概括为Data.Traversable.traverse。我对么?如果是这样,为什么?

1 个答案:

答案 0 :(得分:7)

你无法通过免费Monad解除申请人,因为Monad结构需要选择(通过(>>=)join),而Applicative无法提供。但是,也许不出所料,您可以通过免费申请提升申请人

-- also from the `free` package
data Ap f a where
  Pure :: a -> Ap f a
  Ap :: f a -> Ap f (a -> b) -> Ap f b

hoistAp :: (forall a. f a -> g a) -> Ap f b -> Ap g b
hoistAp _ (Pure a) = Pure a
hoistAp f (Ap x y) = Ap (f x) (hoistAp f y)

hoistApA :: Applicative v => (forall a. f a -> v (g a)) -> Ap f b -> v (Ap g b)
hoistApA _ (Pure a) = pure (Pure a)
hoistApA f (Ap x y) = Ap <$> f x <*> hoistApA f y

-- just what you'd expect, really

为了更明确一点,让我们尝试将hoistFreeM概括为hoistFreeA。这很容易开始

hoistFreeA :: (Traversable f, Applicative v) =>
              (forall a. f a -> v (g a)) -> Free f b -> v (Free g b)
hoistFreeA _ (Pure a) = pure (Pure a)

我们可以尝试在hoistFreeM处继续类推。 mapM变为traverse,我们可以达到

hoistFreeA f (Free xs) = ?f $ traverse (hoistFreeA f) xs

我一直在使用?f作为临时类型的洞来试图找出如何前进。如果可以的话,我们可以完成这个定义

?f :: v (f (Free g b)) -> v (Free g b)

换句话说,我们需要将f图层转换为g图层,同时生活在v图层下方。由于vv,所以很容易得到Functor,但我们必须将f a转换为g a的唯一方法是我们的​​参数函数{{ 1}}。

我们可以尝试将forall a . f a -> v (g a)f包装一起应用,以便折叠我们的Free图层。

g

但现在我们必须解决

hoistFreeA f (Free xs) = ?f . fmap (fmap Free . f) $ traverse (hoistFreeA f) xs

只是?f :: v (v (Free g b)) -> v (Free g b) ,所以我们被卡住了。这基本上是我们总会陷入困境的地方。免费Monads模型Monads,因此为了包裹它们,我们需要以某种方式joinjoin