8. Expression Language

The expression language is inspired by the Scheme Programming Language defined in the IEEE Scheme standard, R4RS. The following specification is based on this definition.

The expression language differs from Scheme in a number of ways:

In addition, DSSSL specifies certain choices that the definition of Scheme leaves open to implementations.

A subset of the expression language, called the core expression language, is defined in “Core Expression Language”.

8.1. Overview of the Expression Language

Following Algol, the expression language is statically scoped. Each use of a variable is associated with a lexically apparent binding of that variable.

The expression language has latent as opposed to manifest types. Types are associated with values (also called objects) rather than with variables. (Some authors refer to languages with latent types as weakly typed or dynamically typed languages.) Other languages with latent types are other dialects of Lisp, APL, and Snobol. Languages with manifest types (sometimes referred to as strongly typed or statically typed languages) include Algol 60, Pascal, and C.

All objects created in the course of a computation, including procedures, have unlimited extent. No expression language object is ever destroyed. The reason that implementations do not (usually!) run out of storage is that they are permitted to reclaim the storage occupied by an object if they can prove that the object cannot possibly matter to any future computation. Other languages in which most objects have unlimited extent include other dialects of Lisp and APL.

Implementations are required to be properly tail-recursive. This allows the execution of an iterative computation in constant space, even if the iterative computation is described by a syntactically recursive procedure. Thus, with a tail-recursive implementation, iteration may be expressed using the ordinary procedure-call mechanics, so that special iteration constructs are useful only as syntactic sugar.

Procedures are objects in their own right. Procedures may be created dynamically, stored in data structures, returned as results of procedures, and so on. Other languages with these properties include Common Lisp and ML.

Arguments to procedures are always passed by value, which means that the actual argument expressions are evaluated before the procedure gains control, whether the procedure needs the result of the evaluation or not. ML, C, and APL are three other languages that always pass arguments by value. This is distinct from the lazy-evaluation semantics of Haskell, or the call-by-name semantics of Algol 60, where an argument expression is not evaluated unless its value is needed by the procedure.

The expression language, like most dialects of Lisp, employs a fully parenthesized prefix notation for expressions and (other) data; the grammar of the expression language generates a sublanguage of the language used for data.

8.2. Basic Concepts

8.2.1. Variables and Regions

Any identifier that is not a syntactic-keyword may be used as a variable. A variable may name a value. A variable that does so is said to be bound to the value. The set of all visible bindings in effect at some point is known as the environment in effect at that point. The value to which a variable is bound is called the variable's value.

Certain expression types are used to bind variables to new values. The most fundamental of these binding constructs is the lambda expression, because all other binding constructs can be explained in terms of lambda expressions. The other binding constructs are let, let*, and letrec expressions.

Like Algol and Pascal, and unlike most other dialects of Lisp except for Common Lisp, the expression language is a statically scoped language with block structure. To each place where a variable is bound in an expression there corresponds a region of the expression text within which the binding is effective. The region is determined by the particular binding construct that establishes the binding; if the binding is established by a lambda expression, for example, then its region is the entire lambda expression. Every reference to, or assignment of, a variable refers to the binding of the variable that established the innermost of the regions containing the use. If there is no binding of the variable whose region contains the use, then the use refers to the binding for the variable in the top-level environment, if any; if there is no binding for the identifier, it is said to be unbound.

8.2.2. True and False

Any expression language value may be used as a boolean value for the purpose of a conditional test. All values count as true in such a test except for #f. This International Standard uses the word “true” to refer to any value that counts as true, and the word “false” to refer to #f.

8.2.3. External Representations

An important concept in the expression language (and Lisp) is that of the external representation of an object as a sequence of characters. For example, an external representation of the integer 28 is the sequence of characters “28”, and an external representation of a list consisting of the integers 8 and 13 is the sequence of characters “(8 13)”.

The external representation of an object is not necessarily unique. The list in the previous paragraph also has the representations “( 08 13 )” and “(8 . (13 . ()))”.

Many objects have external representations, but some, such as procedures, do not.

An external representation may be written in an expression to obtain the corresponding object.

External representations may also be used for communicating between processes defined in this International Standard.

The syntax of external representations of various kinds of objects accompanies the description of the primitives for manipulating the objects.

8.2.4. Disjointness of Types

No object satisfies more than one of the following predicates:

boolean?
pair?
symbol?
keyword?
quantity?
char?
string?
procedure?

These predicates define the types boolean, pair, symbol, keyword, quantity, char (or character), string, and procedure.

8.3. Expressions

An expression is a construct that returns a value, such as a variable reference, literal, procedure call, or conditional.

[16] expression = primitive-expression | derived-expression

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 explained in terms of the primitive constructs. They are redundant in the strict sense of the word, but they capture common patterns of usage, and are, therefore, provided as convenient abbreviations.

8.3.1. Primitive Expression Types

[17] primitive-expression = variable-reference | literal | procedure-call | lambda-expression | conditional

8.3.1.1. Variable Reference

[18] variable-reference = variable

An expression consisting of a variable is a variable reference. The value of the variable reference is the value to which the variable is bound. It shall be an error to reference an unbound variable.

EXAMPLE 5

(define x 28)
x   ==> 28

[19] variable = identifier

[20] syntactic-keyword = expression-keyword | else | => | define

[21] expression-keyword = quote | lambda | if | cond | and | or | case | let | let* | letrec | quasiquote | unquote | unquote-splicing

Any identifier that is not a syntactic-keyword may be used as a variable. DSSSL languages may reserve identifiers as syntactic-keywords in addition to those listed above.

8.3.1.2. Literals

[22] literal = quotation | self-evaluating

[23] quotation = 'datum | (quote datum)

(quote datum) evaluates to datum.

[24] datum = simple-datum | list

[25] simple-datum = boolean | number | character | string | symbol | keyword | named-constant | glyph-identifier

datum may be any external representation of an expression language object. This notation is used to include literal constants in expressions. A glyph-identifier is allowed only within a style-language-body.

EXAMPLE 6

(quote a)                     ==> a
(quote (+ 1 2))               ==> (+ 1 2)

(quote datum) may be abbreviated as 'datum. The two notations are equivalent in all respects.

EXAMPLE 7

'a                   ==> a
'()                  ==> ()
'(+ 1 2)             ==> (+ 1 2)
'(quote a)           ==> (quote a)
''a                  ==> (quote a)

[26] self-evaluating = boolean | number | character | string | keyword | named-constant | glyph-identifier

Boolean constants, numerical constants, character constants, string constants, keywords,named constants, and glyph identifiers evaluate “to themselves”; they need not be quoted.

EXAMPLE 8

'"abc"     ==> "abc"
"abc"      ==> "abc"
'145932    ==> 145932
145932     ==> 145932
'#t        ==> #t
#t         ==> #t
abc:       ==> abc:
'abc:      ==> abc:

8.3.1.3. Procedure Call

[27] procedure-call = (operator operand*)

[28] operator = expression

[29] operand = expression

A procedure call is written by simply enclosing in parentheses expressions for the procedure to be called and the arguments to be passed to it. The operator and operand expressions are evaluated, and the resulting procedure is passed the resulting arguments.

EXAMPLE 9

