To evaluate a function application, the interpreter follows the process
described in section
[1.1.4].
関数適用を評価するために、インタプリタは
section
[1.1.4]で述べたプロセスに従います。
That is, the interpreter evaluates the elements of the
application
and applies the
function
(which is the value of the
function expression of the application)
to the arguments (which are the values of the
argument expressions of the application).
つまり、インタプリタは
関数適用
の要素を評価し、
関数
(
関数適用の関数式の値)
を引数(
関数適用の引数式の値)
に適用します。
We can assume that the application of primitive
functions is handled by the interpreter or libraries.
For compound
functions,
the application process is as follows:
-
To apply a compound
function
to arguments,
evaluate the return expression of the function
with each
parameter replaced by the corresponding argument.
プリミティブ関数の適用は、インタプリタやライブラリが処理すると仮定できます。
複合
関数
の場合、適用のプロセスは次のとおりです:
-
複合
関数
を引数に適用するには、各
パラメータを対応する引数で置き換えて、
関数の return 式を評価
します。
To illustrate this process, let's evaluate the
application
このプロセスを説明するために、次の
関数適用
を評価してみましょう。
where
f is the
function declared
in section
[1.1.4].
We begin by retrieving the
return expression
of
f:
ここで
f は
section
[1.1.4]で
宣言した関数
です。
まず
f の
return 式
を取り出します:
sum_of_squares(a + 1, a * 2)
Then we replace the parameter a
by the argument 5:
次に、パラメータ a を引数 5 で置き換えます:
sum_of_squares(5 + 1, 5 * 2)
Thus the problem reduces to the evaluation of
an application
with two
arguments
and
a function expression
sum_of_squares.
Evaluating this
application
involves three subproblems. We must evaluate the
function expression
to get the
function
to be applied, and we must evaluate the
argument expressions
to get the arguments. Now
5 + 1
produces 6 and
5 * 2
produces 10, so we must apply the
sum_of_squares function
to 6 and 10. These values are substituted for the
parameters x and
y in the body of
sum_of_squares,
reducing the expression to
こうして問題は、2つの
引数
と
関数式
sum_of_squares
を持つ
関数適用
の評価に帰着されます。
この
関数適用
を評価するには、3つの部分問題があります。適用する
関数
を得るために
関数式
を評価し、引数を得るために
引数式
を評価しなければなりません。ここで
5 + 1
は 6 を、
5 * 2
は 10 を生成するので、
sum_of_squares 関数
を 6 と 10 に適用しなければなりません。これらの値は
sum_of_squares
の本体のパラメータ x と
y に置換され、式は次のように簡約されます:
If we use the
declaration
of square, this reduces to
square の
宣言
を使うと、これは次のように簡約されます:
which reduces by multiplication to
乗算により次のように簡約され:
and finally to
最終的に次のようになります:
The process we have just described is called the
substitution
model for
function
application. It can be taken as a model that
determines the
meaning
of
function
application, insofar as the
functions
in this chapter are concerned. However, there are two
points that should be stressed:
-
The purpose of the substitution is to help us think about
function
application, not to provide a description of how the interpreter
really works. Typical interpreters do not evaluate
function
applications by manipulating the text of a
function to substitute values for the
parameters. In practice, the
substitution
is
accomplished by using a local environment for the
parameters. We will discuss this more fully in chapters 3 and
4 when we examine the implementation of an interpreter in detail.
-
Over the course of this book, we will present a sequence of
increasingly elaborate models of how interpreters work, culminating
with a complete implementation of an interpreter and compiler in
chapter
[5]. The substitution model is only the first of
these models—a way to get started thinking formally
about the evaluation process. In general, when
modeling phenomena in science and engineering, we begin with
simplified, incomplete models. As we examine things in greater detail,
these simple models become inadequate and must be replaced by more
refined models. The substitution model is no exception. In particular,
when we address in chapter [3] the use of
functions
with mutable data,
we will see that the substitution
model breaks down and must be replaced by a more complicated model of
function
application.
いま述べたプロセスは、
関数
適用の
置換モデルと呼ばれます。
この章で扱う
関数
に関する限り、これは
関数
適用の
意味
を決定するモデルと見なすことができます。
ただし、2つの点を強調しておくべきでしょう:
-
置換の目的は、
関数
適用について考える助けとなることであり、インタプリタが実際にどう動作するかを説明するものではありません。
一般的なインタプリタは、
関数
のテキストを操作して
パラメータに値を置換するという方法で
関数
適用を評価するわけではありません。
実際には、
置換
は
パラメータのローカル環境を使って実現されます。
これについては、第3章と第4章でインタプリタの実装を詳しく検討するときに、より詳しく議論します。
-
本書を通じて、インタプリタの動作についてますます精巧なモデルを順に提示していき、
chapter
[5]ではインタプリタとコンパイラの完全な実装に到達します。
置換モデルはこれらのモデルの最初のもの—評価プロセスについて形式的に考え始めるための方法にすぎません。
一般に、
科学や工学で現象をモデル化するとき、私たちは単純化された不完全なモデルから始めます。
物事をより詳しく調べていくと、これらの単純なモデルでは不十分になり、より洗練されたモデルで置き換えなければなりません。
置換モデルも例外ではありません。特に、
chapter [3]で
関数
とミュータブルなデータ
の使用を扱うとき、
置換モデルが破綻し、より複雑な
関数
適用のモデルで置き換えなければならないことがわかるでしょう。
According to the description of evaluation given in
section
[1.1.4],
the interpreter first evaluates the
function
and
argument expressions
and then applies the resulting
function
to the resulting arguments. This is not the only way to perform evaluation.
An alternative evaluation model would not evaluate the
arguments
until their values were needed. Instead it would first substitute
argument
expressions for parameters until it obtained an expression involving
only
operators and primitive functions,
and would then perform the evaluation. If we
used this method, the evaluation of
section
[1.1.4]
で示した評価の説明によると、
インタプリタはまず
関数
と
引数式
を評価し、次にその結果の
関数
を結果の引数に適用します。
しかし、これが評価を行う唯一の方法ではありません。
別の評価モデルでは、
引数
の値が必要になるまで評価しません。
代わりに、
演算子とプリミティブ関数
だけを含む式が得られるまで、
引数
式でパラメータを置換し、その後で評価を行います。
この方法を使うと、次の式の評価は
would proceed according to the sequence of expansions
以下の展開の列に従って進みます:
sum_of_squares(5 + 1, 5 * 2)
square(5 + 1) + square(5 * 2)
(5 + 1) * (5 + 1) + (5 * 2) * (5 * 2)
followed by the reductions
続いて以下のように簡約されます:
6 * 6 + 10 * 10
36 + 100
136
This gives the same answer as our previous evaluation model, but the
process is different. In particular, the evaluations of
5 + 1
and
5 * 2
are each performed twice here, corresponding to the reduction of the
expression
これは先ほどの評価モデルと同じ答えを与えますが、プロセスは異なります。
特に、
5 + 1
と
5 * 2
の評価がそれぞれ2回行われています。これは式
with x replaced respectively by
5 + 1
and
5 * 2.
の x をそれぞれ
5 + 1
と
5 * 2
で置き換えて簡約することに対応しています。
This alternative
fully expand and then reduce
evaluation method is known as
normal-order evaluation, in contrast to the
evaluate
the arguments and then apply
method that the interpreter actually
uses, which is called
applicative-order evaluation. It can be shown that, for
function
applications that can be modeled using substitution (including all the
functions
in the first two chapters of this book) and that yield legitimate values,
normal-order and applicative-order evaluation produce the same value.
(See exercise
[1.5]
for an instance of an
illegitimate
value where normal-order
and applicative-order evaluation do not give the same result.)
この
完全に展開してから簡約する
という代替的な評価方法は、
正規順序の評価と呼ばれます。
これに対して、インタプリタが実際に使っている
引数を評価してから適用する
方法は、
適用順序の評価と呼ばれます。
置換を使ってモデル化できる
関数
適用(本書の最初の2章のすべての
関数
を含む)で、正当な値を生成するものについては、
正規順序の評価と適用順序の評価は同じ値を生成することが示せます。
(正規順序の評価と適用順序の評価が同じ結果を与えない
正当でない
値の例については、
exercise
[1.5]を参照してください。)
JavaScript
uses applicative-order evaluation, partly because of the
additional efficiency obtained from avoiding multiple evaluations of
expressions such as those illustrated with
5 + 1
and 5 * 2
above and, more significantly, because normal-order evaluation
becomes much more complicated to deal with when we leave the realm of
functions
that can be modeled by substitution. On the other hand,
normal-order evaluation can be an extremely valuable tool, and we will
investigate some of its implications in chapters 3 and 4.
JavaScript
が適用順序の評価を採用しているのは、上の例で
5 + 1
や 5 * 2
のような式の重複評価を避けることで得られる効率向上が一因ですが、
より重要な理由は、置換でモデル化できる
関数
の領域を離れると、正規順序の評価の扱いがはるかに複雑になるからです。
一方、正規順序の評価は非常に有用なツールとなり得るもので、第3章と第4章でその含意のいくつかを調べていきます。