How are let-forms evaluated?
-
29-10-2019 - |
Вопрос
let
-forms are allowed to contain several expressions inside:
(let ((x 4))
x
(+ x 1))
returns 5
.
How is this expression evaluated?
Решение
The situation you're describing occurs in several parts in Scheme, not only in a let
expression. In the following ...
- After the list of variable bindings in a
let
expression - After the list of parameters in a
lambda
expression (and consequently, after the list of parameters in a procedure definition) - After each clause in a
cond
expression
... you can write a list of expressions. Implicitly those expressions are enclosed inside a begin
special form, the order of evaluation is from left to right, all the expressions are evaluated in turn but the value returned is that of the last expression.
For example, this expression:
(cond ((= 1 1) 1 2 3))
Is equivalent to:
(cond ((= 1 1) (begin 1 2 3)))
In both cases, the returned value is 3
, because that's the value of the last expression in the list.
Другие советы
that's called an implicit begin
, in other words your code is evaluated as if it was written:
(let ((x 4)) (begin x (+ x 1)))
Well, let's get the terminology clear just in case. A let
form has two parts: bindings and a body:
(let (<zero or more bindings>)
<one or more body expressions>)
A binding has the form (<variable> <expression>)
, and the body is a sequence of expressions. A let
is evaluated like this:
- Create a local environment where each variable is bound to the result of evaluating the expression in the corresponding binding.
- Evaluate the expressions in the body in sequential order.
- Result: the result of the last expression in the body.
First, terminology -- the expressions after the variable bindings are collectively known as the body, and each expression in the body is a body expression. Ex:
(let ((variable-1 value-1)
(variable-2 value-2))
body-expression-1
body-expression-2)
The body expressions are wrapped in begin
-- (let ((x 2)) x (+ x 1))
is the same as (let ((x 2)) (begin x (+ x 1)))
.
Each body expression in begin
is evaluated and the return value of the final expression is used as the return value for the entire body. Ex: (begin (+ x 1) (+ x 2))
will evaluate (+ x 1)
and (+ x 2)
and then return the result of evaluating (+ x 2)
.
If every body expression in begin
has no side effects, then all but the last body expression can be removed with no change to the runtime behavior of the program. The only exceptions here are when one of the preliminary body expressions runs slowly/doesn't return/errors out -- eliminating the body expression eliminates the problem, which is a change to the runtime behavior of the program.
However, when using functions with side effects, the ability to call one or more functions for their side effects and then return a value is useful.