简体   繁体   English

在Haskell中编写嵌套的Monads

[英]Compose nested Monads in Haskell

Is there a way to implement bind for nested monads? 有没有办法为嵌套monad实现bind? What I want is the following signature: 我想要的是以下签名:

(>>>=) :: (Monad m, Monad n) => m (n a) -> (a -> m (n b)) -> m (n b)

It looks like it should be a trivial task, but I somehow just can't wrap my head around it. 它看起来应该是一项微不足道的任务,但我不知何故无法绕过它。 In my program, I use this pattern for several different combinations of monads and for each combination, I can implement it. 在我的程序中,我将这种模式用于monad的几种不同组合,对于每种组合,我都可以实现它。 But for the general case, I just don't understand it. 但对于一般情况,我只是不明白。

Edit: It seems that it is not possible in the general case. 编辑:似乎在一般情况下不可能。 But it is certainly possible in some special cases. 但在某些特殊情况下肯定是可能的。 Eg if the inner Monad is a Maybe. 例如,如果内在的Monad是一个Maybe。 Since it IS possible for all the Monads I want to use, having additional constraints seems fine for me. 因为我想要使用的所有Monads都可以使用,所以有额外的限制似乎对我来说很好。 So I change the question a bit: 所以我稍微改变了一下这个问题:

What additional constraints do I need on n such that the following is possible? 我需要对n进行哪些额外限制,以便可以进行以下操作?

(>>>=) :: (Monad m, Monad n, ?? n) => m (n a) -> (a -> m (n b)) -> m (n b)

Expanding on the comments: As the linked questions show, it is necessary to have some function n (ma) -> m (na) to even have a chance to make the composition a monad. 扩展评论:如链接 问题所示,有必要使用某个函数n (ma) -> m (na)甚至有机会使合成成为monad。

If your inner monad is a Traversable , then sequence provides such a function, and the following will have the right type : 如果你的内部monad是一个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)

Several well-known transformers are in fact simple newtype wrappers over something equivalent to this (although mostly defining things with pattern matching instead of literally using the inner monads' Monad and Traversable instances): 几个着名的变换器实际上是简单的newtype包装器,而不是相当于它的东西(虽然主要用模式匹配来定义事物而不是字面上使用内部monad的MonadTraversable实例):

  • MaybeT based on Maybe MaybeT基于Maybe
  • ExceptT based on Either ExceptT基于Either
  • WriterT based on (,) ( (,) doesn't normally have its Monad instance defined, and WriterT is using the wrong tuple order to make use of it if it had - but in spirit it could have). WriterT基于(,) (,)通常不具备其Monad实例定义, WriterT使用错误的元组为了使用它,如果它有-但在精神上它可能有)。
  • ListT based on [] . ListT基于[] Oh, whoops ... 噢, 哎呦 ......

The last one is in fact notorious for not being a monad unless the lifted monad is "commutative" - otherwise, expressions that should be equal by the monad laws can give different order of effects. 最后一个实际上因为不是单子而臭名昭着,除非被提升的单子是“可交换的” - 否则,单子法应该相等的表达可以给出不同的效果顺序。 My hunch is that this comes essentially from lists being able to contain more than one value, unlike the other, reliably working examples. 我的预感是,这主要来自列表能够包含多个值,而不像其他可靠的工作示例。

So, although the above definition will be correctly typed , it can still break the monad laws. 因此,虽然上面的定义将被正确输入 ,但它仍然可以打破monad定律。

Also as an afterthought, one other transformer is such a nested monad, but in a completely different way: ReaderT , based on using (->) as the outer monad. 另外,作为一个事后的想法,另一个变换器是这样一个嵌套的monad,但是以完全不同的方式: ReaderT ,基于使用(->)作为外部 monad。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM