Scheme has very little syntax. R7RS-small (chapter 4) divides expressions into primitive expression types, from which the others can be explained, and derived ones, which a macro could define. This page lists them all, with the forms they take. The viewer colours every keyword here as syntax.
Primitive expressions
| Form | Meaning |
|---|---|
variable | The value in the variable’s location; it is an error to reference an unbound variable. An identifier bound to syntax is not a variable and cannot be referenced alone |
'datum or (quote datum) | The datum itself, unevaluated; a constant |
constant | Numbers, strings, characters, booleans, vectors and bytevectors evaluate to themselves without a quote. |
(operator operand ...) | A procedure call: the operator and the operands are evaluated in an unspecified order, then the procedure is applied. The operator is an ordinary expression, so ((if x + -) 1 2) is a call |
(lambda formals body) | A procedure. formals is (a b c) for exactly three arguments, args for any number gathered in a list, or (a b . rest) for at least two. See Procedures and numbers |
(if test consequent alternate) | Evaluates the test, then one branch. The alternate may be left out, and then the value is unspecified when the test is false |
(set! variable expression) | Stores the value in the variable’s location. The variable must already be bound; the result is unspecified |
(include "file" ...), (include-ci "file" ...) | Reads the files and splices their forms in like begin; include-ci reads them with case folding |
Conditionals
| Form | Meaning |
|---|---|
(cond clause ...) | Clauses are (test expression ...), (test) which returns the test’s value, or (test => procedure) which calls the procedure on the test’s value. The last clause may be (else expression ...). With no true test and no else the value is unspecified |
(case key clause ...) | Clauses are ((datum ...) expression ...) or ((datum ...) => procedure), compared with eqv?; the last may be (else expression ...) or (else => procedure). The data are not evaluated. The => forms are new in R7RS (SRFI 87) |
(and test ...), (or test ...) | Evaluate left to right and stop at the first false (and) or true (or) value, returning it. (and) is #t and (or) is #f. The last test is in tail position |
(when test expression ...), (unless test expression ...) | Run the expressions if the test is true (when) or false (unless). In R6RS (the control library) and R7RS, not in R5RS; the result when the test fails the condition is unspecified |
(cond-expand clause ...) | Chooses forms at expansion time by feature requirement: an identifier, (library name), (and ...), (or ...), (not ...), and else for the last clause. Features are listed on Standard libraries |
(cond ((assv 'b '((a 1) (b 2))) => cadr)
(else #f)) ; 2
(case (car '(c d))
((a e i o u) 'vowel)
((w y) 'semivowel)
(else => (lambda (x) x))) ; c
(cond-expand
(chibi (import (chibi show)))
((library (srfi 69)) (import (srfi 69)))
(else (import (scheme base))))
=> forms, and a cond-expand that chooses an import.Binding constructs
| Form | Meaning |
|---|---|
(let ((v init) ...) body) | Evaluates the inits, in unspecified order, in the outer scope, then binds the variables and runs the body. A let is a lambda call |
(let name ((v init) ...) body) | Named let: binds name to a procedure of the variables inside the body and calls it with the inits; the usual loop of Scheme |
(let* ((v init) ...) body) | Binds in order, each init seeing the earlier variables |
(letrec ((v init) ...) body) | All variables are in scope in all inits, which should be lambda expressions; referring to a not yet initialised variable is an error |
(letrec* ((v init) ...) body) | Like letrec but binds in order, so an init may use earlier ones. Internal defines are letrec*. New in R6RS and R7RS |
(let-values (((a b) expr) ...) body) | Binds the several values an expression returns; formals as in lambda. let*-values binds in order. In R6RS and R7RS (SRFI 11) |
(define-values formals expr) | Defines several variables from several values (R7RS) |
(let-syntax ...), (letrec-syntax ...) | Bind keywords to macro transformers; see Macros |
(parameterize ((param value) ...) body) | Rebinds parameter objects for the dynamic extent of the body; see Control and tail calls |
(guard (var clause ...) body) | Evaluates the body and handles a raised object; see Error handling |
A body is zero or more definitions then one or more expressions. Definitions may come at the start of the body of lambda, let, let*, letrec, letrec*, let-values, let*-values, let-syntax, letrec-syntax, parameterize, guard and case-lambda; a body is read as a letrec*. R7RS requires definitions to come before expressions; Chez, Guile, Racket and others allow them to be mixed, and SRFI 251 proposes it.
Sequencing and iteration
| Form | Meaning |
|---|---|
(begin expression ...) | Evaluates in order and returns the last. At the top level or the start of a body it may hold definitions, which are then spliced in; this is how a macro expands into several definitions |
(do ((var init step) ...) (test result ...) command ...) | Binds the variables to the inits, then repeats: if the test is true return the results, otherwise run the commands, rebind each variable to its step expression (or leave it when there is none) and loop. The loop is iteration by tail call |
(do ((vec (make-vector 5))
(i 0 (+ i 1)))
((= i 5) vec)
(vector-set! vec i i)) ; #(0 1 2 3 4)
(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))
(else
(loop (cdr numbers) nonneg (cons (car numbers) neg)))))
do loop and a named let loop (R7RS section 4.2.4).Delayed evaluation and dynamic binding
(delay expression)– makes a promise that evaluates the expression the first time it is forced and remembers the value.(force promise)forces it.(delay-force expression)is the form for iterative lazy algorithms that must run in constant space, and(make-promise obj)andpromise?complete the library. All are in(scheme lazy).delayandforceare in R5RS and R6RS;delay-forceandmake-promiseare new in R7RS (SRFI 45).(make-parameter init)or(make-parameter init converter)– makes a procedure of no arguments that returns the current value.(parameterize ((p v) ...) body)binds it for the dynamic extent of the body; the converter is applied to the initial value and to every value given toparameterize.current-input-port,current-output-portandcurrent-error-portare parameter objects in R7RS. SRFI 39 first defined them.
Quasiquotation
(quasiquote template), written `template, builds data from a template. Inside it (unquote e), written ,e, evaluates e and inserts the value, and (unquote-splicing e), written ,@e, evaluates e to a list and splices its elements in. Quasiquotations nest; an unquote at nesting level 1 is evaluated. Inside a vector template unquotes work too. R6RS allows an unquote form with several arguments, which R7RS does not.
`(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)
`#(10 5 ,(sqrt 4) ,@(map sqrt '(16 9)) 8) ; #(10 5 2 4 3 8)
case-lambda
(case-lambda (formals body) ...) makes a procedure that takes one of several argument lists, choosing the first clause whose formals fit the number of arguments. It is in (scheme case-lambda) in R7RS and in the base library of R6RS (SRFI 16 first defined it).
(define range
(case-lambda
((e) (range 0 e))
((b e) (do ((r '() (cons e r))
(e (- e 1) (- e 1)))
((< e b) r)))))
range example of R7RS section 4.2.9.Definitions and the program structure forms
| Form | Meaning |
|---|---|
(define var expression) | Binds a variable. At the top level it acts like set! if the variable is bound and creates the binding otherwise |
(define (name . formals) body) | Shorthand for (define name (lambda formals body)); (define (name . rest) body) is (define name (lambda rest body)) |
(define-values formals expr) | Several definitions from several values |
(define-syntax keyword transformer) | Binds a keyword to a macro transformer, at the top level or in a body |
(define-record-type name ctor pred field ...) | A record type; see Records |
(import set ...), (define-library name decl ...) | See Libraries and modules |
Syntax keywords of R6RS that R7RS-small lacks
(assert expression)– raises an&assertioncondition if the expression is false.(define-enumeration name (symbol ...) constructor)– defines an enumeration type and its constructor syntax;(rnrs enums).(define-condition-type name supertype constructor predicate field-spec ...)– defines a condition type;(rnrs conditions).(identifier-syntax template)– a macro that stands for an expression where a variable would be used, with an optional(set! ...)clause.(syntax-case expr (literal ...) clause ...),(syntax template),(quasisyntax template),(with-syntax ((pattern expr) ...) body),unsyntax,unsyntax-splicing– the procedural macro system of(rnrs syntax-case); see Macros.(endianness big),(file-options no-fail),(buffer-mode block),(eol-style lf),(error-handling-mode replace)– symbol-checking syntax of the bytevector and I/O libraries.(library name (export ...) (import ...) body)– an R6RS library.(guard ...),(case-lambda ...),(let-values ...),(define-record-type ...)are also in R6RS; their R6RS forms differ in detail (for example R6RScasehas no=>).
Syntax that implementations add
These are not in the reports; the viewer colours them as syntax because they are common.
define-structure,define-integrable,fluid-let,named-lambda,cons-stream,the-environment(MIT/GNU Scheme).define-macro,defmacro,define-syntax-rule,use-modules,define-module,define*,lambda*,while,match,match-lambda(Guile).declare,use,define-constant,define-inline,module,require-extension,import-for-syntax-style forms (CHICKEN).receive(SRFI 8),and-let*(SRFI 2),cutandcute(SRFI 26),rec(SRFI 31),assume(SRFI 145),let-optionals,let1,dotimes,dolist(Gauche and others),er-macro-transformer,sc-macro-transformer,rsc-macro-transformer,ir-macro-transformer.
Not described
Known, not yet covered
- Reference: the formal semantics of chapter 7 of R7RS is not described.
- Reference: the evaluation order of operands, the interaction of
definewith the REPL, and the exact result values that the reports call unspecified are not described. - Reference: the forms an implementation adds are named in the list above and not described.
See also
- Control and tail calls – how these forms run
- Macros – defining new forms
- Standard libraries – which library exports which keyword