在Haskell中编写嵌套的Monads

Lyk*_*kos 6 monads haskell

有没有办法为嵌套monad实现bind?我想要的是以下签名:

(>>>=) :: (Monad m, Monad n) => m (n a) -> (a -> m (n b)) -> m (n b)
Run Code Online (Sandbox Code Playgroud)

它看起来应该是一项微不足道的任务,但我不知何故无法绕过它.在我的程序中,我将这种模式用于monad的几种不同组合,对于每种组合,我都可以实现它.但对于一般情况,我只是不明白.

编辑:似乎在一般情况下不可能.但在某些特殊情况下肯定是可能的.例如,如果内在的Monad是一个Maybe.因为我想要使用的所有Monads都可以使用,所以有额外的限制似乎对我来说很好.所以我稍微改变了一下这个问题:

我需要对n进行哪些额外限制,以便可以进行以下操作?

(>>>=) :: (Monad m, Monad n, ?? n) => m (n a) -> (a -> m (n b)) -> m (n b)
Run Code Online (Sandbox Code Playgroud)

Ørj*_*sen 7

扩展评论:如链接的 问题所示,有必要有一些功能n (m a) -> m (n a)甚至有机会使合成成为monad.

如果你的内部monad是a Traversable,那么sequence提供这样一个函数,以下将具有正确的类型:

(>>>=) :: (Monad m, Monad n, Traversable n) => m (n a) -> (a -> m (n b)) -> m (n b)
m >>>= k = do
    a <- m
    b <- sequence (map k a)
    return (join b)
Run Code Online (Sandbox Code Playgroud)

事实上,几个众所周知的变换器实际上是简单的newtype包装器,而不是相当于它的东西(虽然主要用模式匹配来定义事物而不是字面上使用内部monad' MonadTraversable实例):

  • MaybeT 基于 Maybe
  • ExceptT 基于 Either
  • WriterT基于(,)((,)通常没有Monad定义它的实例, WriterT使用错误的元组顺序来使用它,如果它有 - 但在精神上它可能有).
  • ListT基于[].噢,哎呦 ......

最后一个实际上因为不是单子而臭名昭着,除非被提升的单子是"可交换的" - 否则,单子法应该相等的表达可以给出不同的效果顺序.我的预感是,这主要来自列表能够包含多个值,而不像其他可靠的工作示例.

因此,虽然上面的定义将被正确输入,但它仍然可以打破monad定律.

也作为一种事后,一种其它变压器是这样嵌套单子,但在一个完全不同的方式:ReaderT基于使用(->)作为单子.