4.2 Terms

► |  | Redex: Practical Semantics Engineering

1 | Amb: A Redex Tutorial
2 | Long Tutorial
3 | Extended Exercises
4 | The Redex Reference
5 | Automated Testing Benchmark
| Bibliography
| Index

▼ | 4 | The Redex Reference

4.1 | Patterns
4.2 | Terms
4.3 | Languages
4.4 | Reduction Relations
4.5 | Other Relations
4.6 | Testing
4.7 | GUI
4.8 | Typesetting

On this page:

term
hole
in-hole
mf-apply
term-let
term-define
redex-let
redex-let*
redex-define
define-term
term-match
term-match/ single
plug
variable-not-in
variables-not-in
exn: fail: redex?

9.2
Racket
top contents ← prev up next →

### 4.2 Terms🔗ℹ

Object language expressions in Redex are written using term. It is similar to Racket’s quote (in many cases it is identical) in that it constructs lists as the visible representation of terms.

The grammar of terms is (note that an ellipsis stands for repetition unless otherwise indicated):

term |  | = |  | identifier
|  | | |  | (term-sequence ...)
|  | | |  | ,expr
|  | | |  | (in-hole term term)
|  | | |  | hole
|  | | |  | (mf-apply identifier term ...)
|  | | |  | datum
term-sequence |  | = |  | term
|  | | |  | ,@expr
|  | | |  | ... ; literal ellipsis

- A term written identifier is equivalent to the corresponding symbol, unless the identifier is bound by term-let, term-define, define-term, or a pattern variable or the identifier is hole (as below).

- A term written (term-sequence ...) constructs a list of the terms constructed by the sequence elements.

- A term written ,expr evaluates expr and substitutes its value into the term at that point.

- A term written ,@expr evaluates the expr, which must produce a list. It then splices the contents of the list into the expression at that point in the sequence.

- A term written (in-hole term term) is the dual to the pattern in-hole – it accepts a context and an expression and uses plug to combine them.

- A term written hole produces a hole.

- A term written (mf-apply f arg ...) asserts that f is a metafunction and produces the term (f arg ...).

