Copyright © 2005 Michael K K Montague
This document is based on the Revised(5) Report on the Algorithmic Language Scheme.Permission is granted to make and distribute whole or partial copies of this document without any restrictions.
(Yet Another) Tiny Scheme is a partial implementation of Revised(5) Report on the Algorithmic Language Scheme. It is designed for embedding in applications.
(quote
datum)
evaluates to datum. datum may be any external representation of a Scheme object. 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)
may 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, and boolean constants evaluate “to themselves”; they need not be quoted.
'"abc" => "abc" "abc" => "abc" '145932 => 145932 145932 => 145932 '#t => #t #t => #t
(
operator operand1 ...)
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 (in an unspecified order) and the resulting procedure is passed the resulting arguments.
(+ 3 4) => 7 ((if #f + *) 3 4) => 12
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 return one value.
Syntax: formals should be a formal arguments list as described below, and body should be a sequence of 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, the corresponding actual argument values will be stored in those locations, and the expressions in the body of the lambda expression will be evaluated sequentially in the extended environment. The result of the last expression in the body will be returned as the result of the procedure call.
(lambda (x) (+ x x)) => #<procedure: #x123456> ((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) => 10formals should have one of the following forms:
(
variable1...)
: The procedure takes a fixed number of arguments; when the procedure is called, the arguments will be stored in the bindings of the corresponding variables.- variable: The procedure takes any number of arguments; when the procedure is called, the sequence of actual arguments is converted into a newly allocated list, and the list is stored in the binding of the variable.
(
variable1...
variable_n . variable_n+1)
: If a space-delimited period precedes the last variable, then the procedure takes n or more arguments, where n is the number of formal arguments before the period (there must be at least one). The value stored in the binding of the last variable will be a newly allocated list of the actual arguments left over after all the other actual arguments have been matched up against the other formal arguments.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)
expression is evaluated, and the resulting value is stored in the location to which variable is bound. variable must be bound either in some region enclosing the
set!
expression or at top level. The result of theset!
expression is unspecified.
Syntax: test, consequent, and alternate may be arbitrary expressions.
Semantics: An
if
expression 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. 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
Syntax: Each clause should be of the form
(test expression1 ...)where test is any expression. Alternatively, a clause may be of the form
(test => expression)The last clause may be an “else clause,” which has the form
(else expression1 expression2 ...)Semantics: A
cond
expression is evaluated by evaluating the test expressions of successive clauses in order until one of them evaluates to a true value. When a test evaluates to a true value, then the remaining expressions in its clause are evaluated in order, and the result of the last expression in the clause is returned as the result of the entirecond
expression. If the selected clause contains only the test and no expressions, then the value of the test is returned as the result. If the selected clause uses the=>
alternate form, then the expression is evaluated. Its value must be a procedure that accepts one argument; this procedure is then called on the value of the test and the value returned by this procedure is returned by thecond
expression. If all tests evaluate to false values, and there is no else clause, then the result of the conditional expression is unspecified; if there is an else clause, then its expressions are evaluated, and the value of the last one is returned.(cond ((> 3 2) 'greater) ((< 3 2) 'less)) => greater (cond ((> 3 3) 'greater) ((< 3 3) 'less) (else 'equal)) => equal (cond ((assv 'b '((a 1) (b 2))) => cadr) (else #f)) => 2
Syntax: key may be any expression. Each clause should have the form
((datum1 ...) expression1 expression2 ...)where each datum is an external representation of some object. All the datums must be distinct. The last clause may be an “else clause,” which has the form
(else expression1 expression2 ...)Semantics: 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 equivalent (in the sense ofeqv?
) to a datum, then the expressions in the corresponding clause are evaluated from left to right and the result of the last expression in the clause is returned as the result of thecase
expression. If the result of evaluating key is different from every datum, then if there is an else clause its expressions are evaluated and the result of the last is the result of thecase
expression; otherwise the result of thecase
expression is unspecified.(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
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.(and (= 2 2) (> 2 1)) => #t (and (= 2 2) (< 2 1)) => #f (and 1 2 'c '(f g)) => (f g) (and) => #t
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.(or (= 2 2) (> 2 1)) => #t (or (= 2 2) (< 2 1)) => #t (or #f #f #f) => #f (or (memq 'b '(a b c)) (/ 3 0)) => (b c)
The two binding constructs let
and letrec
give Scheme a block structure, like Algol 60. The syntax of the two
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;
while in a letrec
expression, all the bindings are in
effect while their initial values are being computed, thus allowing
mutually recursive definitions.
Syntax: bindings should have the form
((variable1 init1) ...)where each init is an expression, and body should be a sequence of one or more expressions. It is an error for a variable to appear more than once in the list of variables being bound.
Semantics: The inits are evaluated in the current environment (in some unspecified order), the variables are bound to fresh locations holding the results, the body is evaluated in the extended environment, and the value of the last expression of body is returned. Each binding of a variable has body as its region.
(let ((x 2) (y 3)) (* x y)) => 6 (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x))) => 35
Syntax: bindings should have the form
((variable1 init1) ...)and body should be a sequence of one or more expressions. It is an error for a variable to appear more than once in the list of variables being bound.
Semantics: The variables are bound to fresh locations holding undefined values, the inits are evaluated in the resulting environment (in some unspecified order), each variable is assigned to the result of the corresponding init, the body is evaluated in the resulting environment, and the value of the last expression in body is returned. Each binding of a variable has the entire
letrec
expression as its region, making it possible to define mutually recursive procedures.(letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88)) => #tOne restriction on
letrec
is very important: it must be possible to evaluate each init without assigning or referring to the value of any variable. If this restriction is violated, then it is an error. The restriction is necessary because Scheme passes arguments by value rather than by name. In the most common uses ofletrec
, all the inits are lambda expressions and the restriction is satisfied automatically.
The expressions are evaluated sequentially from left to right, and the value of the last expression is returned. This expression type is used to sequence side effects such as input and output.
(define x 0) (begin (set! x 5) (+ x 1)) => 6
A Scheme program consists of a sequence of expressions and definitions. Expressions are described in chapter Expressions; definitions are the subject of the rest of the present chapter.
Definitions occurring at the top level of a program can be interpreted declaratively. They cause bindings to be created in the top level environment or modify the value of existing top-level bindings. Expressions occurring at the top level of a program are interpreted imperatively; they are executed in order when the program is invoked or loaded, and typically perform some kind of initialization.
At the top level of a program (begin
form1 ...)
is
equivalent to the sequence of expressions, definitions, and syntax definitions
that form the body of the begin
.
Definitions are valid in some, but not all, contexts where expressions are allowed. They are valid only at the top level of a program and at the beginning of a body.
A definition should have one of the following forms:
(define
variable expression)
(define (
variable formals)
body)
formals should be either a sequence of zero or more variables, or a sequence of one or more variables followed by a space-delimited period and another variable (as in a lambda expression). This form is equivalent to
(define variable (lambda (formals) body))
(define (
variable .
formal)
body)
formal should be a single variable. This form is equivalent to
(define variable (lambda formal body))
At the top level of a program, a definition
(define variable expression)
has essentially the same effect as the assignment expression
(set! variable expression)
if variable is bound. If variable is not bound,
however, then the definition will bind variable to a new
location before performing the assignment, whereas it would be an error
to perform a set!
on an unbound variable.
(define add3 (lambda (x) (+ x 3))) (add3 3) => 6 (define first car) (first '(1 2)) => 1
Definitions may occur at the
beginning of a body (that is, the body of a lambda
,
let
, or letrec
expression or that of a definition of an appropriate form).
Such definitions are known as internal definitions as opposed to the top level definitions described above.
The variable defined by an internal definition is local to the
body. That is, variable is bound rather than assigned,
and 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 can always be converted
into a completely equivalent letrec
expression. For example, the
let
expression in the above 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 must be possible to evaluate each expression of every internal definition in a body without assigning or referring to the value of any variable being defined.
Wherever an internal definition may occur
(begin
definition1 ...)
is equivalent to the sequence of definitions
that form the body of the begin
.
A predicate is a procedure that always returns a boolean
value (#t
or #f
). An equivalence predicate is
the computational analogue of a mathematical equivalence relation (it is
symmetric, reflexive, and transitive). Of the equivalence predicates
described in this section, eq?
is the finest or most
discriminating, and equal?
is the coarsest. Eqv?
is
slightly less discriminating than eq?
.
The
eqv?
procedure defines a useful equivalence relation on objects. Briefly, it returns#t
if obj1 and obj2 should normally be regarded as the same object.The
eqv?
procedure returns#t
if:
- obj1 and obj2 are both
#t
or both#f
.- obj1 and obj2 are both symbols and
(string=? (symbol->string obj1) (symbol->string obj2)) => #t- obj1 and obj2 are both numbers and are numerically equal according to the
=
procedure (see Numbers).- obj1 and obj2 are both characters and are the same character according to the
char=?
procedure (see Characters).- both obj1 and obj2 are the empty list.
- obj1 and obj2 are pairs, vectors, or strings that denote the same locations.
- obj1 and obj2 are the same procedure.
The
eqv?
procedure returns#f
if:
- obj1 and obj2 are of different types.
- one of obj1 and obj2 is
#t
but the other is#f
.- obj1 and obj2 are symbols but
(string=? (symbol->string obj1) (symbol->string obj2)) => #f- obj1 and obj2 are numbers for which the
=
procedure returns#f
.- obj1 and obj2 are characters for which the
char=?
procedure returns#f
.- one of obj1 and obj2 is the empty list but the other is not.
- obj1 and obj2 are pairs, vectors, or strings that denote distinct locations.
- obj1 and obj2 are different procedures.
(eqv? 'a 'a) => #t (eqv? 'a 'b) => #f (eqv? 2 2) => #t (eqv? '() '()) => #t (eqv? 100000000 100000000) => #t (eqv? (cons 1 2) (cons 1 2)) => #f (eqv? (lambda () 1) (lambda () 2)) => #f (eqv? #f 'nil) => #f (let ((p (lambda (x) x))) (eqv? p p)) => #t
eq?
is similar toeqv?
except that in some cases it is capable of discerning distinctions finer than those detectable byeqv?
.
eq?
andeqv?
are guaranteed to have the same behavior on symbols, booleans, the empty list, pairs, procedures, and non-empty strings and vectors.(eq? 'a 'a) => #t (eq? (list 'a) (list 'a)) => #f (eq? '() '()) => #t (eq? car car) => #t (let ((x '(a))) (eq? x x)) => #t (let ((x '#())) (eq? x x)) => #t (let ((p (lambda (x) x))) (eq? p p)) => #t
equal?
recursively compares the contents of pairs, vectors, and strings, applyingeqv?
on other objects such as numbers and symbols. A rule of thumb is that objects are generallyequal?
if they print the same.equal?
may fail to terminate if its arguments are circular data structures.(equal? 'a 'a) => #t (equal? '(a) '(a)) => #t (equal? '(a (b) c) '(a (b) c)) => #t (equal? "abc" "abc") => #t (equal? 2 2) => #t (equal? (make-vector 5 'a) (make-vector 5 'a)) => #t
The only numberical type supported by Tiny Scheme is exact integers.
These numerical type predicates can be applied to any kind of argument, including non-numbers. They return
#t
if the object is of the named type, and otherwise they return#f
.(number? 10) => #t (number? 'a) => #f (integer? 10) => #t (integer? 'a) => #f
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.
These numerical predicates test a number for a particular property, returning
#t
or#f
.
These procedures return the maximum or minimum of their arguments.
These procedures return the sum or product of their arguments.
(+ 3 4) => 7 (+ 3) => 3 (+) => 0 (* 4) => 4 (*) => 1
With two or more arguments, these procedures return the difference or quotient of their arguments, associating to the left. With one argument, however, they return the additive or multiplicative inverse of their argument.
(- 3 4) => -1 (- 3 4 5) => -6 (- 3) => -3 (/ 40 4 5) => 2
This procedure implements number-theoretic (integer) division. n2 should be non-zero.
(remainder 13 4) => 1 (remainder -13 4) => -1 (remainder 13 -4) => 1 (remainder -13 -4) => -1
radix must 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. The result returned bynumber->string
never contains an explicit radix prefix.
Returns a number of the maximally precise representation expressed by the given string. If string is not a syntactically valid notation for a number, then
string->number
returns#f
.
The standard boolean objects for true and false are written as
#t
and #f
. What really
matters, though, are the objects that the Scheme 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 Scheme values, only #f
counts as false in conditional expressions.
Except for #f
,
all standard Scheme values, including #t
,
pairs, the empty list, symbols, numbers, strings, vectors, and procedures,
count as true.
Programmers accustomed to other dialects of Lisp should be aware that
Scheme distinguishes both #f
and the empty list
from the symbol nil
.
Boolean constants evaluate to themselves, so they do not need to be quoted in programs.
#t => #t #f => #f '#f => #f
not
returns#t
if obj is false, and returns#f
otherwise.(not #t) => #f (not 3) => #f (not (list 3)) => #f (not #f) => #t (not '()) => #f (not (list)) => #f (not 'nil) => #f
boolean?
returns#t
if obj is either#t
or#f
and returns#f
otherwise.(boolean? #f) => #t (boolean? 0) => #f (boolean? '()) => #f
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
. The car and cdr fields are assigned by the procedures
set-car!
and set-cdr!
.
Pairs are used primarily to represent lists. A list can be defined recursively as either the empty list or a pair whose cdr is a list. 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.
The empty list is written ()
.
A chain of pairs not ending in the empty list is called an improper list. Note that an improper list is not a list.
pair?
returns#t
if obj is a pair, and otherwise returns#f
.(pair? '(a . b)) => #t (pair? '(a b c)) => #t (pair? '()) => #f (pair? '#(a b)) => #f
Returns a newly allocated pair whose car is obj1 and whose cdr is obj2. The pair is guaranteed to be different (in the sense of
eqv?
) from every existing object.(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)
Returns the contents of the car field of pair. Note that it is an error to take the car of the empty list.
(car '(a b c)) => a (car '((a) b c d)) => (a) (car '(1 . 2)) => 1
Returns the contents of the cdr field of pair. Note that it is an error to take the cdr of the empty list.
(cdr '((a) b c d)) => (b c d) (cdr '(1 . 2)) => 2
Stores obj in the car field of pair. The value returned by
set-car!
is unspecified.
Stores obj in the cdr field of pair. The value returned by
set-cdr!
is unspecified.
Returns
#t
if obj is a list, otherwise returns#f
. By definition, all lists have finite length and are terminated by the empty list.(list? '(a b c)) => #t (list? '()) => #t (list? '(a . b)) => #f (let ((x (list 'a))) (set-cdr! x x) (list? x)) => #f
Returns a newly allocated list of its arguments.
(list 'a (+ 3 4) 'c) => (a 7 c) (list) => ()
Returns the length of list.
(length '(a b c)) => 3 (length '(a (b) (c d e))) => 3 (length '()) => 0
Returns a list consisting of the elements of the first list followed by the elements of the other lists.
(append '(x) '(y)) => (x y) (append '(a) '(b c d)) => (a b c d) (append '(a (b)) '((c))) => (a (b) (c))The resulting list is always newly allocated, except that it shares structure with the last list argument. The last argument may actually be any object; an improper list results if the last argument is not a proper list.
(append '(a b) '(c . d)) => (a b c . d) (append '() 'a) => a
Returns a newly allocated list consisting of the elements of list in reverse order.
(reverse '(a b c)) => (c b a) (reverse '(a (b c) d (e (f)))) => ((e (f)) d (b c) a)
Returns the sublist of list obtained by omitting the first k elements. It is an error if list has fewer than k elements.
list-tail
could be defined by(define list-tail (lambda (x k) (if (zero? k) x (list-tail (cdr x) (- k 1)))))
Returns the kth element of list. (This is the same as the car of
(list-tail
list k)
.) It is an error if list has fewer than k elements.(list-ref '(a b c d) 2) => c
These procedures return the first sublist of list whose car is 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.memq
useseq?
to compare obj with the elements of list, whilememv
useseqv?
andmember
usesequal?
.(memq 'a '(a b c)) => (a b c) (memq 'b '(a b c)) => (b c) (memq 'a '(b c d)) => #f (memq (list 'a) '(b (a) c)) => #f (member (list 'a) '(b (a) c)) => ((a) c) (memv 101 '(100 101 102)) => (101 102)
alist (for “association list”) must be a list of pairs. These procedures find the first pair in alist whose car field is obj, and returns that pair. If no pair in alist has obj as its car, then
#f
(not the empty list) is returned.assq
useseq?
to compare obj with the car fields of the pairs in alist, whileassv
useseqv?
andassoc
usesequal?
.(define e '((a 1) (b 2) (c 3))) (assq 'a e) => (a 1) (assq 'b e) => (b 2) (assq 'd e) => #f (assq (list 'a) '(((a)) ((b)) ((c)))) => #f (assoc (list 'a) '(((a)) ((b)) ((c)))) => ((a)) (assv 5 '((2 3) (5 7) (11 13))) => (5 7)
Symbols are objects whose usefulness rests on the fact that two
symbols are identical (in the sense of eqv?
) if and only if their
names are spelled the same way.
It is guaranteed that any symbol that has been returned as part of
a literal expression, or read using the read
procedure, and
subsequently written out using the write
procedure, will read back
in as the identical symbol (in the sense of eqv?
). The
string->symbol
procedure, however, can create symbols for
which this write/read invariance may not hold because their names
contain special characters or letters in the non-standard case.
Returns
#t
if obj is a symbol, otherwise returns#f
.(symbol? 'foo) => #t (symbol? (car '(a b))) => #t (symbol? "bar") => #f (symbol? 'nil) => #t (symbol? '()) => #f (symbol? #f) => #f
Returns the name of symbol as a string. If the symbol was part of an object returned as the value of a literal expression or by a call to the
read
procedure, and its name contains alphabetic characters, then the string returned will contain characters in lower case. If the symbol was returned bystring->symbol
, the case of characters in the string returned will be the same as the case in the string that was passed tostring->symbol
. It is an error to apply mutation procedures likestring-set!
to strings returned by this procedure.(symbol->string 'flying-fish) => "flying-fish" (symbol->string 'Martin) => "martin" (symbol->string (string->symbol "Malvina")) => "Malvina"
Returns the symbol whose name is string. This procedure can create symbols with names containing special characters or letters in the non-standard case, but it is usually a bad idea to create such symbols because in some implementations of Scheme they cannot be read as themselves. See
symbol->string
.(eq? 'mISSISSIppi 'mississippi) => #t (string->symbol "mISSISSIppi") => mISSISSIppi (eq? 'bitBlt (string->symbol "bitBlt")) => #f (eq? 'JollyWog (string->symbol (symbol->string 'JollyWog))) => #t (string=? "K. Harper, M.D." (symbol->string (string->symbol "K. Harper, M.D."))) => #t
Characters are objects that represent printed characters such as letters and digits. Characters are written using the notation #\character. Case is significant. If character in #\character is alphabetic, then the character following character must be a delimiter character such as a space or parenthesis. Characters written in the #\ notation are self-evaluating. That is, they do not have to be quoted in programs.
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 impose a total ordering on the set of characters.
These procedures are similar to
char=?
et cetera, but they treat upper case and lower case letters as the same. For example,(char-ci=? #\A #\a)
returns#t
.
These procedures return
#t
if their arguments are alphabetic, numeric, or whitespace characters, respectively, otherwise they return#f
.
Given a character,
char->integer
returns an exact integer representation of the character. Given an exact integer that is the image of a character underchar->integer
,integer->char
returns that character. These procedures implement order-preserving isomorphisms between the set of characters under thechar<=?
ordering and some subset of the integers under the<=
ordering.
These procedures return a character char2 such that
(char-ci=?
char char2)
. In addition, if char is alphabetic, then the result ofchar-upcase
is upper case and the result ofchar-downcase
is lower case.
Strings are sequences of characters.
Strings are written as sequences of characters enclosed within doublequotes
("
). A doublequote can be written inside a string only by escaping
it with a backslash (\).
A backslash can be written inside a string only by escaping it with another
backslash.
A string constant may continue from one line to the next.
The length of a string is the number of characters that it contains. This number is an exact, 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. The versions that ignore case
have -ci
(for “case insensitive”) embedded in their
names.
make-string
returns a newly allocated string of length k. If char is given, then all elements of the string are initialized to char, otherwise the contents of the string are unspecified.
k must be a valid index of string.
string-ref
returns character k of string using zero-origin indexing.
k must be a valid index of string.
string-set!
stores char in element k of string and returns an unspecified value.
Returns
#t
if the two strings are the same length and contain the same characters in the same positions, otherwise returns#f
.string-ci=?
treats upper and lower case letters as though they were the same character, butstring=?
treats upper and lower case as distinct characters.
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 orderingchar<?
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.
string must be a string, and start and end must be exact integers satisfying
0 <= start <= end <=(string-length
string)
substring
returns a newly allocated string formed from the characters of string beginning with index start (inclusive) and ending with index end (exclusive).
Returns a newly allocated string whose characters form the concatenation of the given strings.
string->list
returns a newly allocated list of the characters that make up the given string.list->string
returns a newly allocated string formed from the characters in the list list, which must be a list of characters.string->list
andlist->string
are inverses so far asequal?
is concerned.
Stores char in every element of the given string and returns an unspecified value.
Vectors are heterogenous structures whose elements are indexed by integers. A vector typically occupies less space than a list of the same length, and the average time required to access a randomly chosen element is typically less for the vector than for the list.
The length of a vector is the number of elements that it contains. This number is a non-negative integer that is fixed when the vector is created. The valid indexes of a vector are the exact non-negative integers less than the length of the vector. The first element in a vector is indexed by zero, and the last element is indexed by one less than the length of the vector.
Vectors are written using the notation #(
obj ...,)
.
For example, a vector of length 3 containing the number zero in element
0, the list (2 2 2 2)
in element 1, and the string "Anna"
in
element 2 can be written as following:
#(0 (2 2 2 2) "Anna")
Note that this is the external representation of a vector, not an expression evaluating to a vector. Like list constants, vector constants must be quoted:
'#(0 (2 2 2 2) "Anna") => #(0 (2 2 2 2) "Anna")
Returns a newly allocated vector of k elements. If a second argument is given, then each element is initialized to fill. Otherwise the initial contents of each element is unspecified.
Returns a newly allocated vector whose elements contain the given arguments. Analogous to
list
.(vector 'a 'b 'c) => #(a b c)
k must be a valid index of vector.
vector-ref
returns the contents of element k of vector.(vector-ref '#(1 1 2 3 5 8 13 21) 5) => 8
k must be a valid index of vector.
vector-set!
stores obj in element k of vector. The value returned byvector-set!
is unspecified.(let ((vec (vector 0 '(2 2 2 2) "Anna"))) (vector-set! vec 1 '("Sue" "Sue")) vec) => #(0 ("Sue" "Sue") "Anna")
vector->list
returns a newly allocated list of the objects contained in the elements of vector.list->vector
returns a newly created vector initialized to the elements of the list list.(vector->list '#(dah dah didah)) => (dah dah didah) (list->vector '(dididit dah)) => #(dididit dah)
Stores fill in every element of vector. The value returned by
vector-fill!
is unspecified.
Returns
#t
if obj is a procedure, otherwise returns#f
.(procedure? car) => #t (procedure? 'car) => #f (procedure? (lambda (x) (* x x))) => #t (procedure? '(lambda (x) (* x x))) => #f
proc must be a procedure and args must be a list. Calls proc with the elements of the list
(append (list
arg1...,)
args)
as the actual arguments.(apply + (list 3 4)) => 7 (define compose (lambda (f g) (lambda args (f (apply g args))))) ((compose sqrt *) 12 75) => 30
The lists must be lists, and proc must be a procedure taking as many arguments as there are lists and returning a single value. If more than one list is given, then they must 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. The dynamic order in which proc is applied to the elements of the lists is unspecified.(map cadr '((a b) (d e) (g h))) => (b e h) (map (lambda (n) (* n n)) '(1 2 3 4 5)) => (1 4 9 16 25) (map + '(1 2 3) '(4 5 6)) => (5 7 9) (let ((count 0)) (map (lambda (ignored) (set! count (+ count 1)) count) '(a b))) => (1 2)
The arguments to
for-each
are like the arguments tomap
, butfor-each
calls proc for its side effects rather than for its values. Unlikemap
,for-each
is guaranteed to call proc on the elements of the lists in order from the first element(s) to the last, and the value returned byfor-each
is unspecified.(let ((v (make-vector 5))) (for-each (lambda (i) (vector-set! v i (* i i))) '(0 1 2 3 4)) v) => #(0 1 4 9 16)
Writes a written representation of obj to the current output. Strings that appear in the written representation are enclosed in doublequotes, and within those strings backslash and doublequote characters are escaped by backslashes. Character objects are written using the
#\
notation.write
returns an unspecified value.
Writes a representation of obj to the current output. Strings that appear in the written representation are not enclosed in doublequotes, and no characters are escaped within those strings. Character objects appear in the representation as if written by
write-char
instead of bywrite
.display
returns an unspecified value.
write
is intended for producing machine-readable output anddisplay
is for producing human-readable output.
Writes the character char (not an external representation of the character) to the current output and returns an unspecified value.
Tiny Scheme is a partial implementation of Revised(5) Report on the Algorithmic Language Scheme. In particular the following features are not supported.
call-with-current-continuation
, call-with-values
, and
dynamic-wind
are not available.
values
is
not available.
let-syntax
,
letrec-syntax
, syntax-rules
, and define-syntax
are
not available.
eval
is not available.
Notes about the implementation of Tiny Scheme.