18

可以说我有一个功能

f :: State [Int] Int

和一个功能:

g :: StateT [Int] IO Int

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

4

3 回答 3

5

StateT m您要的是从 monad到的映射(称为 monad 态射)StateT n。我将使用这个mmorph库,它提供了一组非常好的工具来处理单子态射。

为了执行State -> StateT m您正在寻找的转换,我们将首先定义一个态射来概括Identity嵌入的 monad State

generalize :: Monad m => Identity a -> m a
generalize = return . runIdentity

接下来我们要提升这个态射来作用于你的内部单子StateT。也就是说,我们想要一个函数,它给出从一个单子到另一个单子的映射(例如我们的generalize态射),将给我们一个作用于单子转换器的基本单子的函数,例如t Identity a -> t m a。你会发现这类似于's类的hoist功能,mmorphMFunctor

hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b

将碎片拼凑在一起,

myAction :: State s Int
myAction = return 2

myAction' :: Monad m => StateT s m Int
myAction' = hoist generalize myAction
于 2013-08-19T22:10:20.510 回答
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

显然,这并非在所有情况下都是可能的,尽管当“源”monadIdentity可能更容易时,但我可以想象为它工作的地方定义另一个类型类。我认为典型的 monad 转换器库中没有这样的东西。然而,一些关于 hackage 的浏览在包中发现了一些非常相似Monatron东西:

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

在 for 的签名中tmap'FunctorD类型基本上是临时实现,fmap而不是直接使用Functor实例。

此外,对于两个类似 Functor 的类型构造函数 F 和 G,具有 like 类型的函数(forall a. F a -> G a)描述了从 F 到 G 的自然转换。很可能在包中的某处您想要的转换器映射的另一种实现,category-extras但我不确定monad 转换器的类别理论版本是什么,所以我不知道它可能被称为什么。

由于tmap只需要一个Functor实例( anyMonad必须具有)和一个自然转换,并且 anyMonad具有从Identity提供的 monad的自然转换,因此可以为 as的return任何实例一般地编写您想要的函数—— 假设“基本”monad 是无论如何,定义为应用于 的转换器的同义词,转换器库通常就是这种情况。FMonadTtmap (return . runIdentity)Identity

回到您的具体示例,请注意 Monatron 确实有一个FMonadTfor的实例StateT

于 2010-11-09T21:41:27.133 回答
4

并非所有单子转换器都可以定义这样的功能。Cont r例如,不能提升 monad,因为这ContT r IO需要将 IO monad ( a -> IO r) 中的延续转换为纯延续 ( a -> r)。

于 2010-11-09T21:33:59.620 回答