我将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
。我对么?如果是这样,为什么?
答案 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
图层下方。由于v
是v
,所以很容易得到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,因此为了包裹它们,我们需要以某种方式join
或join
。