(lispkit datatype)
Library (lispkit datatype)
implements algebraic datatypes for LispKit. It provides the following functionality:
define-datatype
creates a new algebraic datatype consisting of a type test predicate and a number of variants. Each variant implicitly defines a constructor and a pattern.define-pattern
introduces a new pattern and constructor for an existing datatype variant.match
matches a value of an algebraic datatype against patterns, binding pattern variables and executing the code of the first case whose pattern matches the value.
Usage
Here is an example of a datatype defining a tree for storing and finding elements:
The datatype tree
defines a predicate tree?
for checking whether a value is of type tree
. In addition, it defines two variants with corresponding constructors empty
and node
for creating values of type tree
. Variant node
defines an invariant that prevents nodes from being constructed unless left
and right
are also trees.
The following line defines a new tree:
Using match
, values like t1
can be deconstructed using pattern matching. The following function elements
shows how to collect all elements from a tree in a list:
match
is a special form which takes a value of an algebraic datatype and matches it against a list of cases. Each case defines a pattern and a sequence of statements which get executed if the pattern matches the value.
Cases can also optionally define a guard which is a boolean expression that gets executed if the pattern of the case matches a value. Only if the guard evaluates to true, the statements of the case get executed. Otherwise, pattern matching continues. The following function insert
demonstrates this functionality:
A new tree t2
, with two new elements inserted, can be created like this:
If a pattern is used frequently containing a lot of boilerplate, it is possible to define a shortcut using the define-pattern
syntax:
With this declaration, it is possible to use single
in patterns. The following example also shows that it is possible to use else
for defining a fallback case, if no other pattern is matching.
single
can also be used as a constructor for creating trees with a single element:
An advanced feature of match
is the usage of pattern alternatives in a single case of a match
construct. This can be achieved using the or
form on the top level of a pattern:
The underscore in the (single _)
subpattern is a wildcard that matches every value and that does not bind a new variable.
API
Defines a new datatype with a given number of datatype variants. The definition requires the symbol type denoting the new type, an optional symbol pred which gets bound to a type test function for testing whether a value is an instance of this type, and a list of constructors of the form (constr arg1 arg2 ...) where constr is the constructor and arg1, arg2, ... are parameter names of the constructor. A constructor can be annotated with an invariant for defining requirements the parameters need to meet. This is done via clause where
expr succeeding the constructor declaration. condition is a boolean expression which gets checked when the constructor gets invoked.
Defines a new pattern (constr arg ...) which specializes an existing pattern (impl expr ...). Such custom patterns can be used in pattern matching expressions as well as constructors for defining values of an algebraic datatype.
match
provides a mechanism for decomposing values of algebraic datatypes via pattern matching. A match
construct takes a value expr to pattern match on, as well as a sequence of cases. Each case consists of pattern alternatives, an optional guard, and a sequence of statements:
match
iterates through the cases and executes the sequence of statements stat ... of the first case whose pattern is matching expr
and whose guard condition evaluates to true. The value returned by this sequence of statements is returned by match
.
Last updated