首页 > 解决方案 > 在单个 if 语句中使用 AND 评估组合的多个条件

问题描述

在诸如 C++ 之类的语言中,如果“if”语句中有多个条件,并且这些条件与使用 AND(即 &&)相结合,那么只要其中一个条件为假,后续条件的评估就不会发生。Haskell 也是这样吗?例如,在下面的 Haskell 代码中,条件 A 为 FALSE,会发生条件 B 的评估吗?

fun :: Haxl (Maybe Bool)
fun =
 if conditionA .&& conditionB
    then return $ Just True
    else return Nothing

标签: if-statementhaskell

解决方案


这在 Haskell 中是正确的。&&定义如下:

False && _ = False
True  && y = y

这相当于以下内容:

(&&) x y = case x of
  False -> False
  True -> y

Haskell 中的惰性求值是这样定义的case:当你对某事物进行模式匹配求值时,它会根据需要强制(求值)来确定要匹配的构造函数。所以这是自动短路。

这在 Haskell的任何地方都是如此。例如,foldr (&&) True [True, True, False, error "not reached"]evaluates在评估后立即True && True && True && False && error "not reached"返回,从不评估调用。FalseFalseerror

此外,由于懒惰,在 Haskell 中,您始终可以将表达式分配给变量,并且不会改变计算的内容。例如,这些是完全等价的:

example1 x = cheapTest x || expensiveTest x
example2 x =
  let
    okay = cheapTest x
    cool = expensiveTest x
  in
    okay || cool

-- or:

example2 x = okay || cool
  where
    okay = cheapTest x
    cool = expensiveTest x

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;
}

但是,您在haxl包中显示的示例不是Haskell 标准库中的标准&&运算符,而是使用了一个不同的自定义运算符,称为.&&,其定义如下:

fa .&& fb = do a <- fa; if a then fb else return False

GenHaxl因此,这是为库定义的自定义操作类型指定相同类型的短路。首先这个函数执行动作fa,它产生一个Bool被赋值的a,然后只有当aTrue执行下一个动作fb。如果aFalse,它只运行动作return False(= pure False),它不执行任何副作用并产生False.

Haxl 还使用RebindableSyntax扩展覆盖if...<code>then...<code>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

推荐阅读