8.1 Data-structure Contracts
procedure
(flat-named-contract name flat-contract [ generator]) → flat-contract? name : any/c flat-contract : flat-contract? generator : (or/c #f (-> contract (-> int? any))) = #f
(define/contract i (flat-named-contract 'odd-integer (lambda (x) (and (integer? x) (odd? x)))) 2)
The generator argument adds a generator for the flat-named-contract. See contract-generate for more information.
value
When using this contract as the result portion of a function contract, consider using any instead; using any leads to better memory performance, but it also allows multiple results.
value
The or/c result tests any value by applying the contracts in order, from left to right, with the exception that it always moves the non-flat contracts (if any) to the end, checking them last. Thus, a contract such as (or/c (not/c real?) positive?) is guaranteed to only invoke the positive? predicate on real numbers.
If all of the arguments are procedures or flat contracts, the result is a flat contract. If only one of the arguments is a higher-order contract, the result is a contract that just checks the flat contracts and, if they don’t pass, applies the higher-order contract.
If there are multiple higher-order contracts, or/c uses contract-first-order-passes? to distinguish between them. More precisely, when an or/c is checked, it first checks all of the flat contracts. If none of them pass, it calls contract-first-order-passes? with each of the higher-order contracts, taking the first one that returns true as the contract for the value.
If all of its arguments are list-contract?s, then or/c returns a list-contract?.
Changed in version 6.2.900.17 of package base: Adjusted or/c so that it takes the first higher-order contract instead of insisting that there be exactly one higher-order contract for a given value.
If all of the arguments are procedures or flat contracts, the result is a flat contract.
The contract produced by and/c tests any value by applying the contracts in order, from left to right.
procedure
(not/c flat-contract) → flat-contract?
flat-contract : flat-contract?
procedure
(=/c z) → flat-contract?
z : real?
procedure
(</c n) → flat-contract?
n : real?
procedure
(>/c n) → flat-contract?
n : real?
procedure
(<=/c n) → flat-contract?
n : real?
procedure
(>=/c n) → flat-contract?
n : real?
procedure
(between/c n m) → flat-contract?
n : real? m : real?
procedure
(real-in n m) → flat-contract?
n : real? m : real?
procedure
(integer-in j k) → flat-contract?
j : exact-integer? k : exact-integer?
procedure
(char-in a b) → flat-contract?
a : char? b : char?
value
procedure
(string-len/c len) → flat-contract?
len : real?
value
value
procedure
(one-of/c v ...+) → flat-contract?
v : any/c
This is a backwards compatibility contract constructor. If neither #<void> nor #<undefined> are arguments, it simply passes its arguments to or/c.
procedure
(symbols sym ...+) → flat-contract?
sym : symbol?
This is a backwards compatibility constructor; it merely passes its arguments to or/c.
procedure
(vectorof c [ #:immutable immutable #:flat? flat?]) → contract? c : contract? immutable : (or/c #t #f 'dont-care) = 'dont-care flat? : boolean? = #f
If the flat? argument is #t, then the resulting contract is a flat contract, and the c argument must also be a flat contract. Such flat contracts will be unsound if applied to mutable vectors, as they will not check future operations on the vector.
If the immutable argument is #t and the c argument is a flat contract, the result will be a flat contract. If the c argument is a chaperone contract, then the result will be a chaperone contract.
When a higher-order vectorof contract is applied to a vector, the result is not eq? to the input. The result will be a copy for immutable vectors and a chaperone or impersonator of the input for mutable vectors.
procedure
(vector-immutableof c) → contract?
c : contract?
procedure
(vector/c c ... [ #:immutable immutable #:flat? flat?]) → contract? c : contract? immutable : (or/c #t #f 'dont-care) = 'dont-care flat? : boolean? = #f
If the flat? argument is #t, then the resulting contract is a flat contract, and the c arguments must also be flat contracts. Such flat contracts will be unsound if applied to mutable vectors, as they will not check future operations on the vector.
If the immutable argument is #t and the c arguments are flat contracts, the result will be a flat contract. If the c arguments are chaperone contracts, then the result will be a chaperone contract.
When a higher-order vector/c contract is applied to a vector, the result is not eq? to the input. The result will be a copy for immutable vectors and a chaperone or impersonator of the input for mutable vectors.
procedure
(vector-immutable/c c ...) → contract?
c : contract?
procedure
(box/c c [ #:immutable immutable #:flat? flat?]) → contract? c : contract? immutable : (or/c #t #f 'dont-care) = 'dont-care flat? : boolean? = #f
If the flat? argument is #t, then the resulting contract is a flat contract, and the c argument must also be a flat contract. Such flat contracts will be unsound if applied to mutable boxes, as they will not check future operations on the box.
If the immutable argument is #t and the c argument is a flat contract, the result will be a flat contract. If the c argument is a chaperone contract, then the result will be a chaperone contract.
When a higher-order box/c contract is applied to a box, the result is not eq? to the input. The result will be a copy for immutable boxes and either a chaperone or impersonator of the input for mutable boxes.
procedure
(box-immutable/c c) → contract?
c : contract?
procedure
(listof c) → list-contract?
c : contract?
Examples: | ||||||||||||||||||
|
procedure
c : contract?
Examples: | |||||||||||||||||||
|
Examples: | ||||||||||||||||||||
|
Added in version 6.1.1.1 of package base.
If the cdr-c contract is a list-contract?, then cons/c returns a list-contract?.
Examples: | ||||||||||||||||||||
|
Changed in version 6.0.1.13 of package base: Added the list-contract? propagating behavior.
syntax
(cons/dc [car-id contract-expr] [cdr-id (car-id) contract-expr] cons/dc-option)
(cons/dc [car-id (cdr-id) contract-expr] [cdr-id contract-expr] cons/dc-option)
cons/dc-option =
| #:flat | #:chaperone | #:impersonator
In the first case, the contract on the cdr-id portion of the contract may depend on the value in the car-id portion of the pair and in the second case, the reverse is true.
Examples: | ||||||||||||||||||||
|
Added in version 6.1.1.6 of package base.
procedure
(list/c c ...) → list-contract?
c : contract?
procedure
(syntax/c c) → flat-contract?
c : flat-contract?
syntax
(struct/c struct-id contract-expr ...)
Contracts for immutable fields must be either flat or chaperone contracts. Contracts for mutable fields may be impersonator contracts. If all fields are immutable and the contract-exprs evaluate to flat contracts, a flat contract is produced. If all the contract-exprs are chaperone contracts, a chaperone contract is produced. Otherwise, an impersonator contract is produced.
syntax
(struct/dc struct-id field-spec ... maybe-inv)
field-spec = [field-name maybe-lazy contract-expr] |
[field-name (dep-field-name ...) maybe-lazy maybe-contract-type maybe-dep-state contract-expr] field-name = field-id | (#:selector selector-id) | (field-id #:parent struct-id) maybe-lazy =
| #:lazy maybe-contract-type =
| #:flat | #:chaperone | #:impersonator maybe-dep-state =
| #:depends-on-state maybe-inv =
| #:inv (dep-field-name ...) invariant-expr
If the field-spec lists the names of other fields, then the contract depends on values in those fields, and the contract-expr expression is evaluated each time a selector is applied, building a new contract for the fields based on the values of the dep-field-name fields (the dep-field-name syntax is the same as the field-name syntax). If the field is a dependent field and no contract-type annotation appears, then it is assumed that the contract is a chaperone, but not always a flat contract (and thus the entire struct/dc contract is not a flat contract). If this is not the case, and the contract is always flat then the field must be annotated with the #:flat, or the field must be annotated with #:impersonator (in which case, it must be a mutable field).
A field-name is either an identifier naming a field in the first case, an identifier naming a selector in the second case indicated by the #:selector keyword, or a field id for a struct that is a parent of struct-id, indicated by the #:parent keyword.
If the #:lazy keyword appears, then the contract on the field is checked lazily (only when a selector is applied); #:lazy contracts cannot be put on mutable fields.
If a dependent contract depends on some mutable state, then use the #:depends-on-state keyword argument (if a field’s dependent contract depends on a mutable field, this keyword is automatically inferred). The presence of this keyword means that the contract expression is evaluated each time the corresponding field is accessed (or mutated, if it is a mutable field). Otherwise, the contract expression for a dependent field contract is evaluated when the contract is applied to a value.
If the #:inv clause appears, then the invariant expression is evaluated (and must return a non-#f value) when the contract is applied to a struct.
Contracts for immutable fields must be either flat or chaperone contracts. Contracts for mutable fields may be impersonator contracts. If all fields are immutable and the contract-exprs evaluate to flat contracts, a flat contract is produced. If all the contract-exprs are chaperone contracts, a chaperone contract is produced. Otherwise, an impersonator contract is produced.
As an example, the function bst/c below returns a contract for binary search trees whose values are all between lo and hi. The lazy annotations ensure that this contract does not change the running time of operations that do not inspect the entire tree.
(struct bt (val left right)) (define (bst/c lo hi) (or/c #f (struct/dc bt [val (between/c lo hi)] [left (val) #:lazy (bst lo val)] [right (val) #:lazy (bst val hi)])))
Changed in version 6.0.1.6 of package base: Added #:inv.
procedure
(parameter/c in [out]) → contract?
in : contract? out : contract? = in
Examples: | |||||||||||||||||||||||||||||||||||||||
|
procedure
n : exact-nonnegative-integer?
procedure
(hash/c key val [ #:immutable immutable #:flat? flat?]) → contract? key : chaperone-contract? val : contract? immutable : (or/c #t #f 'dont-care) = 'dont-care flat? : boolean? = #f
Examples: | |||||||||||||||||||||||
|
If the flat? argument is #t, then the resulting contract is a flat contract, and the key and val arguments must also be flat contracts.
Examples:
> (flat-contract? (hash/c integer? boolean?)) #f
> (flat-contract? (hash/c integer? boolean? #:flat? #t)) #t
> (hash/c integer? (-> integer? integer?) #:flat? #t) hash/c: contract violation
expected: flat-contract?
given: #<chaperone-contract: (-> integer? integer?)>
Such flat contracts will be unsound if applied to mutable hash tables, as they will not check future mutations to the hash table.
Examples:
> (define original-h (make-hasheq)) > (define/contract ctc-h (hash/c integer? boolean? #:flat? #t) original-h) > (hash-set! original-h 1 "not a boolean") > (hash-ref ctc-h 1) "not a boolean"
If the immutable argument is #t and the key and val arguments are flat-contract?s, the result will be a flat-contract?.
Example:
> (flat-contract? (hash/c integer? boolean? #:immutable #t)) #t
If either the domain or the range is a chaperone-contract?, then the result will be a chaperone-contract?.
Examples:
> (flat-contract? (hash/c (-> integer? integer?) boolean? #:immutable #t)) #f
> (chaperone-contract? (hash/c (-> integer? integer?) boolean? #:immutable #t)) #t
- If the key argument is a chaperone-contract? but not a flat-contract?, then the resulting contract can be applied only to equal?-based hash tables.
Example:
> (define/contract h (hash/c (-> integer? integer?) any/c) (make-hasheq)) h: broke its own contract;
promised equal?-based hash table due to higher-order domain
contract
produced: '#hasheq()
in: (hash/c (-> integer? integer?) any/c)
contract from: (definition h)
blaming: (definition h)
(assuming the contract is correct)
at: eval:2.0
Also, when such a hash/c contract is applied to a hash table, the result is not eq? to the input. The result of applying the contract will be a copy for immutable hash tables, and either a chaperone or impersonator of the original hash table for mutable hash tables.
syntax
(hash/dc [key-id key-contract-expr] [value-id (key-id) value-contract-expr] hash/dc-option)
hash/dc-option =
| #:immutable immutable?-expr hash/dc-option | #:kind kind-expr hash/dc-option
If immutable?-expr is #t, then only immutable? hashes are accepted. If it is #f then immutable? hashes are always rejected. It defaults to 'dont-care, in which case both mutable and immutable hashes are accepted.
If kind-expr evaluates to 'flat, then key-contract-expr and value-contract-expr are expected to evaluate to flat-contract?s. If it is 'chaperone, then they are expected to be chaperone-contract?s, and it may also be 'impersonator, in which case they may be any contract?s. The default is 'chaperone.
Examples: | |||||||||||||||||||||
|
If the val argument is a chaperone contract, then the resulting contract is a chaperone contract. Otherwise, the resulting contract is an impersonator contract. When a channel contract is applied to a channel, the resulting channel is not eq? to the input.
Examples: | |||||||||||||||||
|
syntax
(prompt-tag/c contract ... maybe-call/cc)
maybe-call/cc =
| #:call/cc contract | #:call/cc (values contract ...)
contract : contract?
Each contract will check the corresponding value passed to an abort-current-continuation and handled by the handler of a call to call-with-continuation-prompt.
If all of the contracts are chaperone contracts, the resulting contract will also be a chaperone contract. Otherwise, the contract is an impersonator contract.
If maybe-call/cc is provided, then the provided contracts are used to check the return values from a continuation captured with call-with-current-continuation.
Examples: | ||||||||||||||||||||||||||
|
procedure
(continuation-mark-key/c contract) → contract?
contract : contract?
If the argument contract is a chaperone contract, the resulting contract will also be a chaperone contract. Otherwise, the contract is an impersonator contract.
Examples: | |||||||||||||||||||||||
|
procedure
(evt/c contract ...) → chaperone-contract?
contract : chaperone-contract?
The resulting contract is always a chaperone contract and its arguments must all be chaperone contracts.
Examples: | |||||||||||||||||||||||
|
syntax
(flat-rec-contract id flat-contract-expr ...)
For example, the contract
(flat-rec-contract sexp (cons/c sexp sexp) number? symbol?)
is a flat contract that checks for (a limited form of) S-expressions. It says that a sexp is either two sexps combined with cons, or a number, or a symbol.
Note that if the contract is applied to a circular value, contract checking will not terminate.
syntax
(flat-murec-contract ([id flat-contract-expr ...] ...) body ...+)
syntax
procedure
(flat-contract predicate) → flat-contract?
predicate : (-> any/c any/c)
This function is a holdover from before predicates could be used directly as flat contracts. It exists today for backwards compatibility.
procedure
(flat-contract-predicate v) → (-> any/c any/c)
v : flat-contract?
This function is a holdover from before flat contracts could be used directly as predicates. It exists today for backwards compatibility.