首页 > 解决方案 > Haskell 守卫是按顺序评估的吗?

问题描述

评估 Haskell 守卫的顺序是什么?

假设我有一个返回 Bool 的函数:

someFunc :: Bool -> Bool -> Bool
someFunc b1 b2
 | b1 == True && b2 == True = True
 | b1 == True = False
 | b1 == False .....
...

我认为这是我读到的 Monads 和 Do-notation,有时不会按顺序评估动作。那就是如果我有:

do { val1 <- action1
     val2 <- action2
     action3 }

可能会在 val1 之前计算 val2。

守卫也是这样吗?可以乱序评估它们吗?如果警卫是连续的,那么如果第一个语句的计算结果为 False,第二个语句的计算结果为 True,那么我可以得出 b2 为 False 的结论。这个逻辑总是成立吗?

编辑:通过陈述,我的意思是守卫 1 到 3

标签: haskell

解决方案


评估守卫中的测试不会有任何副作用——与过程语言不同。因此,评估比较或布尔连接词的顺序对程序的语义没有任何影响。

优先级分支——即每一行开始|——是从上到下。但真正的“评估”是错误的概念:编译器可以先评估您的b1 == False,前提是它在检查前两个分支之前不采用第三个分支。(GHC 实际上并没有这样做;我只是在设置一个稻草人。)

请注意,在对 的调用中someFunc, 的参数b1, b2可能是任意复杂的表达式。Haskell 的“惰性语义”意味着在需要之前不会对它们进行评估。

这个逻辑总是成立吗?

请注意:如果早期守卫结果为 False,则您不能对其中的表达式做出任何假设。编译器可能已经重新排列它们以提高效率,不按文本顺序评估它们,然后继续。在您的示例中,如果结果是第一个分支b1 /= True,编译器可能根本不会评估b2。所以你不能得出任何关于b2. 如果评估,确实b2可能会给出底部/无限计算。

不仅仅是 Monads 或 Do-notation(它们是同一件事),表达式不一定按文本顺序进行评估——在任何上下文中的任何表达式中都是如此。(IO Monad 有一些狡猾的语义,使它看起来“语句”是从上到下执行的。)


推荐阅读