The interface of a unit is described in terms of signatures. Each signature is defined (normally within a module ) using define-signature . For example, the following signature, placed in a "toy-factory-sig.rkt" file, describes the exports of a component that implements a toy factory:
By convention, signature names end with ^.
"toy-factory-sig.rkt"
(build-toys;(integer? -> (listof toy?))repaint;(toy? symbol? -> toy?)toy?;(any/c -> boolean?)toy-color));(toy? -> symbol?)
An implementation of the toy-factory^ signature is written using define-unit with an export clause that names toy-factory^:
By convention, unit names end with @.
"simple-factory-unit.rkt"
(toy'blue)))(toycol)))
The toy-factory^ signature also could be referenced by a unit that needs a toy factory to implement something else. In that case, toy-factory^ would be named in an import clause. For example, a toy store would get toys from a toy factory. (Suppose, for the sake of an example with interesting features, that the store is willing to sell only toys in a particular color.)
"toy-store-sig.rkt"
(store-color;(-> symbol?)stock!;(integer? -> void?)get-inventory));(-> (listof toy?))
"toy-store-unit.rkt"
"toy-factory-sig.rkt")t(repaintt(store-color))))(build-toysn)))))
Note that "toy-store-unit.rkt" imports "toy-factory-sig.rkt", but not "simple-factory-unit.rkt". Consequently, the toy-store@ unit relies only on the specification of a toy factory, not on a specific implementation.