也许或者单子、短路和性能

问题描述 投票:0回答:2

C++ 中的函数式编程,第 214 页,参考与 Haskell 的

expected<T,E>
相同的
Either
monad,内容为

[...] 一旦您绑定的任何函数返回错误,执行就会停止并将该错误返回给调用者。

然后,在下面的标题中,写着

如果您在包含错误的

mbind
上调用
>>=
[相当于 Haskell 的
expected
],
mbind
甚至不会调用转换函数; 它只会将该错误转发给结果

这似乎“调整”了之前写的内容。 (我很确定LYAHRWH在某个地方强调了没有短路;如果你记得在哪里,请提醒我。)

事实上,我对 Haskell 的理解是,在一元绑定链中,所有绑定都是真实发生的;然后他们如何处理作为第二个参数传递给他们的函数,取决于特定的 monad。

对于

Maybe
Either
,当绑定传递
Nothing
Left x
参数时,第二个参数将被忽略。

不过,在这两种具体情况下,我想知道这样做是否会造成性能损失

justPlus1 = Just . (+1)
turnToNothing = const Nothing
Just 3 >>= turnToNothing >>= justPlus1
                         >>= justPlus1
                         >>= justPlus1
                         >>= justPlus1
                         >>= justPlus1

在这些情况下,鉴于此,链条除了它所做的之外实际上不能做任何事情

Nothing >>= _ = Nothing
Left l >>= _ = Left l
c++ performance haskell functional-programming monads
2个回答
3
投票

考虑以下表达式:

result :: Maybe Int
result = x >>= f >>= g >>= h

在该表达式中,当然,

x :: Maybe a
代表某些
a
,并且每个
f
g
h
都是函数,
h
返回
Maybe Int
,但返回管道的中间类型可以是任何包裹在
Maybe
中的东西。也许
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
的绑定需要检查其左侧参数来决定它是
Nothing
还是
Just something
;为了确定我们需要调用
g
的绑定,并决定我们需要调用
f
的绑定,这至少必须查看
x
。但是,一旦这些绑定中的任何一个产生
Nothing
,我们只需在每一步检查
Nothing
付费(非常便宜),而不是调用(可能昂贵)下游函数。

假设

x = Nothing
。然后对
f
的绑定会检查它,看到
Nothing
,并且根本不费心去调用
f
。但我们仍然需要绑定它的结果才能知道它是否是
Nothing
。这样继续沿着链向下,直到最后我们得到
result = Nothing
,调用了
>>=
三次,但没有任何函数
f
g
h

Either
Left
值的行为类似,其他 monad 可能有不同的行为。列表可以调用每个函数一次、多次或不调用;元组 monad 只调用每个函数一次,没有短路或其他多重特征。


1
投票

您似乎误解了这些类型的 Monad 实例在 Haskell 中的工作方式。你说:

事实上,我对 Haskell 的理解是,在一元函数链中,所有函数都被调用,

但事实显然并非如此。事实上,任何时候你计算

Nothing >>= f

其中

f
是任何
a -> Maybe b
类型的函数,那么它是根据
>>=
对于
Maybe
单子的实现来计算的,即:

Just x >>= f = f x
Nothing >>= f = Nothing

所以

f
确实会在
Just
情况下被调用,但在
Nothing
情况下不会被调用。所以我们看到确实存在“短路”。事实上,由于 Haskell 很懒,每个函数默认都会“短路”——除非需要产生结果,否则不会计算任何内容。

这是一个关于性能的有趣问题,但我个人不知道如何回答。当然,正如我刚才所解释的,一旦遇到

Nothing
,链中的以下函数都不会被评估 - 但执行模式匹配来查看这一点不太可能是免费的。也许编译器能够对此进行优化,因为一旦遇到
Nothing
,它就可以放弃整个计算。但我不确定。

© www.soinside.com 2019 - 2024. All rights reserved.