Functional Programming in C++ ,第 214 页,引用 expected<T,E>
monad 与 Haskell 的 Either
相同, 阅读
[...] as soon as any of the functions you're binding to returns an error, the execution will stop and return that error to the caller.
然后,在下面的标题中,它显示
If you call
mbind
[equivalent to Haskell's>>=
] on anexpected
that contains an error,,mbind
won't even invoke the transformation function; it will just forward that error to the result.
这似乎是在“调整”之前写的内容。 (我很确定 LYAH 或 RWH 在某处强调没有短路;如果你记得在哪里,请提醒我。)
事实上,我对 Haskell 的理解是,在单子(monad)绑定(bind)链中,所有绑定(bind)都是真实发生的;然后他们如何处理作为第二个参数传递给他们的函数,取决于特定的 monad。
在Maybe
的情况下和 Either
,当绑定(bind)传递给 Nothing
时或 Left x
参数,则忽略第二个参数。
不过,在这两种特定情况下,我想知道这样做是否会降低性能
justPlus1 = Just . (+1)
turnToNothing = const Nothing
Just 3 >>= turnToNothing >>= justPlus1
>>= justPlus1
>>= justPlus1
>>= justPlus1
>>= justPlus1
因为在这些情况下,链不能真正做除它所做的之外的任何事情
Nothing >>= _ = Nothing
Left l >>= _ = Left l
最佳答案
考虑以下表达式:
result :: Maybe Int
result = x >>= f >>= g >>= h
当然,在该表达式中,x::Maybe a
用于某些 a
,以及每个 f
、g
和 h
是函数,h
返回 Maybe Int
但管道的中间类型可以是任何包装在 也许
。也许 f::String -> Maybe String
,g::String -> Maybe Char
,h::Char -> Maybe Int
。
让我们也明确关联性:
result :: Maybe Int
result = ((x >>= f) >>= g) >>= h
要对表达式求值,每个绑定(bind) (>>=
) 实际上都必须被调用,但函数f
、g
,或h
。最终,对 h
的绑定(bind)需要检查其左侧参数,以确定它是 Nothing
还是 Just something
;为了确定我们需要调用对 g
的绑定(bind),并决定我们需要调用对 f
的绑定(bind),这必须至少查看 x
。但是,一旦这些绑定(bind)中的任何一个产生了 Nothing
,我们只需为在每一步检查 Nothing
付费(非常便宜),而不是为调用(可能昂贵的)下游函数付费。
假设 x = Nothing
。然后 f
的绑定(bind)会检查它,看到 Nothing
,并且根本不会调用 f
。但是我们仍然需要绑定(bind)它的结果,以便知道它是否为 Nothing
。这一直沿着链向下,直到我们最终得到 result = Nothing
,调用了 >>=
三次但没有函数 f
,g
,或h
。
Either
与 Left
值的行为相似,而其他 monad 可能有不同的行为。列表可以调用每个函数一次、多次或不调用;元组 monad 只调用每个函数一次,没有短路或其他多重性特征。
关于c++ - Maybe 和 Either 单子(monad)、短路和性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63943706/