结合StateT和State monads

时间:2010-11-09 21:10:33

标签: haskell monads monad-transformers state-monad

假设我有一个功能

f :: State [Int] Int

和一个功能:

g :: StateT [Int] IO Int

我想在f中使用g并在它们之间传递状态。是否有图书馆功能 StateT (return . runState f)?或者一般来说,给定一个具有相应monad的monad变换器,它有一个库函数吗?

3 个答案:

答案 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 mStateT 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