Haskell 中的函数映射到 MonadTrans?

Function in Haskell to map over a MonadTrans?

我最近决定开始使用 monad 转换而不是堆叠我的 monad,因为这似乎是正确的做法。无论如何,我之前并没有真正堆叠很多单子。我得到(我认为)它背后的想法和 lift 函数,据我所知,它作为一种 return 用于转换(将底层 monad 中的某些东西放入转换后的 monad ).

到目前为止一切顺利,但我没有看到任何与 monad 转换的 fmap 函数类似的东西。让我举一个例子。假设我有一个自定义 monad,m,我在其上使用 StateT 转换,因此使用类型 StateT s m a 而不是 m (State s a).

现在,碰巧在我的 monad m 中,我有一个转换 monadic 元素的函数(实际上它是 monad 的构造函数之一,如果您需要详细信息,我可以提供)同时在某种意义上保持基本值:myFunc :: m a -> m a.

所以我正在构建一个递归函数 recFunc :: State s a -> [t] -> m (State s a),它看起来类似于这样的东西:

recFunc :: State s a -> [t] -> m (State s a)
recFunc x [] = return x
recFunc x (t:ts) = myFunc (recFunc x ts)

但是如果我尝试使用 monad 转换来复制它,我 运行 就会遇到问题,因为我找不到将 myFunc 插入到混合中的方法。将输入写成 State s a 还是 StateT s Identity a 都没有关系(代数上哪个更精确?)

recFuncT :: StateT s Identity a -> [t] -> StateT s m a
recFuncT x [] = ???
recFuncT x (t:ts) = ????? where rec = recFuncT x ts

所以我正在寻找的是(发明的,如果可能的话我不知道如何实现)以下功能:

transmap :: (MonadTrans t, Monad m) => (forall b. m b -> m b) -> t m a -> t m a
transmap = ???

transreturn :: (MonadTrans t, Monad m) => m (t Identity a) -> t m a
transreturn = ???

我觉得我应该能够使用 lift 来定义这些,但老实说,我不知道如何定义。

如果我有它们,那么我可以这样做:

recFuncT :: StateT s Identity a -> [t] -> StateT s m a
recFuncT x [] = transreturn (return x)
recFuncT x (t:ts) = transmap myFunc (recFuncT x ts)

也许我真正想要的是更基本的东西。我希望 t m am (t Identity a) 之间假定的同构是明确的,所以我正在寻找函数:

fromTrans :: t m a -> m (t Identity a)
toTrans :: m (t Identity a) -> t m a

据我了解 monad 转换器,这些函数应该始终存在并且相当简单,对吧?

有了这些我显然可以实现 transmaptransreturn:

transmap :: (MonadTrans t, Monad m) => (forall b. m b -> m b) -> t m a -> t m a
transmap f x = toTrans (f (fromTrans x))

transreturn :: (MonadTrans t, Monad m) => m (t Identity a) -> t m a
transreturn = toTrans

我确信我忽略了一些明显的东西。请帮我指出来。

谢谢。

从评论中的讨论来看,听起来您真正想要的是用于自定义 monad 的 monad 转换器,然后将其应用于基本 monad State。换句话说,如果您的自定义 monad 是 "nearly" 列表:

newtype Listish a = Listish [a]

其转换器版本的类型为:

newtype ListishT m a = ListishT [m a]

因此您最终的 monad 转换器堆栈将是:

type M s = ListishT (State s)

与你的 monad 堆栈同构

[State s a]  AKA  Listish (State s a)

但是,请确保不要过度概括从底层 monad 创建转换器的模式。而一些单子的变形金刚:

newtype List a = List [a]
newtype Reader r a = Reader (r -> a)

通过将“a”替换为“m a”来明智地派生:

newtype ListT m a = ListT [m a]
newtype ReaderT r m a = ReaderT (r -> m a)

其他类型的变形金刚的派生方式不同。例如:

newtype State s a = State (s -> (a, s))
newtype Writer w a = Writer (a, w)

给予:

newtype StateT s a = StateT (s -> m (a, s))
-- **NOT** StateT (s -> (m a, s))
newtype WriterT s a = WriterT (m (a, w))
-- **NOT** WriterT (m a, w)

特别是 IO 没有 monad 转换器,因为简单的替换

newtype BadIOT m a = BadIOT (IO (m a))

正如您指出的那样,这很愚蠢。

编辑:以下所有内容都没有意义。我留下删除线。下面的答案很好。

郑重声明,我的最终解决方案既不使用也不实现 monad 转换器,而是简单地实现以下函数:(我的自定义 monad 称为 EnumProc):

(..>>=) :: Monad m => EnumProc (m a) -> (a -> m b) -> EnumProc (m b)
en ..>>= f = en <$> (>>= f)
infixl 7 ..>>=

这使我能够在保持外部 monad 结构的同时处理 monad 内部的 monadic 计算。 fmap 就够了,我自己也很惊讶。

然后我使用 EnumProc (State s a) 作为类型。

过了一会儿,我终于想出了我从一开始就在寻找的东西。我可以完全按照我想要的方式使用 StateT,并且它具有我认为的语义,但我没有很好地解释它(并在我写的地方写错了)。

回到我原来的 post,我不需要 State 作为输入,State/StateT monad 已经在 monadic 元素中包含了输入.所以我需要的是一个函数recFuncT :: [t] -> StateT s m a,它的行为等同于以下非变压器函数:

recFunc :: a -> [t] -> m (State s a)
recFunc x [] = return (return x)
recFunc x (t:ts) = myFunc (recFunc x ts)

可以直接实现,使用构造函数StateTrunStateT。在这里:

recFuncT :: a -> [t] -> StateT m s a
recFuncT x [] = return x
recFuncT x (t:ts) = StateT (\s -> myFunc (runStateT (recFuncT x ts) s))

另外,函数transmap也可以实现一般,至少StateT:

transmap :: Monad m => (forall b. m b -> m b) -> StateT s m a -> StateT s m a
transmap f st = StateT (\s -> f (runStateT st s)

然后我们可以用它写 recFuncT:

recFuncT :: a -> [t] -> StateT m s a
recFuncT x [] = return x
recFuncT x (t:ts) = transmap myFunc (recFuncT x ts)

我意识到这与我最初包含的代码并不完全匹配,但它确实符合我试图诉诸的总体原则,即 StateT 转换器就像向我的 monad 添加状态m,因此在 m (State s a) 级别可以完成的任何事情都可以在 StateT s m a 级别完成。

您正在寻找的一个概念似乎可以在 mmorph 包中找到:

class MFunctor t where
  -- The argument is generally required to be a monad morphism,
  -- but some instances will work sensibly when it's not.
  hoist :: Monad m => (forall x. m x -> n x) -> t m a -> t n a

这比您的版本更通用一些,因为它允许替换底层的 monad。