💾 Archived View for shaggypeak.com › library › r7rs › section4.gmi captured on 2024-05-10 at 12:59:12. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-03-20)

-=-=-=-=-=-=-

Table of Contents

Section 3.5 - Proper Tail Recursion

Section 4.2 - Derived expression types

4 Expressions

Expression types are categorized as primitive or derived. Primitive expression types include variables and procedure calls. Derived expression types are not semantically primitive, but can instead be defined as macros. Suitable syntax definitions of some of the derived expressions are given in section 7.3.

The procedures force, promise?, make-promise, and make-parameter are also described in this chapter because they are intimately associated with the delay, delay-force, and parameterize expression types.

4.1 Primitive Expression Types

4.1.1 Variable references

⟨variable⟩           syntax

An expression consisting of a variable (section 3.1) is a variable reference. The value of the variable reference is the value stored in the location to which the variable is bound. It is an error to reference an unbound variable.

(define x 28)
    x ⇒ 28

4.1.2 Literal expressions

(quote ⟨datum⟩) ’⟨datum⟩ ⟨constant⟩
      ⇒ 28

(quote ⟨datum⟩) evaluates to ⟨datum⟩. ⟨Datum⟩ can be any external representation of a Scheme object (see section 3.3). This notation is used to include literal constants in Scheme code.

(quote a)        ⇒ a
(quote #(a b c)) ⇒ #(a b c)
(quote(+ 1 2))   ⇒ (+ 1 2)

(quote ⟨datum⟩) can be abbreviated as ’⟨datum⟩. The two notations are equivalent in all respects.

’a          ⇒ a
’#(a b c)   ⇒ #(a b c)
’()         ⇒ ()
’(+ 1 2)    ⇒ (+ 1 2)
’(quote a)  ⇒ (quote a)
’’a         ⇒ (quote a)

Numerical constants, string constants, character constants, vector constants, bytevector constants, and boolean constants evaluate to themselves; they need not be quoted.

’145932      ⇒ 145932
145932       ⇒ 145932
’"abc"       ⇒ "abc"
"abc"        ⇒ "abc"
’#\a         ⇒ #\a
#\a          ⇒ #\a
’#(a 10)     ⇒ #(a 10)
#(a 10)      ⇒ #(a 10)
’#u8(64 65)  ⇒ #u8(64 65)
#u8(64 65)   ⇒ #u8(64 65)
’#t          ⇒ #t
#t           ⇒ #t

As noted in section 3.4, it is an error to attempt to alter a constant (i.e. the value of a literal expression) using a mutation procedure like set-car! or string-set!.

4.1.3 Procedure calls

(⟨operator⟩ ⟨operand1⟩ ...)    syntax

A procedure call is written by enclosing in parentheses an expression for the procedure to be called followed by expressions for the arguments to be passed to it. The operator and operand expressions are evaluated (in an unspecified order) and the resulting procedure is passed the resulting arguments.

(+ 3 4)            ⇒ 7
((if #f + *) 3 4)  ⇒ 12

The procedures in this document are available as the values of variables exported by the standard libraries. For example, the addition and multiplication procedures in the above examples are the values of the variables + and * in the base library. New procedures are created by evaluating lambda expressions (see section 4.1.4).

Procedure calls can return any number of values (see values in section 6.10). Most of the procedures defined in this report return one value or, for procedures such as apply, pass on the values returned by a call to one of their arguments. Exceptions are noted in the individual descriptions.

Note: In contrast to other dialects of Lisp, the order of evaluation is unspecified, and the operator expression and the operand expressions are always evaluated with the same evaluation rules.

Note: Although the order of evaluation is otherwise unspecified, the effect of any concurrent evaluation of the operator and operand expressions is constrained to be consistent with some sequential order of evaluation. The order of evaluation may be chosen differently for each procedure call.

Note: In many dialects of Lisp, the empty list, (), is a legitimate expression evaluating to itself. In Scheme, it is an error.

4.1.4 Procedures

(lambda ⟨formals⟩ ⟨body⟩)     syntax

Syntax: ⟨Formals⟩ is a formal arguments list as described below, and ⟨body⟩ is a sequence of zero or more definitions followed by one or more expressions.

Semantics: A lambda expression evaluates to a procedure. The environment in effect when the lambda expression was evaluated is remembered as part of the procedure. When the procedure is later called with some actual arguments, the environment in which the lambda expression was evaluated will be extended by binding the variables in the formal argument list to fresh locations, and the corresponding actual argument values will be stored in those locations. (A fresh location is one that is distinct from every previously existing location.) Next, the expressions in the body of the lambda expression (which, if it contains definitions, represents a letrec* form — see section 4.2.2) will be evaluated sequentially in the extended environment. The results of the last expression in the body will be returned as the results of the procedure call.

(lambda (x) (+ x x))       ⇒ a procedure

((lambda (x) (+ x x)) 4)   ⇒ 8

(define reverse-subtract
  (lambda (x y) (- y x)))
(reverse-subtract 7 10)    ⇒ 3

(define add4
  (let ((x 4))
    (lambda (y) (+ x y))))
(add4 6)                   ⇒ 10

⟨Formals⟩ have one of the following forms:

It is an error for a ⟨variable⟩ to appear more than once in ⟨formals⟩.

((lambda x x) 3 4 5 6) ⇒ (3 4 5 6)
((lambda (x y . z) z)
  3 4 5 6)             ⇒ (5 6)

Each procedure created as the result of evaluating a lambda expression is (conceptually) tagged with a storage location, in order to make eqv? and eq? work on procedures (see section 6.1).

4.1.5 Conditionals

(if ⟨test⟩ ⟨consequent⟩ ⟨alternate⟩)     syntax
(if ⟨test⟩ ⟨consequent⟩)                 syntax

Syntax: ⟨Test⟩, ⟨consequent⟩, and ⟨alternate⟩ are expressions.

Semantics: An if expression is evaluated as follows: first, ⟨test⟩ is evaluated. If it yields a true value (see section 6.3), then ⟨consequent⟩ is evaluated and its values are returned. Otherwise ⟨alternate⟩ is evaluated and its values are returned. If ⟨test⟩ yields a false value and no ⟨alternate⟩ is specified, then the result of the expression is unspecified.

(if (> 3 2) ’yes ’no)  ⇒ yes
(if (> 2 3) ’yes ’no)  ⇒ no
(if (> 3 2)
    (- 3 2)
    (+ 3 2))           ⇒ 1

4.1.6 Assignments

(set! ⟨variable⟩ ⟨expression⟩)    syntax

Semantics: ⟨Expression⟩ is evaluated, and the resulting value is stored in the location to which ⟨variable⟩ is bound. It is an error if ⟨variable⟩ is not bound either in some region enclosing the set! expression or else globally. The result of the set! expression is unspecified.

(define x 2)
(+ x 1)       ⇒ 3

(set! x 4)    ⇒ unspecified
(+ x 1)       ⇒ 5

4.1.7 Inclusion

(include ⟨string1⟩ ⟨string2⟩ ...)        syntax
(include-ci ⟨string1⟩ ⟨string2⟩ ...)     syntax

Semantics: Both include and include-ci take one or more filenames expressed as string literals, apply an implementation-specific algorithm to find corresponding files, read the contents of the files in the specified order as if by repeated applications of read, and effectively replace the include or include-ci expression with a begin expression containing what was read from the files. The difference between the two is that include-ci reads each file as if it began with the #!fold-case directive, while include does not.

Note: Implementations are encouraged to search for files in the directory which contains the including file, and to provide a way for users to specify other directories to search.