On this page:
constructor
constructor?
define-constructor
Constructor  Top
Constructor  Top?
constructor-values
7.1

3 Constructors

Constructors are implemented as tagged structures, using a single special field: values. The constructor identifier and its derivatives therefore call tagged, using that single field. The identifiers described within this section provide some syntactic sugar, allowing constructors to contain more than one value. These values are wrapped in a (possibly improper) list which is stored within the tagged structure’s values field.

type-expander

(constructor tag-name maybe-∀ τᵢ ...)

(constructor tag-name maybe-∀ τᵢ ... . dotted-τ-rest)
(constructor tag-name maybe-∀ τᵢ ... #:rest τ-rest)
 
tag-name = Identifier
     
maybe-∀ = 
  | #:∀ (tvarⱼ ...)
     
τᵢ = xlist-type-or-repeated-type
     
τ-rest = xlist-type-or-repeated-type
     
dotted-τ-rest = "like τ-rest, but must not be a syntax pair"
Expands to the type for a constructor with the given tag name and type of contents. The (τᵢ ...), (τᵢ ... . dotted-τ-rest) or (τᵢ ... #:rest τ-rest) sequence is passed unmodified to xlist. Therefore, depending on the syntax used, the expanded type is equivalent to one of the following types:

(tagged tag-name maybe-∀ [values (xlist τᵢ ...)])
(tagged tag-name maybe-∀ [values (xlist τᵢ ... . dotted-τ-rest)])
(tagged tag-name maybe-∀ [values (xlist τᵢ ... #:rest τ-rest)])

The elements may appear in any order, as long as the tag name appears before any element type, and as long as the element types form a contiguous sequence.

syntax

(constructor maybe-∀ tag-name *)

(constructor maybe-∀ tag-name : typeᵢ ...)
(constructor maybe-∀ tag-name ! . xlist-types)
(constructor maybe-∀ tag-name :: . xlist-types)
 
maybe-∀ = 
  | #:∀ (tvarⱼ ...)
     
tag-name = Identifier
     
xlist-types = (τᵢ ...)
  | (τᵢ ... . dotted-τ-rest)
  | (τᵢ ... #:rest τ-rest)
     
τᵢ = xlist-type-or-repeated-type
     
typeᵢ = Type
Expands to a builder function for a constructor with the given tag name and type of contents.

The first syntax, using * and no types, produces a polymorphic builder function which accepts any number of arguments, infers their types, and uses the whole list of arguments as the constructor’s value.

In the following three cases, when #:∀ (tvarⱼ ...) is specified, a polymorphic builder with the tvarⱼ type variables is produced.

The second syntax, using : followed by a sequence of regular types, produces a builder function with one argument per type. The builder function aggregates all its arguments in a list, and uses that list as the constructor’s value.

The second syntax, using ! followed by a sequence of types valid for xlist, produces a builder function which accepts a variable number of arguments. The builder function casts the whole list of arguments to the type (xlist . xlist-types), which must therefore be a suitable argument to make-predicate. The cast list is used as the constructor’s value.

The third syntax, using :: followed by a sequence of types valid for xlist, produces a builder function which accepts a single value of type (xlist . xlist-typed), and uses that value as the constructor’s value.

Usually, the value stored within a constructor will be a list (i.e. a tuple in other languages), but it is possible to store a single value using xlist’s rest syntax:

((constructor #:∀ (A) tag-name :: . A) 123)
((constructor tag-name :: . Number) 123)
((constructor tag-name :: #:rest (Vector Number String)) #(123 "abc"))

The elements may appear in any order, as long as the tag name appears before any element type, and as long as the element types form a contiguous sequence.

syntax

(constructor maybe-∀ tag-name value-maybe-typeᵢ)

(constructor maybe-∀ tag-name value-maybe-typeᵢ . dotted-rest)
(constructor maybe-∀ tag-name value-maybe-typeᵢ #:rest rest)
 
maybe-∀ = 
  | #:∀ (tvarⱼ ...)
     
tag-name = Identifier
     
value-maybe-typeᵢ = valueᵢ
  | [valueᵢ : typeᵢ]
  | [: typeᵢ valueᵢ]
     
rest = value-maybe-typeᵢ
     
dotted-rest = "like rest, but must not be a syntax pair"
Expands to an instance of a constructor containing the given values, grouped inside a list.

When a typeᵢ is specified, it is used to annotate the value, and is used as the type for that element in the resulting constructor type.

When #:∀ (tvarⱼ ...) is specified, the type of values annotated with tvarⱼ is inferred, and an instance of a polymorphic constructor is produced. A tvarⱼ can be used within a more complex type, in which case only that part of the type is inferred.

The elements may appear in any order, as long as the tag name appears before any value, and as long as the values form a contiguous sequence, including the #:rest rest which must appear immediately after the sequence of values, if specified. The dotted-rest, on the other hand, can be separated from the other values, so (constructor foo 1 [2 : A] 3 #:∀ (A) . 4) is a valid (but awkward) use of constructor.

The type of the dotted-rest can still be specified using typed/racket’s reader abbreviation for ann, namely #{dotted-rest :: type}.

match expander

(constructor tag-name . xlist-pats)

 
tag-name = Identifier
     
xlist-pats = (patᵢ ...)
  | (patᵢ ... . dotted-pat-rest)
  | (patᵢ ... #:rest pat-rest)
     
patᵢ = XList-Match-Pattern
Expands to a match pattern which checks whether the value is a constructor with the given tag name, and then matches the constructor’s value against the match pattern (xlist . xlist-pats). The xlist match expander in turn matches each element of a (possibly improper) list against the given patterns, and supports various means of specifying fixed-length, bounded and unbounded repetitions like "must appear between three and five times". See the documentation for the xlist match expander for more details.

syntax

(constructor? tag-name . xlist-types)

 
tag-name = Identifier
     
xlist-types = (τᵢ ...)
  | (τᵢ ... . dotted-τ-rest)
  | (τᵢ ... #:rest τ-rest)
     
τᵢ = xlist-type-or-repeated-type
     
τ-rest = xlist-type-or-repeated-type
     
dotted-τ-rest = "like τ-rest, but must not be a syntax pair"
Expands to a predicate which returns true if and only if the following conditions are met:
  • The value is a constructor with the given tag name (i.e. a tagged structure with the given tag name and a single field named values, so nodes and untagged structures with a single field named values are accepted too)

  • The constructor’s value (i.e. the contents of its values field) is accepted by (make-predicate (xList . xlist-types))

syntax

(define-constructor name maybe-tag maybe-pred? maybe-∀ . type-spec)

 
name = Identifier
     
maybe-∀ = 
  | #:∀ (tvarⱼ ...)
     
maybe-tag = 
  | #:tag tag-name
     
tag-name = Identifier
     
maybe-pred? = 
  | #:? predicate-name?
     
predicate-name? = Identifier
     
types-spec = (: typeᵢ ...)
  | (! . xlist-types)
  | (:: . xlist-types)
     
xlist-types = (τᵢ ...)
  | (τᵢ ... . dotted-τ-rest)
  | (τᵢ ... #:rest τ-rest)
     
τᵢ = xlist-type-or-repeated-type
     
τ-rest = xlist-type-or-repeated-type
     
dotted-τ-rest = "like τ-rest, but must not be a syntax pair"
     
typeᵢ = Type
Defines name as a shorthand for the type expander, match expander, builder function and predicate for a constructor with given tag-name and content types.

When #:tag tag-name is omitted, it defaults to name.

The predicate is bound to predicate-name?; When #:? predicate-name? is omitted, it defaults to name?, which is an identifier with the same lexical context as name, with a "?" appended at the end.

The name and predicate? identifiers behave as follows:

type expander

name

Expands to the same type as (constructor tag-name typeᵢ ...) or (constructor tag-name . xlist-types) would.

syntax

name

Expands to the same builder function as (constructor tag-name types-spec) would. The use of :, ! or :: before the sequence of types therefore specifies whether the builder function accepts a simple fixed number of arguments, a variable number of arguments (performing a cast), or a single argument used as the whole value for the constructor.

match expander

(name patᵢ ...)

When using the : typeᵢ ... form of define-constructor, the defined match expander expects one pattern patᵢ per type. The resulting match pattern verifies that the value is a constructor with the given tag-name containing a list with the correct number of elements, and matches each element against the corresponding patᵢ.

When using the (! . xlist-types) or (:: . xlist-types) forms of define-constructor, the defined match expander expects one pattern per (possibly repeated) xlist type. The resulting match pattern verifies that the value is a constructor with the given tag-name containing a value accepted by (make-predicate (xlist . xlist-types)). It then uses the split-xlist match expander, which splits the list into one sublist per repeated xlist type (and a single item for each non-repeated xlist type), and matches each sublist or single item against the corresponding patᵢ. See the documentation for split-xlist for more details about this process. The resulting match pattern is therefore equivalent to:

(and (tagged? tag-name values)
     (? (make-predicate (xlist . xlist-types)))
     (split-xlist [patᵢ ...] . xlist-types))

syntax

predicate?

Expands to the same predicate as

(constructor? tag-name (xlist τᵢ  . τ-rest))

would, where all occurrences of tvarⱼ type variables are replaced with Any.

The elements of the grammar for define-tagged may appear in any order, as long as the tag name appears before any field descriptor, and as long as the field descriptors form a contiguous sequence.

The supertype of all constructors, including tagged structures, untagged structures and nodes which only contain a single values field.

procedure

(ConstructorTop? v)  Boolean

  v : Any
A predicate for ConstructorTop. It accepts all constructors, including tagged structures, untagged structures and nodes which contain a single values field, and rejects any other value.

procedure

(constructor-values v)  T

  v : ConstructorTop
Returns the value stored within the constructor.