► |  | The Racket Guide

1 | Welcome to Racket
2 | Racket Essentials
3 | Built-In Datatypes
4 | Expressions and Definitions
5 | Programmer-Defined Datatypes
6 | Modules
7 | Contracts
8 | Input and Output
9 | Regular Expressions
10 | Exceptions and Control
11 | Iterations and Comprehensions
12 | Pattern Matching
13 | Classes and Objects
14 | Units
15 | Reflection and Dynamic Evaluation
16 | Macros
17 | Creating Languages
18 | Concurrency and Synchronization
19 | Performance
20 | Parallelism
21 | Running and Creating Executables
22 | More Libraries
23 | Dialects of Racket and Scheme
24 | Command-Line Tools and Your Editor of Choice
| Bibliography
| Index

▼ | 14 | Units

14.1 | Signatures and Units
14.2 | Invoking Units
14.3 | Linking Units
14.4 | First-Class Units
14.5 | Whole-module Signatures and Units
14.6 | Contracts for Units
14.7 | unit versus module

top ← prev up next →

#### 14.1`` Signatures and Units

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"

> > > #lang racket
> > > (define-signature toy-factory^
> > > (build-toys ; (integer? -> (listof toy?))
> > > repaint ; (toy? symbol? -> toy?)
> > > toy? ; (any/c -> boolean?)
> > > toy-color)) ; (toy? -> symbol?)
> > > (provide toy-factory^)

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"

> > > #lang racket
> > > (require "toy-factory-sig.rkt")
> > > (define-unit simple-factory@
> > > (import)
> > > (export toy-factory^)
> > > (printf "Factory started.\n")
> > > (struct toy (color) #:transparent)
> > > (define (build-toys n)
> > > (for/list ([i (in-range n)])
> > > (toy 'blue)))
> > > (define (repaint t col)
> > > (toy col)))
> > > (provide simple-factory@)

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"

> > > #lang racket
> > > (define-signature toy-store^
> > > (store-color ; (-> symbol?)
> > > stock! ; (integer? -> void?)
> > > get-inventory)) ; (-> (listof toy?))
> > > (provide toy-store^)

> > "toy-store-unit.rkt"

> > > #lang racket
> > > (require "toy-store-sig.rkt"
> > > "toy-factory-sig.rkt")
> > > (define-unit toy-store@
> > > (import toy-factory^)
> > > (export toy-store^)
> > > (define inventory null)
> > > (define (store-color) 'green)
> > > (define (maybe-repaint t)
> > > (if (eq? (toy-color t) (store-color))
> > > t
> > > (repaint t (store-color))))
> > > (define (stock! n)
> > > (set! inventory
> > > (append inventory
> > > (map maybe-repaint
> > > (build-toys n)))))
> > > (define (get-inventory) inventory))
> > > (provide toy-store@)

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.

top ← prev up next →