# 1.1.6条件表达式和谓词

> 译文： [https://sicp.comp.nus.edu.sg/chapters/8](https://sicp.comp.nus.edu.sg/chapters/8)

<split>此时我们可以声明的函数类的表达能力非常有限，因为我们无法根据测试结果进行测试和执行不同的操作。 例如，我们无法声明通过测试数字是否为负数并根据规则![%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7Cx%7C%20%3D%20%5Cleft%5C%7B%20%5Cbegin%7Barray%7D%7Brl%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%20%20%20%26%20%5Cmbox%7Bif%20%24x%20%5Cgeq%200%24%7D%20%5C%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-x%20%20%26%20%5Cmbox%7Botherwise%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Cend%7Barray%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Cright.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20](img/ea27d217ac46ec81b06854eec5be0505.jpg)在每种情况下采取不同的操作来计算数字绝对值的函数。此结构是_案例分析[_ ，并且可以使用_条件表达式_在JavaScript中表示，如下所示：

```js
function abs(x) {
    return x >= 0 ? x : -x;
}
```

The general form of a conditional expression is `![%5Ctextit%7Bpredicate%7D](img/28ecfc1c578296d7ed22b45636571912.jpg) ? ![%5Ctextit%7Bconsequent-expression%7D](img/baee7ce3f3af2debf30a02a83e483902.jpg) : ![%5Ctextit%7Balternative-expression%7D](img/ef87bec6cc09f2e53d8b5c8843a1e2cf.jpg)` Conditional expressions begin with a <nobr> ![%5Ctextit%7Bpredicate%7D](img/28ecfc1c578296d7ed22b45636571912.jpg)</nobr>—that is, an expression whose value is interpreted as either _true_ or _false_, two distinguished _boolean_ values in JavaScript.[[1]](8#footnote-1) Note that the primitive boolean expressions `true` and `false` trivially evaluate to the boolean values _true_ and _false_, respectively. The ![%5Ctextit%7Bpredicate%7D](img/28ecfc1c578296d7ed22b45636571912.jpg) is followed by a question mark, the ![%5Ctextit%7Bconsequent-expression%7D](img/baee7ce3f3af2debf30a02a83e483902.jpg), a colon, and finally the ![%5Ctextit%7Balternative-expression%7D](img/ef87bec6cc09f2e53d8b5c8843a1e2cf.jpg).</split> <split>为了评估条件表达式，解释器首先评估表达式的![%5Ctextit%7Bpredicate%7D](img/28ecfc1c578296d7ed22b45636571912.jpg)部分。 如果![%5Ctextit%7Bpredicate%7D](img/28ecfc1c578296d7ed22b45636571912.jpg)评估为_为真_，则解释器评估为![%5Ctextit%7Bconsequent-expression%7D](img/baee7ce3f3af2debf30a02a83e483902.jpg)。 否则评估为![%5Ctextit%7Balternative-expression%7D](img/ef87bec6cc09f2e53d8b5c8843a1e2cf.jpg)。</split>  <split>单词_谓词_用于返回 _true_ 或 _false_ 的函数，以及返回 _true_ 或_的表达式 错误_。 绝对值函数`abs`利用原始谓词`&gt;=`。 该谓词采用两个数字作为参数，并测试第一个数字是否大于或等于第二个数字，相应地返回 _true_ 或 _false_ 。</split>  <split>JavaScript提供了许多与`&gt;=`相似的原始谓词，包括`&gt;`，`&lt;`，`&lt;=`和`===`。 除了这些原始谓词外，还有逻辑组合运算，这些运算使我们能够构造复合谓词。 三种最常用的是：

*   ![%20%5Ctextit%7Bexpression%7D_1](img/a0edd79701d1c5617ebb27dede7e97e5.jpg) `&&` ![%5Ctextit%7Bexpression%7D_2](img/65aa6628b728916b19487b6648d5257c.jpg) &lt;break&gt;&lt;/break&gt; 解释器评估![%5Ctextit%7Bexpression%7D_1](img/af41029c31183e68ec01b08c614e1295.jpg)。 如果将其评估为_为假_，则整个表达式的值为_为假_，并且不评估![%5Ctextit%7Bexpression%7D_2](img/65aa6628b728916b19487b6648d5257c.jpg)。 如果![%5Ctextit%7Bexpression%7D_1](img/af41029c31183e68ec01b08c614e1295.jpg)评估为_为真_，则整个表达式的值为![%5Ctextit%7Bexpression%7D_2](img/65aa6628b728916b19487b6648d5257c.jpg)的值。
*   ![%5Ctextit%7Bexpression%7D_1](img/af41029c31183e68ec01b08c614e1295.jpg) `||` ![%5Ctextit%7Bexpression%7D_2](img/65aa6628b728916b19487b6648d5257c.jpg) &lt;break&gt;&lt;/break&gt; 解释器评估![%5Ctextit%7Bexpression%7D_1](img/af41029c31183e68ec01b08c614e1295.jpg)。 如果将其评估为 _true_ ，则整个表达式的值为 _true_ ，而不评估![%5Ctextit%7Bexpression%7D_2](img/65aa6628b728916b19487b6648d5257c.jpg)。 如果![%5Ctextit%7Bexpression%7D_1](img/af41029c31183e68ec01b08c614e1295.jpg)的值为_为假_，则整个表达式的值为![%5Ctextit%7Bexpression%7D_2](img/65aa6628b728916b19487b6648d5257c.jpg)的值。
*   `!` ![%5Ctextit%7Bexpression%7D](img/f0cc862b727cfe66f52e91676be9e021.jpg) &lt;break&gt;&lt;/break&gt; 当![%5Ctextit%7Bexpression%7D](img/f0cc862b727cfe66f52e91676be9e021.jpg)评估为_为假_时，该表达式的值为_为真_，否则为_为假。_

Notice that `&&` and `||` are not evaluated like arithmetic operators such as `+`, because their right-hand expression is not always evaluated. The operator `!`, on the other hand, follows the evaluation rule of section <ref name="sec:evaluating-combinations">[1.1.3](5)</ref>. It is a _unary_ operator, which means that it takes only one argument, whereas the arithmetic operators encountered so far are _binary_, taking two arguments. The operator `!` precedes its argument; we call it a _prefix operator_. Another prefix operator is the unary <quote>minus</quote> operator, an example of which is the expression `-x` of the function `abs` in the beginning of this section.</split> <split>作为如何使用这些谓词的示例，数字![x](img/40779fc60a53ff2b70f832ec10cade09.jpg)在![5%20%3C%20x%20%3C%2010](img/048cbd37f4ed257c472fade509095ea4.jpg)范围内的条件可以表示为

```js
x > 5 && x < 10
```

Note that the binary operator `&&` has lower precedence than the comparison operators `>` and `<`.</split> <split>再举一个例子，我们可以声明一个谓词来测试一个数字是否不等于另一个数字。

```js
function not_equal(x, y) {
    return x > y || x < y;
}
```

or alternatively as

```js
function not_equal(x, y) {
    return !(x >= y && x <= y);
}
```

Note that the operator `!==` when applied to two numbers, behaves the same as `not_equal`.</split> <exercise><split>以下是一系列语句。 在单击语句之前，请先预测其评估结果。</split> 

```js
10;
```

```js
5 + 3 + 4;
```

```js
9 - 1;
```

```js
6 / 2;
```

```js
2 * 4 + (4 - 6);
```

```js
const a = 3;
```

```js
const b = a + 1;
```

```js
a + b + a * b;
```

```js
a === b;
```

```js
b > a && b < a * b 
   ? b : a;
```

```js
a === 4 ? 6 : b === 4 ? 6 + 7 + a : 25;
```

```js
2 + (b > a ? b : a);
```

```js
(a > b
 ? a
 : a < b
   ? b
   : -1)
*
(a + 1);
```

<split>Note that the statement

```js
a === 4 ? 6 : b === 4 ? 6 + 7 + a : 25;
```

consists of two conditional expressions, where the second one forms the alternative of the first one. If you want to make that clear, you can indent the lines like this:

```js
a === 4
? 6
: b === 4 
  ? 6 + 7 + a
  : 25;
```</split> <button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#no_solution_8_1_div">Add solution</button>There is currently no solution available for this exercise. This textbook adaptation is a community effort. Do consider contributing by providing a solution for this exercise, using a Pull Request in [Github](https://github.com/source-academy/sicp).</exercise><exercise>Translate the following expression into JavaScript ![%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5Cfrac%7B5%2B4%2B%5Cleft%282-%5Cleft%283-%286%2B%5Cfrac%7B4%7D%7B5%7D%29%5Cright%29%5Cright%29%7D%7B3%20%286-2%29%20%282-7%29%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20](img/fc5924c995aa8af062aa153b0a172d5a.jpg)<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#solution_8_1_div">Solution</button> <solution>```js
(5 + 4 + (2 - (3 - (6 + 4 / 5)))) 
/
(3 * (6 - 2) * (2 - 7));
```</solution></exercise> <exercise>Declare a function that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#solution_8_2_div">Solution</button> <solution>```js
function f(x, y, z) {
   return square(x) + square(y) + square(z) -
          // subtract the square of the smallest
          square(x > y ? (y > z ? z : y) : (x > z ? z : x));
}
```</solution></exercise> <exercise><split>Observe that our model of evaluation allows for application combinations whose function expressions are compound expressions. Use this observation to describe the behavior of the following function:

```js
function plus(a, b) { return a + b; }
function minus(a, b) { return a - b; }
function a_plus_abs_b(a, b) {
    return (b >= 0 ? plus : minus)(a, b);
}
```

Note that in the conditional expression, we cannot directly use the operators `+` and `-` instead of the names `plus` and `minus` because in infix notation, only operator symbols are allowed in the middle, not compound expressions.[[2]](8#footnote-2)<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#solution_8_3_div">Solution</button><solution>According to section <ref name="sec:substitution-model">[1.1.5](7)</ref>, evaluation of a application expression proceeds as follows:

1.  评估应用程序组合的功能表达式，从而得出要应用的功能。
2.  评估组合的参数表达式。
3.  使用每个参数替换为相应参数来评估函数的返回表达式。

Thus the evaluation of the application expression `a_plus_abs_b(5, -4)` (1) evaluates `a_plus_abs_b`, resulting in the function given above, and (2) the arguments are already values. So we need to evaluate (3) the return expression of the function, with the parameters replaced by the arguments, thus: `(-4 >= 0 ? plus : minus)(5, -4)`. With the same rules, we need to (1) evaluate the function expression, which in this case is the conditional expression `-4 >= 0 ? plus : minus`. Since the predicate evaluates to _false_, the function expression evaluates to `minus`. The arguments, again (2) are already values. Thus we end up evaluating (3) the body of `minus` with the parameters `a` and `b` replaced by 5 and -4, respectively, resulting in `5 - (-4)`, which will finally evaluate to 9.</solution></split></exercise><exercise>Ben Bitdiddle has invented a test to determine whether the interpreter he is faced with is using applicative-order evaluation or normal-order evaluation. He declares the following two functions :

```js
function p() {
    return p();
}

function test(x, y) {
    return x === 0 ? 0 : y;
}
```

Then he evaluates the statement

```js
test(0, p());
```

What behavior will Ben observe with an interpreter that uses applicative-order evaluation? What behavior will he observe with an interpreter that uses normal-order evaluation? Explain your answer. (Assume that the evaluation rule for conditional expressions is the same whether the interpreter is using normal or applicative order: The predicate expression is evaluated first, and the result determines whether to evaluate the consequent or the alternative expression.)<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#solution_8_4_div">Solution</button><solution><split>In applicative-order evaluation of `test(0, p())`, we need to evaluate the argument expressions before we can evaluate the return expression of the function `test`. The evaluation of the argument expression `p()` will not terminate, however: It will keep evaluating application expressions of the form `p()`, and thus the evaluation of `test(0, p())` will not produce a legitimate value. In normal-order evaluation, on the other hand, the function application `test(0, p())` would immediately evaluate the return expression of the function `test`, `x === 0 ? 0 : y` after replacing the parameter `x` with `0` and `y` with `p()`. The result of the replacing would be `0 === 0 ? 0 : p()`. The evaluation of the predicate `0 === 0` results in _true_ and thus the conditional expression evaluates to 0, without any need to evaluate `p()`.</split></solution></exercise>

* * *

[[1]](8#footnote-link-1) In JavaScript, other values are automatically converted into _true_ and _false_ according to _conversion rules_, but we choose not to make use of these conversion rules in this book.

[[2]](8#footnote-link-2) For an expression of the form `a (b > 0 ? + : -) b` the JavaScript interpreter would not know the precedence of the operator between `a` and `b`, and therefore such expressions are not allowed.