(+ 3 4)                  ==>  7
((if #f + *) 3 4)        ==> 12

If more than one of the operator or operand expressions signals an error, it is system-dependent which of the errors will be reported to the user.

A number of procedures are available as the values of variables in the initial environment; for example, the addition and multiplication procedures in the above examples are the values of the variables + and *. New procedures are created by evaluating lambda expressions.

Procedure calls are also called combinations.

NOTE 7: In contrast to other dialects of Lisp, the operator expression and the operand expressions are always evaluated with the same evaluation rules.

8.3.1.4. Lambda Expression

[30] lambda-expression = (lambda (formal-argument-list) body)

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 shall be extended by binding the variables in the formal argument list to the corresponding actual argument values, and the body of the lambda expression shall be evaluated in the extended environment. The result of the body shall be returned as the result of the procedure call.

EXAMPLE 10

(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

[31] formal-argument-list = required-formal-argument* (#!optional optional-formal-argument*)? (#!rest rest-formal-argument)? (#!key keyword-formal-argument*)?

[32] required-formal-argument = variable

[33] optional-formal-argument = variable | ((variable initializer))

[34] rest-formal-argument = variable

[35] keyword-formal-argument = variable | ((variable initializer))

[36] initializer = expression

When the procedure is applied to a list of actual arguments, the formal and actual arguments are processed from left to right as follows:

  1. Variables in required-formal-arguments are bound to successive actual arguments starting with the first actual argument. It shall be an error if there are fewer actual arguments than required-formal-arguments.

  2. Next variables in optional-formal-arguments are bound to remaining actual arguments. If there are fewer remaining actual arguments than optional-formal-arguments, then the variables are bound to the result of evaluating initializer, if one was specified, and otherwise to #f. The initializer is evaluated in an environment in which all previous formal arguments have been bound.

  3. If there is a rest-formal-argument, then it is bound to a list of all remaining actual arguments. These remaining actual arguments are also eligible to be bound to keyword-formal-arguments. If there is no rest-formal-argument and there are no keyword-formal-arguments, then it shall be an error if there are any remaining actual arguments.

  4. If #!key was specified in the formal-argument-list, there shall be an even number of remaining actual arguments. These are interpreted as a series of pairs, where the first member of each pair is a keyword specifying the argument name, and the second is the corresponding value. It shall be an error if the first member of a pair is not a keyword. It shall be an error if the argument name is not the same as a variable in a keyword-formal-argument, unless there is a rest-formal-argument. If the same argument name occurs more than once in the list of actual arguments, then the first value is used. If there is no actual argument for a particular keyword-formal-argument, then the variable is bound to the result of evaluating initializer if one was specified, and otherwise to #f. The initializer is evaluated in an environment in which all previous formal arguments have been bound.

    NOTE 8: Use of #!key in a formal-argument-list in the transformation language or style language requires the keyword feature.

It shall be an error for a variable to appear more than once in a formal-argument-list.

EXAMPLE 11

((lambda x x) 3 4 5 6)          ==> (3 4 5 6)
((lambda (x y #!rest z) z)
 3 4 5 6)                       ==> (5 6)
((lambda (x y #!optional z #!rest r #!key i (j 1)) (list x y z i: i j: j))
 3 4 5 i: 6 i: 7)               ==> (3 4 5 i: 6 j: 1)

8.3.1.5. Conditional Expression

[37] conditional = (if test consequent alternate)

[38] test = expression

[39] consequent = expression

[40] alternate = expression

A conditional is evaluated as follows: first, test is evaluated. If it yields a true value, then consequent is evaluated and its value is returned. Otherwise, alternate is evaluated and its value is returned.

EXAMPLE 12

(if (> 3 2) 'yes 'no)   ==> yes
(if (> 2 3) 'yes 'no)   ==> no
(if (> 3 2)
    (- 3 2)
    (+ 3 2))            ==> 1

8.3.2. Derived Expression Types

[41] derived-expression = cond-expression | case-expression | and-expression | or-expression | binding-expression | named-let | quasiquotation

8.3.2.1. Cond-expression

[42] cond-expression = (cond cond-clause+) | (cond cond-clause* (else expression))

[43] cond-clause = (test expression) | (test) | (test => recipient)

[44] recipient = expression

A cond-expression is evaluated by evaluating the test expressions of each successive cond-clause in order until one of them evaluates to a true value. When a test evaluates to a true value, then the result of evaluating the expression in the cond-clause is returned as the result of the entire cond expression. If the selected cond-clause contains only the test and no expression, then the value of the test is returned as the result. If the cond-clause contains a recipient, then recipient is evaluated. Its value shall be a procedure of one argument; this procedure is then invoked on the value of the test. If all tests evaluate to false values, and there is no else clause, then an error is signaled; if there is an else clause, then the result of evaluating its expression is returned.

EXAMPLE 13

(cond ((> 3 2) 'greater)
      ((< 3 2) 'less))   ==> greater

(cond ((> 3 3) 'greater)
      ((< 3 3) 'less)
      (else 'equal))     ==> equal

8.3.2.2. Case-expression

[45] case-expression = (case key case-clause+) | (case key case-clause* (else expression))

[46] key = expression

[47] case-clause = ((datum*) expression)

All the datums shall be distinct. A case-expression is evaluated as follows. key is evaluated and its result is compared against each datum. If the result of evaluating key is equal (in the sense of equal?) to a datum, then the result of evaluating the expression in the corresponding case-clause is returned as the result of the case-expression. If the result of evaluating key is different from every datum, and if there is an else clause, then the result of evaluating its expression is the result of the case-expression; otherwise, an error is signaled.

EXAMPLE 14

(case (* 2 3)
  ((2 3 5 7) 'prime)
  ((1 4 6 8 9) 'composite))     ==> composite
(case (car '(c d))
  ((a e i o u) 'vowel)
  ((w y) 'semivowel)
  (else 'consonant))            ==> consonant

8.3.2.3. And-expression

[48] and-expression = (and test*)

The test expressions are evaluated from left to right, and the value of the first expression that evaluates to a false value is returned. Any remaining expressions are not evaluated. If all the expressions evaluate to true values, the value of the last expression is returned. If there are no expressions then #t is returned.

EXAMPLE 15

(and (= 2 2) (> 2 1))           ==> #t
(and (= 2 2) (< 2 1))           ==> #f
(and 1 2 'c '(f g))             ==> (f g)
(and)                           ==> #t

8.3.2.4. Or-expression

[49] or-expression = (or test*)

The test expressions are evaluated from left to right, and the value of the first expression that evaluates to a true value is returned. Any remaining expressions are not evaluated. If all expressions evaluate to false values, the value of the last expression is returned. If there are no expressions then #f is returned.

EXAMPLE 16

(or (= 2 2) (> 2 1))     ==> #t
(or (= 2 2) (< 2 1))     ==> #t
(or #f #f #f)            ==> #f

8.3.2.5. Binding expressions

[50] binding-expression = let-expression | let*-expression | letrec-expression

The three binding constructs let, let*, and letrec give the expression language a block structure, like Algol 60. The syntax of the three constructs is identical, but they differ in the regions they establish for their variable bindings. In a let expression, the initial values are computed before any of the variables become bound; in a let* expression, the bindings and evaluations are performed sequentially; while in a letrec expression, all the bindings are in effect while their initial values are being computed, thus allowing mutually recursive definitions.

[51] let-expression = (let bindings body)

[52] bindings = (binding-spec*)

[53] binding-spec = (variable init)

[54] init = expression

It shall be an error for a variable to appear more than once in any bindings. The inits are evaluated in the current environment, the variables are bound to the results, and the result of evaluating body in the extended environment is returned. Each binding of a variable has body as its region.

EXAMPLE 17

(let ((x 2) (y 3))
  (* x y))               ==> 6

(let ((x 2) (y 3))
  (let ((x 7)
        (z (+ x y)))
    (* z x)))            ==> 35

See also named-let.

[55] let*-expression = (let* bindings body)

A let*-expression is similar to a let-expression, but the bindings are performed sequentially from left to right, and the region of a binding indicated by a binding-spec is that part of the let*-expression to the right of the binding-spec. Thus, the second binding is done in an environment in which the first binding is visible, and so on.

EXAMPLE 18

(let ((x 2) (y 3))
  (let* ((x 7)
         (z (+ x y)))
    (* z x)))                   ==> 70

[56] letrec-expression = (letrec bindings body)

Each variable in a binding-spec is bound to the result of evaluating the corresponding init, and the result of evaluating body in the extended environment is returned. The inits are evaluated in the extended environment. Each binding of a variable in a binding-spec has the entire letrec-expression as its region, making it possible to define mutually recursive procedures. It shall be an error if the evaluation of an init references the value of any of the variables. In the most common uses of letrec, all the inits are lambda expressions, and this restriction is satisfied automatically.

EXAMPLE 19

(letrec ((even?
          (lambda (n)
            (if (zero? n)
                #t
                (odd? (- n 1)))))
         (odd?
          (lambda (n)
            (if (zero? n)
                #f
                (even? (- n 1))))))
  (even? 88))
  ==> #t

8.3.2.6. Named-let

[57] named-let = (let variable (binding-spec*) body)

Named let has the same syntax and semantics as ordinary let except that variable is bound within body to a procedure whose formal arguments are the bound variables and whose body is body. Thus, the execution of body may be repeated by invoking the procedure named by variable.

EXAMPLE 20

(let loop ((numbers '(3 -2 1 6 -5))
           (nonneg '())
           (neg '()))
  (cond ((null? numbers) (list nonneg neg))
        ((>= (car numbers) 0)
         (loop (cdr numbers)
               (cons (car numbers) nonneg)
               neg))
        ((< (car numbers) 0)
         (loop (cdr numbers)
               nonneg
               (cons (car numbers) neg)))))
  ==>  ((6 1 3) (-5 -2))

8.3.2.7. Quasiquotation

The following grammar for quasiquote expressions is not context-free. It is presented as a recipe for generating an infinite number of production rules. Imagine a copy of the following rules for D = 1, 2, 3, .... D keeps track of the nesting depth.

[58] quasiquotation = quasiquotation_1

[59] template_0 = expression

[60] quasiquotation_D = `template_D | (quasiquote template_D)

[61] template_D = simple-datum | list-template_D | unquotation_D

[62] list-template_D = (template-or-splice_D*) | (template-or-splice_D+ . template_D) | 'template_D | quasiquotation_D+1

[63] unquotation_D = ,template_D-1 | (unquote template_D-1)

[64] template-or-splice_D = template_D | splicing-unquotation_D

[65] splicing-unquotation_D = ,@template_D-1 | (unquote-splicing template_D-1)

In quasiquotations, a list-template_D may sometimes be confused with either an unquotation_D or a splicing-unquotation_D. The interpretation as an unquotation or splicing-unquotation_D takes precedence.

“Backquote” or “quasiquote” expressions are useful for constructing a list structure when most but not all of the desired structure is known in advance. If no commas appear within the template, the result of evaluating `template is equivalent to the result of evaluating 'template. If a comma appears within the template, however, the expression following the comma is evaluated (“unquoted”), and its result is inserted into the structure instead of the comma and the expression. If a comma appears followed immediately by an at-sign (@), then the following expression shall evaluate to a list; the opening and closing parentheses of the list are then “stripped away” and the elements of the list are inserted in place of the comma at-sign expression sequence.

EXAMPLE 21

`(list ,(+ 1 2) 4)  ==>  (list 3 4)
(let ((name 'a)) `(list ,name ',name))
          ==>  (list a (quote a))
`(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)
          ==>  (a 3 4 5 6 b)
`((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))
          ==>  ((foo 7) . cons)

Quasiquote forms may be nested. Substitutions are made only for unquoted components appearing at the same nesting level as the outermost backquote. The nesting level increases by one inside each successive quasiquotation and decreases by one inside each unquotation.

EXAMPLE 22

`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)
          ==>  (a `(b ,(+ 1 2) ,(foo 4 d) e) f)
(let ((name1 'x)
      (name2 'y))
  `(a `(b ,,name1 ,',name2 d) e))
          ==>  (a `(b ,x ,'y d) e)

The notations `template and (quasiquote template) are identical in all respects. ,expression is identical to (unquote expression), and ,@expression is identical to (unquote-splicing expression).

EXAMPLE 23

(quasiquote (list (unquote (+ 1 2)) 4))  ==>  (list 3 4)
'(quasiquote (list (unquote (+ 1 2)) 4))
  ==>  `(list ,(+ 1 2) 4)  
i.e., (quasiquote (list (unquote (+ 1 2)) 4))

Unpredictable behavior may result if any of the symbols quasiquote, unquote, or unquote-splicing appear in positions within a template other than as described above.

8.4. Definitions

[66] definition = variable-definition | procedure-definition

Definitions may take two possible forms.

[67] variable-definition = (define variable expression)

This syntax is primitive.

[68] procedure-definition = (define (variable formal-argument-list) body)

This form is equivalent to

(define variable
  (lambda (variable formal-argument-list) body))
.

A definition that does not occur within an expression is known as a top-level definition.

A top-level definition

(define variable expression)

evaluates expression in the top-level environment and binds variable to the result in the top-level environment.

EXAMPLE 24

(define add3
  (lambda (x) (+ x 3)))
(add3 3)                            ==>  6
(define first car)
(first '(1 2))                      ==>  1

A single variable shall not be defined by more than one top-level definition in any process specification part. A top-level definition of a variable in a process specification part is ignored if that variable has been defined at the top level in a previous process specification part. See “DSSSL Document Architecture”.

The expression in a top-level definition shall not be evaluated until all top-level variables that would be referenced by evaluating the expression have been defined.

NOTE 9: This constraint does not prevent the definition of mutually recursive procedures, because evaluating a lambda expression does not reference variables that occur free within it.

It shall be an error if it is impossible to evaluate all the expressions occurring in top-level definitions in such a way that this constraint is not violated.

The built-in definition of a variable may be replaced by a top-level definition. The replacement definition shall be used for all references to that variable, even those that occur in process specification parts preceding the part that contains the first top-level definition.

NOTE 10: This rule is not easy to implement, but it allows built-in procedures to be added in future versions of this International Standard without changing the meaning of any conforming DSSSL specifications.

[69] body = definition* expression

Definitions may also occur at the beginning of a body. These are known as internal definitions. The variable defined by an internal definition is local to the body. The region of the binding is the entire body. For example,

(let ((x 5))
  (define foo (lambda (y) (bar x y)))
  (define bar (lambda (a b) (+ (* a b) a)))
  (foo (+ x 3)))                ==>  45

A body containing internal definitions may always be converted into a completely equivalent letrec expression. For example, the let expression in the previous example is equivalent to

(let ((x 5))
  (letrec ((foo (lambda (y) (bar x y)))
           (bar (lambda (a b) (+ (* a b) a))))
    (foo (+ x 3))))

Just as for the equivalent letrec expression, it shall be possible to evaluate each expression of every internal definition in a body without referring to the value of any variable being defined.

8.5. Standard Procedures

This section describes the expression language's built-in procedures. The initial (or “top-level”) environment starts out with a number of variables bound to useful values, most of which are primitive procedures that manipulate data. For example, the variable abs is bound to a procedure of one argument that computes the absolute value of a number, and the variable + is bound to a procedure that computes sums.

It shall be an error for a procedure to be passed an argument of a type that it is not specified to handle.

8.5.1. Booleans

[70] boolean = #t | #f

The standard boolean objects for true and false are written as #t and #f. What really matters, though, are the objects that the conditional expressions (if, cond, and, or) treat as true or false. The phrase “a true value” (or sometimes just “true”) means any object treated as true by the conditional expressions, and the phrase “a false value” (or “false”) means any object treated as false by the conditional expressions.

Of all the standard values, only #f counts as false in conditional expressions. Except for #f, all standard values, including #t, pairs, the empty list, symbols, numbers, strings, and procedures, count as true.

NOTE 11: Programmers accustomed to other dialects of Lisp should be aware that the expression language distinguishes both #f and the empty list from the symbol nil.

Boolean constants evaluate to themselves, so they don't need to be quoted in expressions.

EXAMPLE 25

#t         ==>  #t
#f         ==>  #f
'#f        ==>  #f

8.5.1.1. Negation

(not obj)

not returns #t if obj is false, and returns #f otherwise.

EXAMPLE 26

(not #t)         ==>  #f
(not 3)          ==>  #f
(not (list 3))   ==>  #f
(not #f)         ==>  #t
(not '())        ==>  #f
(not (list))     ==>  #f
(not 'nil)       ==>  #f

8.5.1.2. Boolean Type Predicate

(boolean? obj)

boolean? returns #t if obj is either #t or #f and returns #f otherwise.

EXAMPLE 27

(boolean? #f)         ==>  #t
(boolean? 0)          ==>  #f
(boolean? '())        ==>  #f

8.5.2. Equivalence

(equal? obj1 obj2)

The equal? procedure defines an equivalence relation on objects. It returns #t if obj1 and obj2 should be regarded as the same object, and otherwise returns #f. For objects that have external representations, two objects shall be the same if their external representations are the same. If each of obj1 and obj2 is of type boolean, symbol, char, pair, quantity, or string, then the equal? procedure shall return #t if and only if:

If one of obj1 and obj2 is a procedure and the other is not, then equal? shall return #f. If obj1 and obj2 are both procedures then equal? shall return #f if obj1 and obj2 would return a different value for some arguments, and otherwise shall return either #t or #f.

NOTE 12: In other words equality for procedures is not well defined.

8.5.3. Pairs and Lists

A pair (sometimes called a dotted pair) is a record structure with two fields called the car and cdr fields (for historical reasons). Pairs are created by the procedure cons. The car and cdr fields are accessed by the procedures car and cdr. Pairs are used primarily to represent lists. A list may be defined recursively as either the empty list or a pair whose cdr is a list. More precisely, the set of lists is defined as the smallest set X such that:

The objects in the car fields of successive pairs of a list are the elements of the list. For example, a two-element list is a pair whose car is the first element and whose cdr is a pair whose car is the second element and whose cdr is the empty list. The length of a list is the number of elements, which is the same as the number of pairs.

The empty list is a special object of its own type (it is not a pair); it has no elements and its length is zero.

NOTE 13: The above definitions imply that all lists have finite length and are terminated by the empty list.

[71] list = (datum*) | (datum+ . datum) | abbreviation

The most general notation (external representation) for pairs is the “dotted” notation (c1 . c2) where c1 is the value of the car field and c2 is the value of the cdr field. For example (4 . 5) is a pair whose car is 4 and whose cdr is 5. Note that (4 . 5) is the external representation of a pair, not an expression that evaluates to a pair.

A more streamlined notation may be used for lists: the elements of the list are simply enclosed in parentheses and separated by spaces. The empty list is written () . For example,

(a b c d e)

and

(a . (b . (c . (d . (e . ())))))

are equivalent notations for a list of symbols.

A chain of pairs not ending in the empty list is called an improper list. Note that an improper list is not a list. The list and dotted notations may be combined to represent improper lists:

(a b c . d)

is equivalent to

(a . (b . (c . d)))

Whether a given pair is a list depends upon what is stored in the cdr field.

[72] abbreviation = abbrev-prefix datum

[73] abbrev-prefix = ' | ` | , | ,@

Within literal expressions, the forms 'datum, `datum, ,datum, and ,@datum denote the two-element list whose first element are the symbols quote, quasiquote, unquote, and unquote-splicing, respectively. The second element in each case is datum. This convention is supported so that arbitrary expressions and portions of the specification may be represented as lists. That is, according to the DSSSL expression language grammar, every expression is also a datum, and a transformation-language-body is a sequence of datums.

8.5.3.1. Pair Type Predicate

(pair? obj)

Returns #t if obj is a pair, and otherwise returns #f.

EXAMPLE 28

(pair? '(a . b))        ==>  #t
(pair? '(a b c))        ==>  #t
(pair? '())             ==>  #f

8.5.3.2. Pair Construction Procedure

(cons obj1 obj2)

Returns a pair whose car is obj1 and whose cdr is obj2.

EXAMPLE 29

(cons 'a '())           ==>  (a)
(cons '(a) '(b c d))    ==>  ((a) b c d)
(cons "a" '(b c))       ==>  ("a" b c)
(cons 'a 3)             ==>  (a . 3)
(cons '(a b) 'c)        ==>  ((a b) . c)

8.5.3.3. car Procedure

(car pair)

Returns the contents of the car field of pair. Note that it shall be an error to take the car of the empty list.

EXAMPLE 30

(car '(a b c))          ==>  a
(car '((a) b c d))      ==>  (a)
(car '(1 . 2))          ==>  1
(car '())               ==>  error

8.5.3.4. cdr Procedure

(cdr pair)

Returns the contents of the cdr field of pair. Note that it shall be an error to take the cdr of the empty list.

EXAMPLE 31

(cdr '((a) b c d))      ==>  (b c d)
(cdr '(1 . 2))          ==>  2
(cdr '())               ==>  error

8.5.3.5. c...r Procedures

(caar pair)
(cadr pair)
(cdar pair)
(cddr pair)
(caaar pair)
(caadr pair)
(cadar pair)
(caddr pair)
(cdaar pair)
(cdadr pair)
(cddar pair)
(cdddr pair)
(caaaar pair)
(caaadr pair)
(caadar pair)
(caaddr pair)
(cadaar pair)
(cadadr pair)
(caddar pair)
(cadddr pair)
(cdaaar pair)
(cdaadr pair)
(cdadar pair)
(cdaddr pair)
(cddaar pair)
(cddadr pair)
(cdddar pair)
(cddddr pair)

These procedures are compositions of car and cdr, where for example caddr could be defined by

(define caddr (lambda (x) (car (cdr (cdr x)))))
.

Arbitrary compositions, up to four deep, are provided. There are twenty-eight of these procedures in all.

8.5.3.6. Empty List Type Predicate

(null? obj)

Returns #t if obj is the empty list, and otherwise returns #f.

8.5.3.7. List Type Predicate

(list? obj)

Returns #t if obj is a list, and otherwise returns #f. By definition, all lists have finite length and are terminated by the empty list.

EXAMPLE 32

(list? '(a b c))     ==>  #t
(list? '())          ==>  #t
(list? '(a . b))     ==>  #f

8.5.3.8. List Construction

(list obj ...)

Returns a list of its arguments.

EXAMPLE 33

(list 'a (+ 3 4) 'c)            ==>  (a 7 c)
(list)                          ==>  ()

8.5.3.9. List Length

(length list)

Returns the length of list.

EXAMPLE 34

(length '(a b c))               ==>  3
(length '(a (b) (c d e)))       ==>  3
(length '())                    ==>  0

8.5.3.10. Lists Appendance

(append list ...)

Returns a list consisting of the elements of the first list followed by the elements of the other lists.

EXAMPLE 35

(append '(x) '(y))              ==>  (x y)
(append '(a) '(b c d))          ==>  (a b c d)
(append '(a (b)) '((c)))        ==>  (a (b) (c))

The last argument may actually be any object; an improper list results if the last argument is not a proper list.

EXAMPLE 36

(append '(a b) '(c . d))        ==>  (a b c . d)
(append '() 'a)                 ==>  a

8.5.3.11. List Reversal

(reverse list)

Returns a list consisting of the elements of list in reverse order.

EXAMPLE 37

(reverse '(a b c))              ==>  (c b a)
(reverse '(a (b c) d (e (f))))  ==>  ((e (f)) d (b c) a)

8.5.3.12. Sublist Extraction

(list-tail list k)

Returns the sublist of list obtained by omitting the first k elements. List-tail could be defined by

(define list-tail
  (lambda (x k)
    (if (zero? k)
        x
        (list-tail (cdr x) (- k 1)))))

8.5.3.13. List Access

(list-ref list k)

Returns the kth element of list. (This is the same as the car of (list-tail list k).)

EXAMPLE 38

(list-ref '(a b c d) 2)                 ==>  c
(list-ref '(a b c d)
          (inexact->exact (round 1.8))) ==>  c

8.5.3.14. List Membership

(member obj list)

Returns the first sublist of list whose car is equal? to obj, where the sublists of list are the non-empty lists returned by (list-tail list k) for k less than the length of list. If obj does not occur in list, then #f (not the empty list) is returned.

EXAMPLE 39

(member 'a '(a b c))              ==>  (a b c)
(member 'b '(a b c))              ==>  (b c)
(member 'a '(b c d))              ==>  #f

8.5.3.15. Association Lists

(assoc obj alist)

alist (for “association list”) shall be a list of pairs. This procedure finds the first pair in alist whose car field is equal? to obj and returns that pair. If no pair in alist has obj as its car, then #f (not the empty list) is returned.

EXAMPLE 40

(define e '((a 1) (b 2) (c 3)))
(assoc 'a e)     ==>  (a 1)
(assoc 'b e)     ==>  (b 2)
(assoc 'd e)     ==>  #f

NOTE 14: Although they are ordinarily used as predicates, member and assoc do not have question marks in their names because they return useful values rather than just #t or #f.

8.5.4. Symbols

Symbols are objects whose usefulness rests on the fact that two symbols are identical (in the sense of equal?) if and only if their names are spelled the same way. This is exactly the property needed to represent identifiers, so most implementations of Lisp dialects use them internally for that purpose. Symbols are useful for many other applications; for instance, they may be used the way enumerated values are used in Pascal. Typically, two symbols may be compared for equality in constant time, no matter how long their names.

[74] symbol = identifier

The rules for writing a symbol are exactly the same as the rules for writing an identifier.

8.5.4.1. Symbol Type Predicate

(symbol? obj)

Returns #t if obj is a symbol, and otherwise returns #f.

EXAMPLE 41

(symbol? 'foo)          ==>  #t
(symbol? (car '(a b)))  ==>  #t
(symbol? "bar")         ==>  #f
(symbol? 'nil)          ==>  #t
(symbol? '())           ==>  #f
(symbol? #f)            ==>  #f

8.5.4.2. Symbol to String Conversion

(symbol->string symbol)

Returns the name of symbol as a string.

EXAMPLE 42

(symbol->string 'flying-fish)         ==>  "flying-fish"
(symbol->string
   (string->symbol "Malvina"))        ==>  "Malvina"

8.5.4.3. String to Symbol Conversion

(string->symbol string)

Returns the symbol whose name is string. This procedure may create symbols with names containing special characters, but it is usually a bad idea to create such symbols because they have no external representation. See symbol->string.

EXAMPLE 43

(equal? 'mISSISSIppi 'mississippi)               ==>  #f
(equal? 'bitBlt (string->symbol "bitBlt"))       ==>  #t
(equal? 'JollyWog
        (string->symbol
          (symbol->string 'JollyWog)))           ==>  #t
(string=? "K. Harper, M.D."
          (symbol->string
            (string->symbol "K. Harper, M.D."))  ==>  #t

8.5.5. Keywords

Keywords are similar to symbols. The main difference is that keywords are self-evaluating and therefore do not need to be quoted in expressions. They are used mainly for specifying keyword arguments.

[75] keyword = identifier:

A keyword is a single token; therefore, no whitespace is allowed between the identifier and the :. The : is not considered part of the name of the keyword.

8.5.5.1. Keyword Type Predicate

(keyword? obj)

Returns #t if obj is a keyword, and otherwise returns #f.

8.5.5.2. Keyword to String Conversion

(keyword->string keyword)

Returns the name of keyword as a string.

EXAMPLE 44

(keyword->string Argentina:) ==> "Argentina"

8.5.5.3. String to Keyword Conversion

(string->keyword string)

Returns the keyword whose name is string.

EXAMPLE 45

(string->keyword "foobar") ==> foobar:

8.5.6. Named Constants

[76] named-constant = #!optional | #!rest | #!key

Named-constants are used in formal-argument-lists. They are self-evaluating. The named objects have their own unique (unnamed) type that is distinct from the type of any other object.

8.5.7. Quantities and Numbers

8.5.7.1. Numerical Types

The expression language provides a quantity data type which represents lengths and quantities derived from lengths, such as areas and volumes. The SI meter is used as the base unit for representing quantities. The name of this unit is m. Any quantity may be represented as the product of a number and the base unit raised to the power of an integer. The dimension of a quantity is the power to which the base unit is raised when the quantity is so represented. A quantity with dimension 0 is dimensionless.

It is convenient to be able to express quantities not only in terms of the base unit but also in terms of other derived units.

[77] unit-declaration = (define-unit unit-name expression)

expression shall evaluate to a quantity. A unit-declaration declares the derived quantity unit-name to be equivalent to this quantity. In this context, unit-name is a separate token.

Derived units for centimeters, millimeters, inches, picas, and points, corresponding to the following declarations, are pre-defined.

(define-unit cm 0.01m)
(define-unit mm 0.001m)
(define-unit in 0.0254m)
(define-unit pt 0.0003527778m)
(define-unit pica 0.004233333m)

The number data type is considered to be a subtype of quantity that represents dimensionless quantities. The expression language provides two types of number: reals and integers. Integers are considered to be a subtype of reals, and reals are a subtype of numbers. For example, the integer 3 is also considered to be a real number, which, in turn, is considered to be a (dimensionless) quantity. The types quantity, number, real, and integer are defined by the predicates quantity?, number?, real?, and integer?.

Angle (or more precisely, plane angle) is considered to be a dimensionless quantity (the ratio of two lengths). The integer 1 is equivalent to 1 radian. It is recommended that rad be declared as the name of a derived unit equal to the dimensionless quantity 1.

8.5.7.2. Exactness

It is necessary to distinguish between quantities that are represented exactly and those that may not be. For example, indexes into data structures shall be known exactly. In order to catch uses of inexact quantities where exact quantities are required, the expression language explicitly distinguishes exact from inexact quantities. This distinction is orthogonal to the dimension of type.

Quantities are either exact or inexact. A quantity is exact if it was written as an exact constant or was derived from exact quantities using only exact operations. A quantity is inexact if it was written as an inexact constant, if it was derived using inexact ingredients, or if it was derived using inexact operations. Thus, inexactness is a contagious property of a quantity.

If two implementations produce exact results for a computation that did not involve inexact intermediate results, the two ultimate results shall be mathematically equivalent. This is generally not true of computations involving inexact quantities since approximate methods such as floating point arithmetic may be used, but implementations should make the result as close as practical to the mathematically ideal result.

Rational operations such as + should always produce exact results when given exact arguments. If the operation is unable to produce an exact result, then it may either report the violation of an implementation restriction, or it may silently coerce its result to an inexact value.

With the exception of inexact->exact, the operations described in this section shall generally return inexact results when given any inexact arguments. An operation may, however, return an exact result if it can prove that the value of the result is unaffected by the inexactness of its arguments. For example, multiplication of any quantity by an exact zero may produce an exact zero result, even if the other argument is inexact.

8.5.7.3. Implementation Restrictions

Implementations may also support only a limited range of numbers of any type, subject to the requirements of this section. The supported range for exact numbers of any type may be different from the supported range for inexact numbers of that type. For example, an implementation that uses floating point numbers to represent all its inexact real numbers may support a practically unbounded range of exact integers while limiting the range of inexact reals (and, therefore, the range of inexact integers) to the dynamic range of the floating point format. All implementations are required to support exact integers between -2147483647 and 2147483647.

An implementation shall support exact integers throughout the range of numbers that may be used for indexes of lists and strings or that may result from computing the length of a list or string. The length and string-length procedures shall return an exact integer, and it shall be an error to use anything but an exact integer as an index. Furthermore, any integer constant within the index range, if expressed by an exact integer syntax, shall indeed be read as an exact integer, regardless of any implementation restrictions that may apply outside this range. Finally, the procedures listed below shall always return an exact integer result provided all their arguments are exact integers and the mathematically expected result is representable as an exact integer within the implementation:

+            -             *
quotient     remainder     modulo
max          min           abs
floor        ceiling       truncate
round        expt

If one of these procedures is unable to deliver an exact result when given exact arguments, then it may either report a violation of an implementation restriction or it may silently coerce its result to an inexact number. Such a coercion may cause an error later.

An implementation may use floating point and other approximate representation strategies for inexact numbers.

This International Standard recommends, but does not require, that the IEEE 32-bit and 64-bit floating point standards be followed by implementations that use floating point representations, and that implementations using other representations should match or exceed the precision achievable using these floating point standards.

In particular, implementations that use floating point representations shall follow these rules. A floating point result shall be represented with at least as much precision as is used to express any of the inexact arguments to that operation. It is desirable (but not required) for potentially inexact operations such as sqrt, when applied to exact arguments, to produce exact answers whenever possible (for example the square root of an exact 4 ought to be an exact 2). If, however, an exact quantity is operated upon so as to produce an inexact result (as by sqrt), and if the result is represented as a floating point number, then the most precise floating point format available shall be used; but if the result is represented in some other way, then the representation shall have at least as much precision as the most precise floating point format available.

If an implementation encounters an exact numerical constant that it cannot represent as an exact quantity, then it may either report a violation of an implementation restriction, or it may silently represent the constant by an inexact quantity.

8.5.7.4. Syntax of Numerical Constants

[78] number = num-2 | num-8 | num-10 | num-16

[79] num-2 = #b sign? digit-2+

[80] num-8 = #o sign? digit-8+

[81] num-16 = #x sign? digit-16+

[82] num-10 = #d? sign? decimal exponent? unit?

[83] decimal = digit-10+ | . digit-10+ | digit-10+ . digit-10*

[84] exponent = exponent-marker sign? digit+

[85] exponent-marker = e

[86] unit = unit-name (sign? digit-10+)?

[87] unit-name = letter+

[88] sign = + | -

[89] digit-2 = 0 | 1

[90] digit-8 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7

[91] digit-10 = digit

[92] digit-16 = digit-10 | a | b | c | d | e | f

[93] digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

A quantity may be written in binary, octal, decimal, or hexadecimal by the use of a radix prefix. The radix prefixes are #b (binary), #o (octal), #d (decimal), and #x (hexadecimal). With no radix prefix, a quantity is assumed to be expressed in decimal.

A numerical constant is inexact if it contains a decimal point, an exponent or a unit; otherwise, it is exact.

NOTE 15: The examples used in this section assume that any numerical constant written using an exact notation is indeed represented as an exact quantity. Some examples also assume that certain numerical constants written using an inexact notation may be represented without loss of accuracy; the inexact constants were chosen so that this is likely to be true in implementations that use floating point numbers to represent inexact quantities.

A numerical constant may have a unit suffix. Each unit-name shall be the name of the base unit or shall be declared by a unit-declaration. A unit-name shall not be an exponent-marker. If no number follows the unit-name, the constant is multiplied by the quantity associated with the unit. If a number with no sign or a sign of + follows the unit-name, the constant is multiplied by the quantity associated with the number name raised to the power of the following number. If a number with a sign of - follows the unit-name, the constant is divided by the quantity associated with the unit-name raised to the power of the absolute value of the following number.

8.5.7.5. Number Type Predicates

(quantity? obj)
(number? obj)
(real? obj)
(integer? obj)

These type predicates may be applied to any kind of argument, including non-quantities. They return #t if the object is of the named type, and otherwise they return #f. In general, if a type predicate is true of a quantity, then all higher type predicates are also true of that quantity. Consequently, if a type predicate is false for a quantity, then all lower type predicates are also false for that quantity.

If x is an inexact real number, then (integer? x) is true if and only if (= x (round x)).

EXAMPLE 46

(real? 3)               ==>  #t
(integer? 3.0)          ==>  #t

NOTE 16: The behavior of these type predicates on inexact quantities is unreliable, since any inaccuracy may affect the result.

8.5.7.6. Exactness Predicates

(exact? q)
(inexact? q)

These numerical predicates provide tests for the exactness of a quantity. For any quantity, precisely one of these predicates is true.

8.5.7.7. Comparison Predicates

(= q1 q2 q3 ...)
(< q1 q2 q3 ...)
(> q1 q2 q3 ...)
(<= q1 q2 q3 ...)
(>= q1 q2 q3 ...)

These procedures return #t if their arguments are (respectively): equal, monotonically increasing, monotonically decreasing, monotonically nondecreasing, or monotonically nonincreasing.

These predicates are required to be transitive.

The dimensions of all the arguments shall be identical.

NOTE 17: While it is not an error to compare inexact quantities using these predicates, the results may be unreliable because a small inaccuracy may affect the result; this is especially true of = and zero?.

8.5.7.8. Numerical Property Predicates

(zero? q)
(positive? q)
(negative? q)
(odd? n)
(even? n)

These predicates test a quantity for a particular property, returning #t or #f. See note above.

8.5.7.9. Maximum and Minimum

(max q1 q2 ...)
(min q1 q2 ...)

These procedures return the maximum or minimum of their arguments. The dimensions of all the arguments shall be identical; the dimension of the result shall be the same as the dimension of the arguments.

EXAMPLE 47

(max 3 4)              ==>  4    ; exact
(max 3.9 4)            ==>  4.0  ; inexact

NOTE 18: If any argument is inexact, then the result shall also be inexact (unless the procedure can prove that the inaccuracy is not large enough to affect the result, which is possible only in unusual implementations). If min or max is used to compare quantities of mixed exactness, and the numerical value of the result cannot be represented as an inexact quantity without loss of accuracy, then the procedure may report a violation of an implementation restriction.

8.5.7.10. Addition

(+ q1 ...)

Returns the sum of its arguments, which shall all have the same dimension. The result shall have the same dimension as the arguments.

EXAMPLE 48

(+ 3 4)                 ==>  7
(+ 3)                   ==>  3
(+)                     ==>  0

8.5.7.11. Multiplication

(* q1 ...)

Returns the product of its arguments. The dimension of the result shall be the sum of the dimensions of the arguments.

EXAMPLE 49

(* 4)                   ==>  4
(*)                     ==>  1

8.5.7.12. Subtraction

(- q1 q2)
(- q)
(- q1 q2 ...)

With two or more arguments, returns the difference of its arguments, associating to the left; with one argument, returns the negation of its argument. The dimensions of all the arguments shall be identical. The dimension of the result shall be the same as the dimension of the arguments.

EXAMPLE 50

(- 3 4)                 ==>  -1
(- 3 4 5)               ==>  -6
(- 3)                   ==>  -3

8.5.7.13. Division

(/ q1 q2)
(/ q)
(/ q1 q2 ...)

With two or more arguments, returns the quotient of its arguments, associating to the left; with one argument, returns 1 divided by the argument. The dimension of the result shall be the difference of the dimensions of each of the arguments.

EXAMPLE 51

(/ 3 4 5)               ==>  3/20
(/ 3)                   ==>  1/3

8.5.7.14. Absolute Value

(abs q)

Returns the magnitude of its argument.

EXAMPLE 52

(abs -7)                ==>  7

8.5.7.15. Number-theoretic Division

(quotient n1 n2)
(remainder n1 n2)
(modulo n1 n2)

These procedures implement number-theoretic (integer) division: For positive integers n1 and n2, if n3 and n4 are integers such that n1 = n2n3 +n4 and 0 <= n4 < n2, then the following is true.

(quotient n1 n2)        ==>  n3
(remainder n1 n2)       ==>  n4
(modulo n1 n2)          ==>  n4

For integers n1 and n2 with n2 not equal to 0,

(= n1 (+ (* n2 (quotient n1 n2))
               (remainder n1 n2)))
                                   ==>  #t

provided all numbers involved in that computation are exact. The value returned by quotient always has the sign of the product of its arguments. remainder and modulo differ on negative arguments -- the remainder is either zero or has the sign of the dividend, whereas the modulo always has the sign of the divisor:

EXAMPLE 53

(modulo 13 4)           ==>  1
(remainder 13 4)        ==>  1

(modulo -13 4)          ==>  3
(remainder -13 4)       ==>  -1

(modulo 13 -4)          ==>  -3
(remainder 13 -4)       ==>  1

(modulo -13 -4)         ==>  -1
(remainder -13 -4)      ==>  -1

(remainder -13 -4.0)    ==>  -1.0  ; inexact

8.5.7.16. Real to Integer Conversion

(floor x)
(ceiling x)
(truncate x)
(round x)

These procedures return integers.

floor returns the largest integer not larger than x. ceiling returns the smallest integer not smaller than x. truncate returns the integer closest to x whose absolute value is not larger than the absolute value of x. round returns the closest integer to x, rounding to even when x is halfway between two integers.

round rounds to even for consistency with the default rounding mode specified by the IEEE floating point standard.

If the argument to one of these procedures is inexact, then the result shall also be inexact. If an exact value is needed, the result should be passed to the inexact->exact procedure.

EXAMPLE 54

(floor -4.3)          ==>  -5.0
(ceiling -4.3)        ==>  -4.0
(truncate -4.3)       ==>  -4.0
(round -4.3)          ==>  -4.0

(floor 3.5)           ==>  3.0
(ceiling 3.5)         ==>  4.0
(truncate 3.5)        ==>  3.0
(round 3.5)           ==>  4.0  ; inexact

(round 7)             ==>  7

8.5.7.17. en and Natural Logarithm

(exp x)
(log x)

Returns e raised to the power of x. log computes the natural logarithm of x (not the base-ten logarithm). If x is zero or negative, an error shall be signaled.

8.5.7.18. Trigonometric Functions

(sin x)
(cos x)
(tan x)

sin, cos, and tan return the sine, cosine, and tangent of their arguments, respectively. The result shall be a number.

8.5.7.19. Inverse Trigonometric Functions

(asin x)
(acos x)
(atan x)
(atan q1 q2)

asin, acos, and atan return the arcsine, arccosine, and arctangent of their arguments, respectively. The result shall be a number. The two-argument variant of atan returns the angle of the complex number whose real part is the numerical value of q2 and whose imaginary part is the numerical value of q1; the dimensions of q1 and q2 shall be identical.

asin returns a value in the range -pi/2 to pi/2. acos returns a value in the range 0 to pi. atan returns a value in the range -pi/2 to pi/2.

8.5.7.20. Square Root

(sqrt q)

Returns the square root of q. The dimension of q shall be even. The dimension of the result shall be half the dimension of q. If q is negative, an error is signaled.

8.5.7.21. Exponentiation

(expt x1 x2)

Returns x1 raised to the power x2. (expt x1 0) is defined to be equal to 1.

8.5.7.22. Exactness Conversion

(exact->inexact q)
(inexact->exact q)

Exact->inexact returns an inexact representation of q. The value returned is the inexact quantity that is numerically closest to the argument. If an exact argument has no reasonably close inexact equivalent, then a violation of an implementation restriction may be reported.

Inexact->exact returns an exact representation of q. The value returned is the exact quantity that is numerically closest to the argument. If an inexact argument has no reasonably close exact equivalent, then a violation of an implementation restriction may be reported.

These procedures implement the natural one-to-one correspondence between exact and inexact integers throughout an implementation-dependent range.

8.5.7.23. Quantity to Number Conversion

(quantity->number q)

Returns the number of the quantity q.

8.5.7.24. Number to String Conversion

(number->string number)
(number->string number radix)

Radix shall be an exact integer, either 2, 8, 10, or 16. If omitted, radix defaults to 10. The procedure number->string takes a number and a radix and returns as a string an external representation of the given number in the given radix such that

(let ((number number)
      (radix radix))
  (equal? number
          (string->number (number->string number
                                          radix)
                          radix)))

is true. It shall be an error if no possible result makes this expression true.

If number is inexact, the radix is 10, and the above expression may be satisfied by a result that contains a decimal point, then the result contains a decimal point and is expressed using the minimum number of digits (exclusive of exponent and trailing zeroes) needed to make the above expression true; otherwise, the format of the result is unspecified.

The result returned by number->string never contains an explicit radix prefix.

NOTE 19: If number is an inexact number represented using floating-point numbers, and the radix is 10, then the above expression is normally satisfied by a result containing a decimal point. The unspecified case allows for infinities, NaNs, and non-floating-point representations.

(format-number n string)

Returns a string representation of n. string specifies the format to use as follows:

(format-number-list list obj1 obj2)

Returns a string representation of list, where list is a list of integers. obj1 specifies the format to use for each number. It shall be either a single string specifying the format to use for all numbers in the same manner as format-number or a list of strings with the same number of members as list specifying the format to use for each string in the same manner as format-number. obj2 is either a single string or a list of strings specifying the separator to be used between the strings representing each number; it shall contain either a single string or a list of strings with one fewer members than list.

8.5.7.25. String to Number Conversion

(string->number string)
(string->number string radix)

Returns a number of the maximally precise representation expressed by the given string. radix shall be an exact integer, either 2, 8, 10, or 16. If supplied, radix is a default radix that may be overridden by an explicit radix prefix in string (e.g., [Quot]#o177[Quot]). If radix is not supplied, then the default radix is 10. If string is not a syntactically valid notation for a number, then string->number returns #f.

EXAMPLE 55

(string->number "100")        ==>  100
(string->number "100" 16)     ==>  256
(string->number "1e2")        ==>  100.0

8.5.8. Characters

The character object represents a character.

[94] character = #\ any-character | #\ character-name

[95] character-name = letter (letter | digit | - | .)+

Characters are written using the notation #\character or #\character-name. For example:

If the character in #\any-character is alphabetic, then the character following any-character shall be a delimiter character such as a space or parenthesis. This rule resolves the ambiguous case where, for example, the sequence of characters “#\ space” could be taken to be either a representation of the space character or a representation of the character “#\ s” followed by a representation of the symbol “pace.”

The character-name shall be the name of a character declared in the character repertoire declaration.

Characters written in the #\ notation are self-evaluating. That is, they do not have to be quoted in expressions.

8.5.8.1. Character Properties

Every character has a set of named properties. Each property has a default value.

[96] character-property-declaration = (declare-char-property identifier expression)

This declares identifier to be a character property with the default value equal to the value of expression.

[97] added-char-properties-declaration = (add-char-properties keyword-argument-list character+)

[98] keyword-argument-list = (keyword expression)*

The added-char-properties-declaration adds properties to each of the characters. The keyword-argument-list specifies the properties to be added. The keyword specifies the property name, and the expression specifies the property value. Each property either shall be a property that is pre-defined in this International Standard or it shall be explicitly declared using a character-property-declaration.

The following character property is pre-defined:

Additional properties are pre-defined for the style language.

8.5.8.2. Language-dependent Operations

Certain operations on characters such as case-conversion and collation are dependent on the natural language for which the characters are being used. The language data type describes how language-dependent operations should be performed. Expressions may be evaluated with respect to a current language. It shall be an error to call procedures which use the current language if there is no current language.

Some of the procedures that operate on characters ignore the difference between upper case and lower case. The procedures that ignore case have “-ci” (for “case-insensitive”) embedded in their names. These procedures always behave as if they converted their arguments to upper case. These procedures all use the current language. See “Case-insensitive Character Predicates” for these procedures.

(language? obj)

Returns #t if obj is of type language, and otherwise returns #f.

(current-language)

At any point in a computation there may be a current language. current-language returns the current language if there is one, and otherwise returns #f.

[99] default-language-declaration = (declare-default-language expression)

A default-language-declaration declares the current language which is used initially in the evaluation of an expression. The expression shall evaluate to a language object.

(with-language language proc)

The with-language procedure calls proc, which shall be a procedure of no arguments, with language as the current language.

8.5.8.2.1. Language Definition

[100] language-definition = (define-language variable [[collation-specification? | toupper-specification? | tolower-specification?]])

A language-definition defines variable to be an object of type language.

8.5.8.2.1.1. Collation

[101] collation-specification = (collate [[multi-collating-element-specification* | collating-symbol-specification*]] order-specification )

A collation-specification determines the relative order of strings.

NOTE 20: The syntax of the collation-specification is based on ISO 9945-2, which contains examples that may assist the reader.

[102] multi-collating-element-specification = (element multi-collating-element string)

[103] multi-collating-element = identifier

When two strings are compared, each string is divided up into collating elements. Each collating element is either a single character or a sequence of consecutive characters that is to be treated as a single unit. A multi-collating-element-specification declares that the sequence of characters in the string is to be treated as a collating element. Within the order-specification, this collating element is identified by the multi-collating-element. Identifiers declared as multi-collating-elements shall be distinct from those used as weight-identifiers.

[104] collating-symbol-specification = (symbol weight-identifier)

[105] weight-identifier = identifier

A collating-symbol-specification declares that weight-identifier is a symbolic identifier for a weight, which may be used within the order-specification.

[106] order-specification = (order sort-rules collation-entry*)

[107] sort-rules = ( level-sort-rules+ )

Each order specification defines a number of different comparison levels. If two strings compare equal at the first level, they are compared at the second level. If they also compare equal at the second level, they are compared at the third level. This process is repeated until there are no more levels or until the strings compare unequal. The number of levels in the order specification is determined by the number of level-sort-rules.

[108] level-sort-rules = sort-keyword | ((sort-keyword+))

[109] sort-keyword = forward | backward | position

The level-sort-rules determine for each level how the strings are to be compared. At a given level, each collating-element in the strings to be compared is assigned zero or more weights. This results in an ordered list of weights for each string.

The backward and forward sort-keywords determine the comparison direction for the level. If the backward sort-keyword is specified, then comparison proceeds from the last weight to the first; otherwise, it proceeds from the first weight to the last.

If the position sort-keyword is specified, then the position of the collating element corresponding to each weight is considered when comparing weights. When comparing two weights with different positions, the weight with the earlier position (in the comparison direction) shall collate first.

A single level-sort-rules shall not contain both forward and backward.

[110] collation-entry = (( collating-element level-weight*)) | weight-identifier | collating-element

Each collation entry is associated with a weight determined by its position in the order-specification. The first collation entry is associated with the lowest weight, the second with the next lowest weight, and so on.

When a collation-entry is a weight-identifier, then the effect of the collation-entry is to associate the weight-identifier with the weight with which the collation-entry is associated.

A collation-entry that contains a collating-element serves two purposes. First, it assigns weights for each level to the collating-element. Second, it makes collating-element stand for the weight associated with the collation-entry when the collating-element is used in a weight.

If a level-weight is not specified for some level, then the single weight associated with the collation-entry shall be assigned. For example, a collation-entry of #\a is equivalent to a collation-entry of (#\a #\a).

[111] collating-element = character | multi-collating-element | #t

When #t is used as a collating-element, then the specified weights are assigned to all collating elements to which no weight has been explicitly assigned by a collation-entry.

[112] level-weight = weight | weight-list

[113] weight-list = ( weight* )

The level-weight specifies the weights to be assigned for a particular level.

[114] weight = weight-identifier | multi-collating-element | character | string

Specifying a string is equivalent to specifying a list of the characters it contains.

8.5.8.2.1.2. Case Conversion

[115] toupper-specification = (toupper case-conversion-list)

[116] tolower-specification = (tolower case-conversion-list)

[117] case-conversion-list = ((character character))*

In the case-conversion-list, the upper-case or lower-case equivalent of the first character in each pair is the second character in that pair according as the case-conversion-list occurs in a toupper-specification or a tolower-specification.

8.5.8.3. Character Type Predicate

(char? obj)

Returns #t if obj is a character, and otherwise returns #f.

8.5.8.4. Character Comparison Predicates

(char=? char1 char2)
(char<? char1 char2)
(char>? char1 char2)
(char<=? char1 char2)
(char>=? char1 char2)

These procedures impose a total ordering on the set of characters. All the procedures other than char=? use the current language.

8.5.8.5. Case-insensitive Character Predicates

(char-ci=? char1 char2)
(char-ci<? char1 char2)
(char-ci>? char1 char2)
(char-ci<=? char1 char2)
(char-ci>=? char1 char2)

These procedures are similar to char=? etc., but they treat upper-case and lower-case letters as the same. All these procedures use the current language. For example, (char-ci=? #\A #\a) returns #t.

8.5.8.6. Character Case Conversion

(char-upcase char)
(char-downcase char)

The procedures return the upper- or lower-case equivalent of char as defined by the current language. If char has no upper- or lower-case equivalent, char is returned.

8.5.8.7. Character Properties

(char-property symbol char)
(char-property symbol char obj)

Returns the value of the property symbol of char. If symbol is not a character property, an error is signaled. If char does not have a property symbol, then obj is returned, or if obj was not specified, the default value of the property is returned.

8.5.9. Strings

Strings are sequences of characters.

[118] string = [Quot] string-element* [Quot]

[119] string-element = any-character-other-than-[Quot]-or-\ | \[Quot] | \\ | \character-name;?

Strings are written as sequences of characters enclosed within doublequotes ([Quot]). A doublequote may be written inside a string by escaping it with a backslash (\), as in

"The word \"recursion\" has many meanings."

A backslash may be written inside a string by escaping it with another backslash. Any character may be written inside a string by writing its name after a backslash. The name shall be followed by a semi-colon, unless there are no following characters in the string, or the following character is not a subsequent. The name used here is the same as the name used in #\ syntax for characters.

A string constant may continue from one record to the next and shall contain the characters that separate the two records in the entity.

The length of a string is the number of characters that it contains. This number is a non-negative integer that is fixed when the string is created. The valid indexes of a string are the exact non-negative integers less than the length of the string. The first character of a string has index 0, the second has index 1, and so on.

In phrases such as “the characters of string beginning with index start and ending with index end,” it is understood that the index start is inclusive and the index end is exclusive. Thus, if start and end are the same index, a null substring is referred to, and if start is zero and end is the length of string, then the entire string is referred to.

Some of the procedures that operate on strings ignore the difference between upper and lower case by converting the strings to upper case before performing the operation. The versions that ignore case have “-ci” (for “case-insensitive”) embedded in their names.

8.5.9.1. String Type Predicate

(string? obj)

Returns #t if obj is a string, and otherwise returns #f.

8.5.9.2. String Construction

(string char ...)

Returns a string composed of the arguments.

8.5.9.3. String Length

(string-length string)

Returns the number of characters in the given string.

8.5.9.4. String Access

(string-ref string k)

k shall be a valid index of string. string-ref returns character k of string using zero-origin indexing.

8.5.9.5. String Equivalence

(string=? string1 string2)
(string-ci=? string1 string2)

Return #t if the two strings are the same length and contain the same characters in the same positions, and otherwise return #f. string-ci=? treats upper- and lower-case letters as though they were the same character, but string=? treats upper- and lower-case letters as distinct characters. string-ci=? uses the current language.

(string-equiv? string1 string2 k)

Returns #t if the two strings compare the same at the first k comparison levels of the collation specification of the current language, and otherwise returns #f. k shall be strictly positive.

8.5.9.6. String Comparison

(string<? string1 string2)
(string>? <string1 string2)
(string<=? string1 string2)
(string>=? string1 string2)
(string-ci<? string1 string2)
(string-ci>? string1 string2)
(string-ci<=? string1 string2)
(string-ci>=? string1 string2)

These procedures are the lexicographic extensions to strings of the corresponding orderings on characters. For example, string<? is the lexicographic ordering on strings induced by the ordering char<? on characters. If two strings differ in length but are the same up to the length of the shorter string, the shorter string is considered to be lexicographically less than the longer string. These procedures use the current language.

8.5.9.7. Substring Extraction

(substring string start end)

Returns a string formed from the characters of string beginning with index start (inclusive) and ending with index end (exclusive).

8.5.9.8. String Appendance

(string-append string ...)

Returns a string formed by the concatenation of the given strings.

8.5.9.9. Conversion between Strings and Lists

(string->list string)
(list->string chars)

string->list returns a list of the characters that make up the given string. list->string returns a string formed from the characters in the list chars. string->list and list->string are inverses so far as equal? is concerned.

8.5.10. Procedures

8.5.10.1. Procedure Type Predicate

(procedure? obj)

Returns #t if obj is a procedure, and otherwise returns #f.

EXAMPLE 56

(procedure? car)            ==>  #t
(procedure? 'car)           ==>  #f
(procedure? (lambda (x) (* x x)))
                            ==>  #t
(procedure? '(lambda (x) (* x x)))
                            ==>  #f

8.5.10.2. Procedure Application

(apply proc args)
(apply proc arg1 ... args)

Proc shall be a procedure and args shall be a list. The first (essential) form calls proc with the elements of args as the actual arguments. The second form is a generalization of the first that calls proc with the elements of the list (append (list arg1 ...) args) as the actual arguments.

EXAMPLE 57

(apply + (list 3 4))            ==>  7

(define compose
  (lambda (f g)
    (lambda args
      (f (apply g args)))))

((compose sqrt *) 12 75)        ==>  30

8.5.10.3. Mapping Procedures over Lists

(map proc list1 list2 ...)

The lists shall be lists, and proc shall be a procedure taking as many arguments as there are lists. If more than one list is given, then they shall all be the same length. map applies proc element-wise to the elements of the lists and returns a list of the results, in order from left to right.

EXAMPLE 58

(map cadr '((a b) (d e) (g h)))   ==>  (b e h)

(map (lambda (n) (expt n n))
     '(1 2 3 4 5))                ==>  (1 4 27 256 3125)

(map + '(1 2 3) '(4 5 6))         ==>  (5 7 9)

8.5.10.4. External Procedures

(external-procedure string)

Returns a procedure object which when called shall execute the external procedure with public identifier string. If the system is unable to find the external procedure, then #f is returned. The arguments passed to the procedure object shall be passed to the external procedure. If the number or type of arguments do not match those expected by the external procedure, then an error may be signaled. The result of the external procedure shall be returned as the result of the call of the procedure object.

External procedures should be side-effect free, and implementations are free to assume that they are. They should be used to retrieve information from the system rather than to change the state of the system.

8.5.11. Date and Time

(time)
(time->string k)
(time->string k boolean)

time returns the number of seconds since 1970-01-01 00:00:00 GMT as an integer.

time->string converts an integer representation as returned by time of the time and date into a string in the format of ISO 8601.

If the boolean argument is present and true, then the string representation shall be in GMT; otherwise the string shall be in local time.

(time<? string1 string2)
(time>? string1 string2)
(time<=? string1 string2)
(time>=? string1 string2)

These procedures impose a total ordering on the set of strings that represent dates and times in ISO 8601 format. It shall be an error if any argument does not represent a date or time in ISO 8601 format.

8.5.12. Error Signaling

(error string)

error signals an error. The string argument describes the error. The action a system takes when an error is signaled is system-dependent. In particular, the manner in which the error is reported to the user is system-dependent. It should, however, use string in its report and describe the context in which the error occurred. No value is returned from error.

8.6. Core Expression Language

This clause defines a subset of the expression language called the core expression language. In the core expression language, only those expressions and definitions allowed by the productions in this clause are permitted, and only those procedures with prototypes in this clause are available. Any expression or definition that is valid in the core expression language has the same meaning that it does in the full expression language.

8.6.1. Syntax

[120] expression = primitive-expression | derived-expression

[121] primitive-expression = variable-reference | literal | procedure-call | conditional

[122] variable-reference = variable

[123] variable = identifier

[124] literal = quotation | self-evaluating

[125] quotation = 'datum | (quote datum)

[126] datum = simple-datum | list

[127] simple-datum = boolean | number | character | string | symbol | keyword | glyph-identifier

[128] list = (datum*) | 'datum

[129] self-evaluating = boolean | number | character | string | keyword | glyph-identifier

[130] procedure-call = (operator operand*)

[131] operator = expression

[132] operand = expression

[133] conditional = (if test consequent alternate)

[134] test = expression

[135] consequent = expression

[136] alternate = expression

[137] derived-expression = cond-expression | case-expression | and-expression | or-expression

[138] cond-expression = (cond cond-clause+) | (cond cond-clause* (else expression))

[139] cond-clause = (test expression)

[140] case-expression = (case key case-clause+) | (case key case-clause* (else expression))

[141] key = expression

[142] case-clause = ((datum*) expression)

[143] and-expression = (and test*)

[144] or-expression = (or test*)

[145] definition = (define variable expression)

8.6.2. Procedures

(not obj)
(boolean? obj)
(equal? obj1 obj2)
(null? obj)
(list? obj)
(list obj ...)
(length list)
(append list ...)
(reverse list)
(list-tail list k)
(list-ref list k)
(member obj list)
(symbol? obj)
(keyword? obj)
(quantity? obj)
(number? obj)
(real? obj)
(integer? obj)
(= q1 q2 q3 ...)
(< q1 q2 q3 ...)
(> q1 q2 q3 ...)
(<= q1 q2 q3 ...)
(>= q1 q2 q3 ...)
(max q1 q2 ...)
(min q1 q2 ...)
(+ q1 ...)
(* q1 ...)
(- q1 q2)
(- q)
(/ q1 q2)
(/ q)
(abs q)
(quotient n1 n2)
(remainder n1 n2)
(modulo n1 n2)
(floor x)
(ceiling x)
(truncate x)
(round x)
(sqrt q)
(number->string number)
(number->string number radix)
(string->number string)
(string->number string radix)
(char? obj)
(char=? char1 char2)
(char-property symbol char)
(char-property symbol char obj)
(string? obj)
(string char ...)
(string-length string)
(string-ref string k)
(string=? string1 string2)
(substring string start end)
(string-append string ...)
(procedure? obj)
(apply proc args)
(external-procedure string)
(time)
(time->string k)
(time->string k boolean)
(error string)