假设我有一个功能
f :: State [Int] Int
和一个功能:
g :: StateT [Int] IO Int
我想在f
中使用g
并在它们之间传递状态。是否有图书馆功能
StateT (return . runState f)
?或者一般来说,给定一个具有相应monad的monad变换器,它有一个库函数吗?
答案 0 :(得分:5)
更一般地说,您要做的是将变换应用于变换器堆栈的内层。对于两个任意monad,类型签名可能如下所示:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a
基本上是更高级fmap
。事实上,将它与最终参数上的地图相结合可能更有意义:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b
显然,在所有情况下都不可能实现这一点,但是当“源”monad为Identity
时,它可能会更容易,但我可以想象为它确实起作用的地方定义另一个类型类。我不认为在典型的monad变压器库中有这样的东西;然而,一些浏览hackage的东西非常相似in the Monatron
package:
class MonadT t => FMonadT t where
tmap' :: FunctorD m -> FunctorD n -> (a -> b)
-> (forall x. m x -> n x) -> t m a -> t n b
tmap :: (FMonadT t, Functor m, Functor n) => (forall b. m b -> n b)
-> t m a -> t n a
tmap = tmap' functor functor id
在tmap'
的签名中,FunctorD
类型基本上是fmap
的临时实施,而不是直接使用Functor
个实例。
此外,对于两个类似Functor的类型构造函数F和G,类型为(forall a. F a -> G a)
的函数描述了从F到G的a natural transformation。很可能是你想要的变换器映射的另一个实现在category-extras
包中的某个地方,但我不确定monad变换器的类别理论版本是什么,所以我不知道它可能被称为什么。
由于tmap
只需要Functor
个实例(任何Monad
必须拥有的)和自然转换,并且任何Monad
都有{{1}的自然转换由Identity
提供的monad,你想要的函数可以作为return
的任何实例一般编写为FMonadT
- 假设“基本”monad被定义为变换器的同义词无论如何都应用于tmap (return . runIdentity)
,这通常是变压器库的情况。
回到您的具体示例,请注意,Monatron确实为Identity
提供了FMonadT
的实例。
答案 1 :(得分:4)
对于所有monad变换器来说,这样的功能是不可定义的。例如,Cont r
monad无法被提升到ContT r IO
,因为这需要将IO monad(a -> IO r
)中的延续变为纯粹的延续(a -> r
)。
答案 2 :(得分:4)
您要求的是从monad StateT m
到StateT n
的映射(称为monad态射)。我将使用mmorph
库,它提供了一组非常好的工具来处理monad态射。
要执行您正在寻找的State -> StateT m
转换,我们首先定义一个态射,以概括Identity
中嵌入的State
monad,
generalize :: Monad m => Identity a -> m a
generalize = return . runIdentity
接下来,我们要提升这种态度来对你StateT
的内部monad采取行动。也就是说,我们想要一个给出从一个monad到另一个monad的映射的函数(例如我们的generalize
态射),它将给我们一个作用于monad变换器的基monad的函数,例如: t Identity a -> t m a
。您会发现这类似于hoist
的{{1}}类的mmorph
函数,
MFunctor
把各个部分放在一起,
hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b