The expressive power of the class of
functions
that we can define at this point is very limited, because we have no way to
make tests and to perform different operations depending on the result of a
test.
For instance, we cannot declare a function that computes the
absolute value of a number by testing whether the number is nonnegative
and taking different actions in each case according to the rule
This construct is a
case analysis and can be written
in JavaScript using a conditional expression as
この構文は
場合分けであり、JavaScript では条件式を使って次のように書くことができます。
function abs(x) {
return x >= 0 ? x : - x;
}
which could be expressed in English as If $x$ is
greater than or equal to zero, return $x$; otherwise
return $- x$.
The general form of a conditional expression is
Conditional
expressions begin with a
$predicate$—that is,
an expression whose value is either
true or false, two distinguished
boolean values in JavaScript.
The primitive boolean expressions
true and
false trivially evaluate
to the boolean values true and false, respectively.
The $predicate$
is followed by a question mark, the
$consequent$-$expression$,
a colon, and finally the
$alternative$-$expression$.
To
evaluate a conditional expression,
the interpreter starts by evaluating the
$predicate$
of the expression. If the
$predicate$
evaluates to true, the interpreter evaluates the
$consequent$-$expression$ and returns its value as the value of the conditional.
If the $predicate$
evaluates to false, it evaluates the
$alternative$-$expression$ and returns its value as the value of the
conditional.
The word
predicate is used for operators and functions that
return true or false, as well as for expressions that
evaluate to true or false. The absolute-value function
abs makes use of the
primitive predicate >=,
an operator that takes two numbers as arguments and tests whether the
first number is greater than or equal to the second number, returning
true or false accordingly.
In JavaScript, we express a case analysis with multiple cases by nesting
conditional expressions as alternative expressions inside other conditional expressions:
function abs(x) {
return x > 0
? x
: x === 0
? 0
: - x;
}
Parentheses are not needed around the alternative expression
x === 0 ? 0 : - x, because
the conditional-expression syntactic form
is right-associative.
The interpreter ignores spaces and line breaks, here inserted for readability
to align the
?'s
and :'s under the first predicate
of the case analysis.
The general form of a
case analysis is
代替式 x === 0 ? 0 : - x の周りに括弧は不要です。条件式の構文形式は
右結合だからです。インタプリタはスペースや改行を無視しますが、ここでは読みやすさのために ? と : を場合分けの最初の述語の下に揃えています。
場合分けの一般的な形式は次のとおりです。
We call a predicate $p_i$
together with its consequent expression
$e_i$
a
clause. A case analysis
can be seen as a sequence of clauses, followed by a final
alternative expression.
According to the evaluation of conditional expressions,
a case analysis is evaluated by first evaluating
the predicate $p$$_1$.
If its value is false, then $p$$_2$
is evaluated.
If $p$$_2$'s
value is also false, then $p$$_3$
is evaluated. This process continues until a predicate is
found whose value is true, in which case the interpreter returns the
value of the corresponding
consequent expression
$e$
of the clause
as the value of the case analysis.
If none of the
$p$'s
is found to be true, the value of the case analysis
is the value of the final alternative expression.
In addition to primitive predicates such as
>=,
>,
<,
<=,
===, and
!== that are applied to
numbers,
there are logical composition operations, which enable us to construct
compound predicates. The three most frequently used are these:
$expression$$_1$ &&
$expression$$_2$
This operation expresses
logical conjunction, meaning roughly
the same as the English word and.
We assume this syntactic form to be syntactic
sugar for
$expression$$_1$ ?
$expression$$_2$ :false.
$expression$$_1$
||
$expression$$_2$
This operation expresses
logical disjunction, meaning roughly
the same as the English word or.
We assume this syntactic form to be syntactic sugar for
$expression$$_1$ ?true:
$expression$$_2$.
!
$expression$
This operation expresses
logical negation, meaning
roughly the same as the English word not.
The value of the expression is true when
$expression$
evaluates to false, and false when
$expression$
evaluates to true.
Notice that && and
|| are syntactic forms,
not operators;
their right-hand
expression is not always evaluated. The operator
!, on the other hand,
follows the evaluation rule of section
1.1.3.
It is a unary operator, which means that it takes only
one argument, whereas the arithmetic operators and primitive predicates
discussed so far
are binary, taking two arguments. The operator
! precedes its argument;
we call it a
prefix operator. Another prefix operator is
the numeric negation operator, an example of
which is the expression - x
in the abs functions above.
As an example of how these predicates are used, the condition that a
number $x$ be in the range
$5 < x < 10$ may be expressed as
これらの述語の使い方の例として、数 $x$ が $5 < x < 10$ の範囲にあるという条件は次のように表現できます。
x > 5 && x < 10
The syntactic form
&&
has lower precedence than the comparison operators
>
and <, and
the conditional-expression syntactic form
$\cdots$?$\cdots$:$\cdots$
has lower precedence than any other operator we have encountered so far,
a property we used in
the abs functions above.
As another example, we can
declare
a predicate to test whether one number is
greater than or equal to another as
別の例として、ある数が別の数以上かどうかをテストする述語を次のように
宣言
できます。
function greater_or_equal(x, y) {
return x > y || x === y;
}
or alternatively as
あるいは次のようにも書けます。
function greater_or_equal(x, y) {
return ! (x < y);
}
The function greater_or_equal,
when applied to two numbers, behaves the same as the operator
>=. Unary operators have
higher precedence than binary operators, which makes the
parentheses in this example necessary.
Below is a sequence of
statements.
What is the result printed by the interpreter in response to each
statement?
Assume that the sequence is to be evaluated in the order
in which it is presented.
The parentheses around the conditional expressions in the last two statements
are necessary because the
conditional-expression syntactic form has lower
precedence than the arithmetic operators
+ and
*.
Declare a function
that takes three numbers as arguments and returns
the sum of the squares of the two larger numbers.
3 つの数を引数として受け取り、大きい方の 2 つの数の二乗の和を返す
関数を宣言
してください。
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));
}
Observe that our model of evaluation allows for
applications
whose function expressions are compound expressions. Use this observation
to describe the behavior of a_plus_abs_b:
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);
}
According to section 1.1.5, evaluation
of an application proceeds as follows:
Evaluate the subexpressions of the application.
Evaluate the return expression of the result of
the function expression with each
parameter replaced by the corresponding result of the respective
argument expression.
Thus the evaluation of the application
a_plus_abs_b(5, -4)
(1) evaluates a_plus_abs_b,
resulting in the function given above, and the arguments are
already values. So we need to evaluate (2) 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 (1) are already values. Thus we end up evaluating (2) 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.
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:
Ben Bitdiddle は、自分が使っているインタプリタが
適用順序の評価を使っているのか正規順序の評価を使っているのかを判定するテストを考案しました。彼は次の 2 つの
関数を宣言します。
function p() { return p(); }
function test(x, y) {
return x === 0 ? 0 : y;
}
Then he evaluates the
statement
そして次の
文
を評価します。
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.)
適用順序の評価を使うインタプリタで Ben が観察する動作はどうなるでしょうか?正規順序の評価を使うインタプリタではどうでしょうか?答えを説明してください。
(
条件式
の評価規則は、インタプリタが正規順序と適用順序のどちらを使う場合でも同じであると仮定してください。つまり、まず述語式が評価され、その結果に基づいて帰結式と代替式のどちらを評価するかが決まります。)
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().
Conditionals
in full JavaScript accept any value, not just a boolean, as the result of evaluating
the $predicate$ expression (see footnote 1
in section 4.1.3 for details). The programs in this book
use only boolean values as predicates of conditionals.
For now, we restrict these operators to number
arguments. In sections 2.3.1
and 3.3.1, we shall
generalize the equality and inequality predicates
=== and
!==.
This assumption is justified by the restriction mentioned
in footnote undefined. Full JavaScript
needs to consider the case where the result of evaluating $expression$$_1$ is neither true nor false.
Syntactic forms that are simply convenient
alternative surface structures for things that can be written in more
uniform ways are sometimes called syntactic sugar, to use a
phrase coined by
Peter Landin.
より統一的な方法で書けるものに対して、単に便利な代替的表層構造を提供する構文形式は、
Peter Landin が作った言葉を借りて糖衣構文と呼ばれることがあります。