Ash*_*dey -2 haskell if-statement
在诸如 C++ 之类的语言中,如果“if”语句中有多个条件,并且这些条件使用 AND(即&&)进行组合,那么只要其中一个条件为假,后续条件的求值就不会发生。Haskell 也是如此吗?例如,在下面的 Haskell 代码中,条件 A 为 FALSE,条件 B 的评估会发生吗?
fun :: Haxl (Maybe Bool)
fun =
if conditionA .&& conditionB
then return $ Just True
else return Nothing
Run Code Online (Sandbox Code Playgroud)
这在 Haskell 中是正确的。&&定义如下:
False && _ = False
True && y = y
Run Code Online (Sandbox Code Playgroud)
这相当于以下内容:
(&&) x y = case x of
False -> False
True -> y
Run Code Online (Sandbox Code Playgroud)
Haskell 中的惰性求值定义为case:当您对某事物进行模式匹配求值时,它会被强制(求值)到必要的程度,以确定要匹配的构造函数。所以这是自动短路。
这通常是正确的无处不在Haskell。例如,foldr (&&) True [True, True, False, error "not reached"]评估后立即True && True && True && False && error "not reached"返回,从不评估调用。FalseFalseerror
此外,由于懒惰,在 Haskell 中,您始终可以将表达式分配给变量,并且不会更改所评估的内容。例如,这些完全等效:
example1 x = cheapTest x || expensiveTest x
Run Code Online (Sandbox Code Playgroud)
example2 x =
let
okay = cheapTest x
cool = expensiveTest x
in
okay || cool
-- or:
example2 x = okay || cool
where
okay = cheapTest x
cool = expensiveTest x
Run Code Online (Sandbox Code Playgroud)
expensiveTest除非cool被评估,否则不会被调用,这只会在okayis 时发生False。这与急切评估的语言不同,这可能会改变运行时成本,或者与非引用透明的语言不同,它可能会改变副作用。例如,在 JavaScript 中,example1和example2不同的是:
function cheapTest(x) {
console.log('cheap test');
return x !== 0;
}
function expensiveTest(x) {
console.log('expensive test');
return Math.log2(x) < 10;
}
// Short-circuits second effect if possible.
function example1(x) {
return cheapTest(x) || expensiveTest(x);
}
// Always evaluates both effects.
function example2(x) {
var okay = cheapTest(x);
var cool = expensiveTest(x);
return okay || cool;
}
Run Code Online (Sandbox Code Playgroud)
但是,您从haxl包中显示的示例不是&&Haskell 标准库中的标准运算符,而是使用了一个名为 的不同自定义运算符.&&,其定义如下:
fa .&& fb = do a <- fa; if a then fb else return False
Run Code Online (Sandbox Code Playgroud)
所以这是为GenHaxl库定义的自定义操作类型指定相同类型的短路。首先执行此函数的作用fa,其产生的Bool分配a,那么只有当a是True它执行下一个动作fb。如果a是False,它只运行操作return False(= pure False),它不执行任何副作用并产生False。
Haxl还采用了RebindableSyntax扩展覆盖if... ... then... ... else... ...语法允许副作用if的条件。在没有该扩展的普通 Haskell 代码中,您需要将效果与 分开if,例如,在do块中使用单独的绑定语句:
fun = do
c <- conditionA .&& conditionB
if c
then return $ Just True
else return Nothing
-- or: return $ if c then Just True else Nothing
Run Code Online (Sandbox Code Playgroud)