- A term written as any other datum not listed above produces that datum. For example, (term (1 x #t)) is the same as '(1 x #t).

  Term substitution and metafunction application do not occur within compound datums. For example,

  > (term-let ([a 1]) (term #hash((x . a))))

  is the same as '#hash((x . a)), not '#hash((x . 1)).

> syntax (term term)
> (term term #:lang lang-id)

Used for construction of a term.

The term form behaves similarly to quasiquote, except for a few special forms that are recognized (listed below) and that names bound by term-let and term-define are implicitly substituted with the values that those names were bound to, expanding ellipses as in-place sublists (in the same manner as syntax-case patterns).

The optional #:lang keyword must supply an identifier bound by define-language, and adds a check that any symbol containing an underscore in term could have been bound by a pattern in the language referenced by lang-id. In practice, this means that the underscore must be preceded by a non-terminal in that language or a built-in pattern such as number. This form of term is used internally by default, so this check is applied to terms that are constructed by Redex forms such as reduction-relation and define-metafunction.

For example,

> (term-let ([body '(+ x 1)]
> [(expr ...) '(+ - (values * /))]
> [((id ...) ...) '((a) (b) (c d))])
> (term (let-values ([(id ...) expr] ...) body)))

evaluates to

> '(let-values ([(a) +]
> [(b) -]
> [(c d) (values * /)])
> (+ x 1))

It is an error for a term variable to appear in an expression with an ellipsis-depth different from the depth with which it was bound by term-let. It is also an error for two term-let-bound identifiers bound to lists of different lengths to appear together inside an ellipsis.

Symbols in a term whose names end in guillemets (French quotes) around a number (for example asdf«5000») will be modified to contain a smiley face character (for example asdf«5000☺»). This is to prevent collisions with names generated by the freshening process that binding forms use.

> syntax hole

Recognized specially within terms. A hole form is an error elsewhere.

> syntax in-hole

Recognized specially within terms. An in-hole form is an error elsewhere.

> syntax mf-apply

Recognized specially within terms. A mf-apply form is an error elsewhere.

> syntax (term-let ([tl-pat expr] ...) body)
> tl-pat |  | = |  | identifier
> |  | | |  | (tl-pat-ele ...)
> tl-pat-ele |  | = |  | tl-pat
> |  | | |  | tl-pat ... ; a literal ellipsis

Matches each given id pattern to the value yielded by evaluating the corresponding expression and binds each variable in the id pattern to the appropriate value (described below). These bindings are then accessible to the term syntactic form.

Note that each ellipsis should be the literal symbol consisting of three dots (and the ... elsewhere indicates repetition as usual). If tl-pat is an identifier, it matches any value and binds it to the identifier, for use inside term. If it is a list, it matches only if the value being matched is a list value and only if every subpattern recursively matches the corresponding list element. There may be a single ellipsis in any list pattern; if one is present, the pattern before the ellipses may match multiple adjacent elements in the list value (possibly none).

This form is a lower-level form in Redex, and not really designed to be used directly. For let-like forms that use Redex’s full pattern matching facilities, see redex-let, redex-let*, term-match, term-match/single.

Examples:

> > (term-let ([x 1]
> [y #t]
> [z '(p q r)])
> (term (x y z)))
> '(1 #t (p q r))
> > (term-let ([((init ... last) ...) '((1 2 3 x) (4 5 y))])
> (term (last ...)))
> '(x y)
> > (term-let ([((init ... last) ...) '((1 2 3 x) (4 5 y))])
> (term ((~@ init init) ... ...)))
> '(1 1 2 2 3 3 4 4 5 5)

> syntax (term-define tl-pat expr)

The define analog of term-let.

Examples:

> > (term-define z '(p q r))
> > (term z)
> '(p q r)
> > (term-define ((init ... last) ...)
> '((1 2 3 x) (4 5 y)))
> > (term (last ...))
> '(x y)
> > (term ((~@ init init) ... ...))
> '(1 1 2 2 3 3 4 4 5 5)

Added in version 1.21 of package redex-lib.

> syntax (redex-let language ([pattern expression] ...) body ...+)

Like term-let but the left-hand sides are Redex patterns, interpreted according to the specified language. It is a syntax error for two left-hand sides to bind the same pattern variable.

This form raises an exception recognized by exn:fail:redex? if any right-hand side does not match its left-hand side in exactly one way.

In some contexts, it may be more efficient to use term-match/single (lifted out of the context).

> syntax (redex-let* language ([pattern expression] ...) body ...+)

The let* analog of redex-let.

> syntax (redex-define language pattern expression)

The define analog of redex-let. The form redex-define evaluates expression, matches the result against pattern and binds the corresponding identifiers.

Examples:

> > (define-language Larith
> (AE number
> (+ AE AE)))
> > (redex-define Larith (name AE_all (+ AE_common AE_common)) (term (+ 4 4)))
> > (term (AE_all AE_common))
> '((+ 4 4) 4)
> > (redex-define Larith AE_stx-err (term (+ (+ 0 #f) 1)))
> redex-define: term (+ (+ 0 #f) 1) does not match pattern
> AE_stx-err
> > (redex-define Larith (+ AE_same AE_same) (term (+ 6 3)))
> redex-define: term (+ 6 3) does not match pattern (+ AE_same
> AE_same)

Examples:

> > (define-language Lempty)
> > (redex-define Lempty (number ...) (term (2 1 7)))
> > (term ((~@ number number) ...))
> '(2 2 1 1 7 7)

Added in version 1.21 of package redex-lib.

> syntax (define-term identifier term)

Defines identifier for use in term templates. To pattern match and bind identifiers against term, see redex-define.

> syntax (term-match language [pattern expression] ...)

Produces a procedure that accepts term (or quoted) expressions and checks them against each pattern. The function returns a list of the values of the expression where the pattern matches. If one of the patterns matches multiple times, the expression is evaluated multiple times, once with the bindings in the pattern for each match.

When evaluating a term-match expression, the patterns are compiled in an effort to speed up matching. Using the procedural result multiple times to avoid compiling the patterns multiple times.

> syntax (term-match/single language [pattern expression] ...)

Produces a procedure that accepts term (or quoted) expressions and checks them against each pattern. The function returns the expression behind the first successful match. If that pattern produces multiple matches, an error is signaled. If no patterns match, an error is signaled.

The term-match/single form raises an exception recognized by exn:fail:redex? if no clauses match or if one of the clauses matches multiple ways.

When evaluating a term-match/single expression, the patterns are compiled in an effort to speed up matching. Using the procedural result multiple times to avoid compiling the patterns multiple times.

> procedure (plug context expression) → any
> context : any/c
> expression : any/c

The first argument to this function is an term to plug into. The second argument is the term to replace in the first argument. It returns the replaced term. This is also used when a term sub-expression contains in-hole.

> procedure (variable-not-in t prefix) → symbol?
> t : any/c
> prefix : symbol?

A helper function that accepts a term and a variable. It returns a symbol that not in the term, where the variable has prefix as a prefix.

> procedure (variables-not-in t vars) → (listof symbol?)
> t : any/c
> vars : (listof symbol?)

Like variable-not-in, create variables that do no occur in t—but returning a list of such variables, one for each variable in its second argument.

The variables-not-in function does not expect the symbols in vars to be distinct, but it does produce a list of distinct symbols.

> procedure (exn:fail:redex? v) → boolean?
> v : any/c

Returns #t if its argument is a Redex exception record, and #f otherwise.
top contents ← prev up next →