在 Haskell 中编写嵌套的 Monad
Compose nested Monads in Haskell
有没有办法为嵌套的 monad 实现绑定?我要的是下面的签名:
(>>>=) :: (Monad m, Monad n) => m (n a) -> (a -> m (n b)) -> m (n b)
看起来这应该是一项微不足道的任务,但我不知何故就是无法理解它。在我的程序中,我将这种模式用于几种不同的 monad 组合,并且对于每种组合,我都可以实现它。但是对于一般情况,我就是看不懂。
编辑:似乎在一般情况下是不可能的。但在某些特殊情况下肯定是可以的。例如。如果内部 Monad 是 Maybe。因为我想使用的所有 Monad 都是可能的,所以有额外的限制对我来说似乎很好。所以我稍微改变一下问题:
我需要对 n 进行哪些额外约束才能实现以下条件?
(>>>=) :: (Monad m, Monad n, ?? n) => m (n a) -> (a -> m (n b)) -> m (n b)
扩展评论:如 linked 所示,有必要具有一些功能 n (m a) -> m (n a)
甚至有机会使组合成为 monad。
如果你的inner monad是一个Traversable
,那么sequence
提供了这样一个函数,下面就会有正确的type:
(>>>=) :: (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)
几个著名的转换器实际上是简单的新类型包装器,对等同于此的东西进行包装(尽管大多数情况下使用模式匹配来定义事物,而不是字面上使用内部 monad 的 Monad
和 Traversable
实例) :
MaybeT
基于 Maybe
ExceptT
基于 Either
WriterT
基于 (,)
((,)
通常没有定义其 Monad
实例, 和 WriterT
正在使用错误的元组顺序来使用它,如果它有的话 - 但在精神上它可能有)。
ListT
基于 []
。哦,哎呀...
最后一个实际上是臭名昭著的,因为 不是 是单子,除非提升的单子是 "commutative" - 否则,根据单子法则应该相等的表达式可以给出不同顺序的效果。我的直觉是,这主要来自能够包含多个值的列表,这与其他可靠工作的示例不同。
所以,虽然上面的定义类型是正确的,它仍然可以打破单子法则。
另外一个事后的想法是,另一个转换器就是这样一个嵌套的 monad,但是以完全不同的方式:ReaderT
,基于使用 (->)
作为 outer单子。
有没有办法为嵌套的 monad 实现绑定?我要的是下面的签名:
(>>>=) :: (Monad m, Monad n) => m (n a) -> (a -> m (n b)) -> m (n b)
看起来这应该是一项微不足道的任务,但我不知何故就是无法理解它。在我的程序中,我将这种模式用于几种不同的 monad 组合,并且对于每种组合,我都可以实现它。但是对于一般情况,我就是看不懂。
编辑:似乎在一般情况下是不可能的。但在某些特殊情况下肯定是可以的。例如。如果内部 Monad 是 Maybe。因为我想使用的所有 Monad 都是可能的,所以有额外的限制对我来说似乎很好。所以我稍微改变一下问题:
我需要对 n 进行哪些额外约束才能实现以下条件?
(>>>=) :: (Monad m, Monad n, ?? n) => m (n a) -> (a -> m (n b)) -> m (n b)
扩展评论:如 linked n (m a) -> m (n a)
甚至有机会使组合成为 monad。
如果你的inner monad是一个Traversable
,那么sequence
提供了这样一个函数,下面就会有正确的type:
(>>>=) :: (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)
几个著名的转换器实际上是简单的新类型包装器,对等同于此的东西进行包装(尽管大多数情况下使用模式匹配来定义事物,而不是字面上使用内部 monad 的 Monad
和 Traversable
实例) :
MaybeT
基于Maybe
ExceptT
基于Either
WriterT
基于(,)
((,)
通常没有定义其Monad
实例, 和WriterT
正在使用错误的元组顺序来使用它,如果它有的话 - 但在精神上它可能有)。ListT
基于[]
。哦,哎呀...
最后一个实际上是臭名昭著的,因为 不是 是单子,除非提升的单子是 "commutative" - 否则,根据单子法则应该相等的表达式可以给出不同顺序的效果。我的直觉是,这主要来自能够包含多个值的列表,这与其他可靠工作的示例不同。
所以,虽然上面的定义类型是正确的,它仍然可以打破单子法则。
另外一个事后的想法是,另一个转换器就是这样一个嵌套的 monad,但是以完全不同的方式:ReaderT
,基于使用 (->)
作为 outer单子。