[英]Why can't I generalize this from Monad to Applicative?
我概括hoistFree
从免费包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
。 我对么? 如果是这样,为什么?
你不能通过免费Monad解除Applicative,因为Monad结构需要选择(via (>>=)
或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
是一个Functor
,因此很容易得到v
,但是我们必须将fa
转换为ga
的唯一方法是我们的参数函数forall a . fa -> v (ga)
forall a . fa -> v (ga)
。
我们可以尝试将该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)
这只是join
,所以我们被困住了。 这基本上是我们总会陷入困境的地方。 免费Monads模型Monads因此为了包裹它们我们需要以某种方式join
或bind
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.