#lang scribble/doc @(require "mz.rkt") @(require (for-label syntax/modcollapse racket/stxparam racket/serialize)) @(define contract-eval (lambda () (let ([the-eval (make-base-eval)]) (the-eval '(require racket/contract racket/contract/parametric racket/list racket/math)) the-eval))) @(define blame-object @tech{blame object}) @(define blame-objects @tech{blame objects}) @title[#:tag "contracts" #:style 'toc]{Contracts} @guideintro["contracts"]{contracts} The contract system guards one part of a program from another. Programmers specify the behavior of a module's exports via @racket[(provide (contract-out ....))], and the contract system enforces those constraints. @(define-syntax-rule (add-use-sources (x y ...)) (x y ... #:use-sources (racket/contract/private/base racket/contract/private/misc racket/contract/private/provide racket/contract/private/guts racket/contract/private/prop racket/contract/private/blame racket/contract/collapsible racket/contract/private/ds racket/contract/private/opt racket/contract/private/basic-opters racket/contract/private/box racket/contract/private/hash racket/contract/private/vector racket/contract/private/struct-dc))) @(define-syntax-rule (declare-exporting-ctc mod) (add-use-sources (declare-exporting mod racket/contract racket))) @(add-use-sources @note-lib[racket/contract]) @deftech{Contracts} come in two forms: those constructed by the various operations listed in this section of the manual, and various ordinary Racket values that double as contracts, including @itemize[ @item{@tech{symbols}, @tech{booleans}, @tech{keywords}, and @racket[null], which are treated as contracts that recognize themselves, using @racket[eq?], } @item{@tech{strings}, @tech{byte strings}, @tech{characters}, @racket[+nan.0], and @racket[+nan.f], which are treated as contracts that recognize themselves using @racket[equal?], } @item{@tech{numbers} (except @racket[+nan.0] and @racket[+nan.f]), which are treated as contracts that recognize themselves using @racket[=],} @item{@tech{regular expressions}, which are treated as contracts that recognize @tech{byte strings} and @tech{strings} that match the regular expression, and } @item{predicates: any procedure of arity 1 is treated as a predicate. During contract checking, it is applied to the values that appear and should return @racket[#f] to indicate that the contract failed, and anything else to indicate it passed.} ] @deftech{Contract combinators} are functions such as @racket[->] and @racket[listof] that take contracts and produce other contracts. Contracts in Racket are subdivided into three different categories: @; @itemlist[@item{@deftech{Flat @tech{contracts}} can be fully checked immediately for a given value. These kinds of @tech{contracts} are essentially predicate functions. Using @racket[flat-contract-predicate], you can extract the predicate from an arbitrary flat contract; some flat contracts can be applied like functions, in which case they accept a single argument and return @racket[#t] or @racket[#f] to indicate if the given value would be accepted by the contract. All of the flat contracts returned by functions in this library can be used directly as predicates, but ordinary Racket values that double as flat contracts (e.g., numbers or symbols) cannot. The function @racket[flat-contract?] recognizes a flat contract.} @item{@deftech{Chaperone @tech{contracts}} may wrap a value in such a way that it signals contract violations later, as the value is used, but are guaranteed to not otherwise change behavior. For example, a function contract wraps a function value and later checks inputs and outputs; any properties that the function value had before being wrapped by the contract are preserved by the contract wrapper. All @tech{flat contracts} may be used where @tech{chaperone contracts} are expected (but not vice-versa). The function @racket[chaperone-contract?] recognizes a chaperone contract.} @item{@deftech{Impersonator @tech{contracts}} may wrap values and do not provide any guarantees. Impersonator contracts may hide properties of values, or even make them completely opaque (e.g, @racket[new-∀/c]). All @tech{contracts} may be used where impersonator contracts are expected. The function @racket[impersonator-contract?] recognizes an impersonator contract.}] For more about this hierarchy, see the section ``@secref["chaperones"]'' as well as a research paper @cite{Strickland12} on chaperones, impersonators, and how they can be used to implement contracts. @history[#:changed "6.1.1.8" @list{Changed @racket[+nan.0] and @racket[+nan.f] to be @racket[equal?]-based contracts.}] @local-table-of-contents[] @; ---------------------------------------- @section[#:tag "data-structure-contracts"]{Data-structure Contracts} @declare-exporting-ctc[racket/contract/base] @defproc[(flat-contract-with-explanation [get-explanation (-> any/c (or/c boolean? (-> blame? any)))] [#:name name any/c (object-name get-explanation)]) flat-contract?]{ Provides a way to use flat contracts that, when a contract fails, provide more information about the failure. If @racket[get-explanation] returns a boolean, then that boolean value is treated as the predicate in a @tech{flat contract}. If it returns a procedure, then it is treated similarly to returning @racket[#f], except the result procedure is called to actually signal the contract violation. The @racket[name] argument is used as the name of the contract; it defaults to the name of the @racket[get-explanation] function. @racketblock[(flat-contract-with-explanation (λ (val) (cond [(even? val) #t] [else (λ (blame) (define more-information ...do-some-complex-computation-here...) (raise-blame-error blame val '(expected: "an even number" given: "~e" "and, here is more help: ~s") val more-information))])))] } @defproc[(flat-named-contract [name any/c] [flat-contract flat-contract?] [generator (or/c #f (-> contract (-> int? any))) #f]) flat-contract?]{ Produces a @tech{flat contract} like @racket[flat-contract], but with the name @racket[name]. For example, @racketblock[(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 @racket[contract-random-generate] for more information. } @defthing[any/c flat-contract?]{ A @tech{flat contract} that accepts any value. When using this contract as the result portion of a function contract, consider using @racket[any] instead; using @racket[any] leads to better memory performance, but it also allows multiple results.} @defthing[none/c flat-contract?]{ A @tech{flat contract} that accepts no values.} @defproc[(or/c [contract contract?] ...) contract?]{ Takes any number of @tech{contracts} and returns a @tech{contract} that accepts any value that any one of the contracts accepts individually. The @racket[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-@tech{flat contracts} (if any) to the end, checking them last. Thus, a contract such as @racket[(or/c (not/c real?) positive?)] is guaranteed to only invoke the @racket[positive?] predicate on real numbers. If all of the arguments are procedures or @tech{flat contracts}, the result is a @tech{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, @racket[or/c] uses @racket[contract-first-order-passes?] to distinguish between them. More precisely, when an @racket[or/c] is checked, it first checks all of the @tech{flat contracts}. If none of them pass, it calls @racket[contract-first-order-passes?] with each of the higher-order contracts. If only one returns true, @racket[or/c] uses that contract. If none of them return true, it signals a contract violation. If more than one returns true, it also signals a contract violation. For example, this contract @racketblock[ (or/c (-> number? number?) (-> string? string? string?)) ] does not accept a function like this one: @racket[(lambda args ...)] since it cannot tell which of the two arrow contracts should be used with the function. If all of its arguments are @racket[list-contract?]s, then @racket[or/c] returns a @racket[list-contract?]. } @defproc[(first-or/c [contract contract?] ...) contract?]{ Takes any number of @tech{contracts} and returns a @tech{contract} that accepts any value that any one of the contracts accepts individually. The @racket[first-or/c] result tests any value by applying the contracts in order from left to right. Thus, a contract such as @racket[(first-or/c (not/c real?) positive?)] is guaranteed to only invoke the @racket[positive?] predicate on real numbers. If all of the arguments are procedures or @tech{flat contracts}, the result is a @tech{flat contract} and similarly if all of the arguments are @tech{chaperone contracts} the result is too. Otherwise, the result is an @tech{impersonator contract}. If there are multiple higher-order contracts, @racket[first-or/c] uses @racket[contract-first-order-passes?] to distinguish between them. More precisely, when an @racket[first-or/c] is checked, it checks the first order passes of the first contract against the value. If it succeeds, then it uses only that contract. If it fails, then it moves to the second contract, continuing until it finds one of the contracts where the first order check succeeds. If none of them do, a contract violation is signaled. For example, this contract @racketblock[ (first-or/c (-> number? number?) (-> string? string? string?))] accepts the function @racket[(λ args 0)], applying the @racket[(-> number? number?)] contract to the function because it comes first, even though @racket[(-> string? string? string?)] also applies. If all of its arguments are @racket[list-contract?]s, then @racket[first-or/c] returns a @racket[list-contract?]. } @defproc[(and/c [contract contract?] ...) contract?]{ Takes any number of @tech{contracts} and returns a @tech{contract} that accepts any value that satisfies all of the contracts simultaneously. If all of the arguments are procedures or @tech{flat contracts}, the result is a @tech{flat contract}. The contract produced by @racket[and/c] tests any value by applying the contracts in order, from left to right. This means that @racket[and/c] can be used to guard predicates that are not total in contracts. For example, this contract is well-behaved, correctly blaming the definition of @racket[whoops-not-a-number] for not being a number: @examples[#:eval (contract-eval) #:once (eval:error (define/contract whoops-not-a-number (and/c real? even?) "four"))] but if the arguments to @racket[and/c] are reversed, then the contract itself raises an error: @examples[#:eval (contract-eval) #:once (eval:error (define/contract whoops-not-a-number (and/c even? real?) "four"))] If more than one of the contracts are not @tech{flat contracts}, then the order in which the higher-order parts of the contract are tested can be counter-intuitive. As an example, consider this function that uses @racket[and/c] in a higher-order manner with contracts that always succeed, but that print when they are called, in order for us to see the order in which they are called. @examples[#:eval (contract-eval) #:once (define ((show-me n) x) (printf "show-me ~a\n" n) #t) (define/contract identity-with-complex-printing-contract (and/c (-> (show-me 4) (show-me 5)) (-> (show-me 3) (show-me 6)) (-> (show-me 2) (show-me 7)) (-> (show-me 1) (show-me 8))) (λ (x) x)) (identity-with-complex-printing-contract 101)] The checking order is just like the usual ordering when a contract is double-wrapped. The contract that is first put on has its domain checked second but its range checked first and we see a similar pattern here in this example, because @racket[and/c] simply applies the contracts in order. } @defproc[(not/c [flat-contract flat-contract?]) flat-contract?]{ Accepts a @tech{flat contract} or a predicate and returns a @tech{flat contract} that checks the inverse of the argument.} @defproc[(=/c [z real?]) flat-contract?]{ Returns a @tech{flat contract} that requires the input to be a number and @racket[=] to @racket[z].} @defproc[(/c [n real?]) flat-contract?]{ Like @racket[].} @defproc[(<=/c [n real?]) flat-contract?]{ Like @racket[=/c [n real?]) flat-contract?]{ Like @racket[=].} @defproc[(between/c [n real?] [m real?]) flat-contract?]{ Returns a @tech{flat contract} that requires the input to be a real number between @racket[n] and @racket[m] or equal to one of them.} @defproc[(real-in [n real?] [m real?]) flat-contract?]{ An alias for @racket[between/c].} @defproc[(integer-in [j (or/c exact-integer? #f)] [k (or/c exact-integer? #f)]) flat-contract?]{ Returns a @tech{flat contract} that requires the input to be an exact integer between @racket[j] and @racket[k], inclusive. If either @racket[j] or @racket[k] is @racket[#f], then the range is unbounded on that end. @examples[#:eval (contract-eval) #:once (define/contract two-digit-number (integer-in 10 99) 23) (eval:error (define/contract not-a-two-digit-number (integer-in 10 99) 124)) (define/contract negative-number (integer-in #f -1) -4) (eval:error (define/contract not-a-negative-number (integer-in #f -1) 4))] @history[#:changed "6.8.0.2" @elem{Allow @racket[j] and @racket[k] to be @racket[#f]}] } @defproc[(char-in [a char?] [b char?]) flat-contract?]{ Returns a @tech{flat contract} that requires the input to be a character whose code point number is between the code point numbers of @racket[a] and @racket[b], inclusive.} @defthing[natural-number/c flat-contract?]{ A @tech{flat contract} that requires the input to be an exact non-negative integer.} @defproc[(string-len/c [len real?]) flat-contract?]{ Returns a @tech{flat contract} that recognizes strings that have fewer than @racket[len] characters.} @defthing[false/c flat-contract?]{ An alias for @racket[#f] for backwards compatibility.} @defthing[printable/c flat-contract?]{ A @tech{flat contract} that recognizes values that can be written out and read back in with @racket[write] and @racket[read].} @defproc[(one-of/c [v any/c] ...+) flat-contract?]{ Accepts any number of atomic values and returns a @tech{flat contract} that recognizes those values, using @racket[eqv?] as the comparison predicate. For the purposes of @racket[one-of/c], atomic values are defined to be: @tech{characters}, @tech{symbols}, @tech{booleans}, @racket[null], @tech{keywords}, @tech{numbers}, @|void-const|, and @|undefined-const|. This is a backwards compatibility contract constructor. If neither @|void-const| nor @|undefined-const| are arguments, it simply passes its arguments to @racket[or/c]. } @defproc[(symbols [sym symbol?] ...+) flat-contract?]{ Accepts any number of symbols and returns a @tech{flat contract} that recognizes those symbols. This is a backwards compatibility constructor; it merely passes its arguments to @racket[or/c]. } @defproc[(vectorof [c contract?] [#:immutable immutable (or/c #t #f 'dont-care) 'dont-care] [#:flat? flat? boolean? #f] [#:eager eager (or/c #t #f exact-nonnegative-integer?) #t]) contract?]{ Returns a @tech{contract} that recognizes vectors. The elements of the vector must match @racket[c]. If the @racket[flat?] argument is @racket[#t], then the resulting contract is a @tech{flat contract}, and the @racket[c] argument must also be a @tech{flat contract}. Such @tech{flat contracts} will be unsound if applied to mutable vectors, as they will not check future operations on the vector. If the @racket[immutable] argument is @racket[#t] and the @racket[c] argument is a @tech{flat contract} and the @racket[eager] argument is @racket[#t], the result will be a @tech{flat contract}. If the @racket[c] argument is a @tech{chaperone contract}, then the result will be a @tech{chaperone contract}. If the @racket[eager] argument is @racket[#t], then immutable vectors are checked eagerly when @racket[c] is a @tech{flat contract}. If the @racket[eager] argument is a number @racket[n], then immutable vectors are checked eagerly when @racket[c] is a @tech{flat contract} and the length of the vector is less than or equal to @racket[n]. When a higher-order @racket[vectorof] contract is applied to a vector, the result is not @racket[eq?] to the input. The result will be a copy for immutable vectors and a @tech{chaperone} or @tech{impersonator} of the input for mutable vectors, unless the @racket[c] argument is a @tech{flat contract} and the vector is immutable, in which case the result is the original vector. @history[#:changed "6.3.0.5" @list{Changed flat vector contracts to not copy immutable vectors.} #:changed "6.7.0.3" @list{Added the @racket[#:eager] option.}] } @defproc[(vector-immutableof [c contract?]) contract?]{ Returns the same @tech{contract} as @racket[(vectorof c #:immutable #t)]. This form exists for backwards compatibility.} @defproc[(vector/c [c contract?] ... [#:immutable immutable (or/c #t #f 'dont-care) 'dont-care] [#:flat? flat? boolean? #f]) contract?]{ Returns a @tech{contract} that recognizes vectors whose lengths match the number of contracts given. Each element of the vector must match its corresponding contract. If the @racket[flat?] argument is @racket[#t], then the resulting contract is a @tech{flat contract}, and the @racket[c] arguments must also be @tech{flat contracts}. Such @tech{flat contracts} will be unsound if applied to mutable vectors, as they will not check future operations on the vector. If the @racket[immutable] argument is @racket[#t] and the @racket[c] arguments are @tech{flat contracts}, the result will be a @tech{flat contract}. If the @racket[c] arguments are @tech{chaperone contracts}, then the result will be a @tech{chaperone contract}. When a higher-order @racket[vector/c] contract is applied to a vector, the result is not @racket[eq?] to the input. The result will be a copy for immutable vectors and a @tech{chaperone} or @tech{impersonator} of the input for mutable vectors.} @defproc[(vector-immutable/c [c contract?] ...) contract?]{ Returns the same contract as @racket[(vector/c c ... #:immutable #t)]. This form exists for reasons of backwards compatibility.} @defproc[(box/c [in-c contract?] [c contract? in-c] [#:immutable immutable (or/c #t #f 'dont-care) 'dont-care] [#:flat? flat? boolean? #f]) contract?]{ Returns a contract that recognizes boxes. The content of the box must match @racket[c], and mutations on mutable boxes must match @racket[in-c]. If the @racket[flat?] argument is @racket[#t], then the resulting contract is a @tech{flat contract}, and the @racket[out] argument must also be a @tech{flat contract}. Such @tech{flat contracts} will be unsound if applied to mutable boxes, as they will not check future operations on the box. If the @racket[immutable] argument is @racket[#t] and the @racket[c] argument is a @tech{flat contract}, the result will be a @tech{flat contract}. If the @racket[c] argument is a @tech{chaperone contract}, then the result will be a @tech{chaperone contract}. When a higher-order @racket[box/c] contract is applied to a box, the result is not @racket[eq?] to the input. The result will be a copy for immutable boxes and either a @tech{chaperone} or @tech{impersonator} of the input for mutable boxes.} @defproc[(box-immutable/c [c contract?]) contract?]{ Returns the same contract as @racket[(box/c c #:immutable #t)]. This form exists for reasons of backwards compatibility.} @defproc[(listof [c contract?]) list-contract?]{ Returns a contract that recognizes a list whose every element matches the contract @racket[c]. Beware that when this contract is applied to a value, the result is not necessarily @racket[eq?] to the input. @examples[#:eval (contract-eval) #:once (define/contract some-numbers (listof number?) (list 1 2 3)) (eval:error (define/contract just-one-number (listof number?) 11))] } @defproc[(non-empty-listof [c contract?]) list-contract?]{ Returns a contract that recognizes non-empty lists whose elements match the contract @racket[c]. Beware that when this contract is applied to a value, the result is not necessarily @racket[eq?] to the input. @examples[#:eval (contract-eval) #:once (define/contract some-numbers (non-empty-listof number?) (list 1 2 3)) (eval:error (define/contract not-enough-numbers (non-empty-listof number?) (list)))] } @defproc[(list*of [ele-c contract?] [last-c contract? ele-c]) contract?]{ Returns a contract that recognizes improper lists whose elements match the contract @racket[ele-c] and whose last position matches @racket[last-c]. If an improper list is created with @racket[cons], then its @racket[car] position is expected to match @racket[ele-c] and its @racket[cdr] position is expected to be @racket[(list*of ele-c list-c)]. Otherwise, it is expected to match @racket[last-c]. Beware that when this contract is applied to a value, the result is not necessarily @racket[eq?] to the input. @examples[#:eval (contract-eval) #:once (define/contract improper-numbers (list*of number?) (cons 1 (cons 2 3))) (eval:error (define/contract not-improper-numbers (list*of number?) (list 1 2 3)))] @history[#:added "6.1.1.1" #:changed "6.4.0.4" @list{Added the @racket[last-c] argument.}] } @defproc[(cons/c [car-c contract?] [cdr-c contract?]) contract?]{ Produces a contract that recognizes pairs whose first and second elements match @racket[car-c] and @racket[cdr-c], respectively. Beware that when this contract is applied to a value, the result is not necessarily @racket[eq?] to the input. If the @racket[cdr-c] contract is a @racket[list-contract?], then @racket[cons/c] returns a @racket[list-contract?]. @examples[#:eval (contract-eval) #:once (define/contract a-pair-of-numbers (cons/c number? number?) (cons 1 2)) (eval:error (define/contract not-a-pair-of-numbers (cons/c number? number?) (cons #f #t)))] @history[#:changed "6.0.1.13" @list{Added the @racket[list-contract?] propagating behavior.}] } @defform*[[(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)] #:grammar ([cons/dc-option (code:line) #:flat #:chaperone #:impersonator])]{ Produces a contract that recognizes pairs whose first and second elements match the expressions after @racket[car-id] and @racket[cdr-id], respectively. In the first case, the contract on the @racket[cdr-id] portion of the contract may depend on the value in the @racket[car-id] portion of the pair and in the second case, the reverse is true. @examples[#:eval (contract-eval) #:once (define/contract an-ordered-pair-of-reals (cons/dc [hd real?] [tl (hd) (>=/c hd)]) (cons 1 2)) (eval:error (define/contract not-an-ordered-pair-of-reals (cons/dc [hd real?] [tl (hd) (>=/c hd)]) (cons 2 1)))] @history[#:added "6.1.1.6"] } @defproc[(list/c [c contract?] ...) list-contract?]{ Produces a contract for a list. The number of elements in the list must match the number of arguments supplied to @racket[list/c], and each element of the list must match the corresponding contract. Beware that when this contract is applied to a value, the result is not necessarily @racket[eq?] to the input.} @defproc[(*list/c [prefix contract?] [suffix contract?] ...) list-contract?]{ Produces a contract for a list. The number of elements in the list must be at least as long as the number of @racket[suffix] contracts and the tail of the list must match those contracts, one for each element. The beginning portion of the list can be arbitrarily long, and each element must match @racket[prefix]. Beware that when this contract is applied to a value, the result is not necessarily @racket[eq?] to the input. @examples[#:eval (contract-eval) #:once (define/contract a-list-of-numbers-ending-with-two-integers (*list/c number? integer? integer?) (list 1/2 4/5 +1i -11 322)) (eval:error (define/contract not-enough-integers-at-the-end (*list/c number? integer? integer? integer?) (list 1/2 4/5 1/2 321 322)))] } @defproc[(syntax/c [c flat-contract?]) flat-contract?]{ Produces a @tech{flat contract} that recognizes syntax objects whose @racket[syntax-e] content matches @racket[c].} @defform[(struct/c struct-id contract-expr ...)]{ Produces a contract that recognizes instances of the structure type named by @racket[struct-id], and whose field values match the contracts produced by the @racket[contract-expr]s. Contracts for immutable fields must be either flat or @tech{chaperone contracts}. Contracts for mutable fields may be impersonator contracts. If all fields are immutable and the @racket[contract-expr]s evaluate to @tech{flat contracts}, a @tech{flat contract} is produced. If all the @racket[contract-expr]s are @tech{chaperone contracts}, a @tech{chaperone contract} is produced. Otherwise, an impersonator contract is produced. } @defform/subs[(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 (code:line) #:lazy] [maybe-contract-type (code:line) #:flat #:chaperone #:impersonator] [maybe-dep-state (code:line) #:depends-on-state] [maybe-inv (code:line) (code:line #:inv (dep-field-name ...) invariant-expr)])]{ Produces a contract that recognizes instances of the structure type named by @racket[struct-id], and whose field values match the contracts produced by the @racket[field-spec]s. If the @racket[field-spec] lists the names of other fields, then the contract depends on values in those fields, and the @racket[contract-expr] expression is evaluated each time a selector is applied, building a new contract for the fields based on the values of the @racket[dep-field-name] fields (the @racket[dep-field-name] syntax is the same as the @racket[field-name] syntax). If the field is a dependent field and no @racket[contract-type] annotation appears, then it is assumed that the contract is a chaperone, but not always a @tech{flat contract} (and thus the entire @racket[struct/dc] contract is not a @tech{flat contract}). If this is not the case, and the contract is always flat then the field must be annotated with the @racket[#:flat], or the field must be annotated with @racket[#:impersonator] (in which case, it must be a mutable field). A @racket[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 @racket[#:selector] keyword, or a field id for a struct that is a parent of @racket[struct-id], indicated by the @racket[#:parent] keyword. If the @racket[#:lazy] keyword appears, then the contract on the field is checked lazily (only when a selector is applied); @racket[#:lazy] contracts cannot be put on mutable fields. If a dependent contract depends on some mutable state, then use the @racket[#: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 @racket[#:inv] clause appears, then the invariant expression is evaluated (and must return a non-@racket[#f] value) when the contract is applied to a struct. Contracts for immutable fields must be either flat or @tech{chaperone contracts}. Contracts for mutable fields may be impersonator contracts. If all fields are immutable and the @racket[contract-expr]s evaluate to @tech{flat contracts}, a @tech{flat contract} is produced. If all the @racket[contract-expr]s are @tech{chaperone contracts}, a @tech{chaperone contract} is produced. Otherwise, an impersonator contract is produced. As an example, the function @racket[bst/c] below returns a contract for binary search trees whose values are all between @racket[lo] and @racket[hi]. The lazy annotations ensure that this contract does not change the running time of operations that do not inspect the entire tree. @examples[#:eval (contract-eval) #:once (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/c lo val)] [right (val) #:lazy (bst/c val hi)]))) (define/contract not-really-a-bst (bst/c -inf.0 +inf.0) (bt 5 (bt 4 (bt 2 #f #f) (bt 6 #f #f)) #f)) (bt-right not-really-a-bst) (bt-val (bt-left (bt-left not-really-a-bst))) (eval:error (bt-right (bt-left not-really-a-bst)))] @history[#:changed "6.0.1.6" @elem{Added @racket[#:inv].}] } @defproc[(parameter/c [in contract?] [out contract? in]) contract?]{ Produces a contract on parameters whose values must match @racket[_out]. When the value in the contracted parameter is set, it must match @racket[_in]. @examples[#:eval (contract-eval) #:once (define/contract current-snack (parameter/c string?) (make-parameter "potato-chip")) (define baked/c (flat-named-contract 'baked/c (λ (s) (regexp-match #rx"baked" s)))) (define/contract current-dinner (parameter/c string? baked/c) (make-parameter "turkey" (λ (s) (string-append "roasted " s)))) (eval:error (current-snack 'not-a-snack)) (eval:error (parameterize ([current-dinner "tofurkey"]) (current-dinner))) ]} @defproc[(procedure-arity-includes/c [n exact-nonnegative-integer?]) flat-contract?]{ Produces a contract for procedures that accept @racket[n] argument (i.e,. the @racket[procedure?] contract is implied).} @defproc[(hash/c [key chaperone-contract?] [val contract?] [#:immutable immutable (or/c #t #f 'dont-care) 'dont-care] [#:flat? flat? boolean? #f]) contract?]{ Produces a contract that recognizes @racket[hash] tables with keys and values as specified by the @racket[key] and @racket[val] arguments. @examples[#:eval (contract-eval) #:once (define/contract good-hash (hash/c integer? boolean?) (hash 1 #t 2 #f 3 #t)) (eval:error (define/contract bad-hash (hash/c integer? boolean?) (hash 1 "elephant" 2 "monkey" 3 "manatee")))] There are a number of technicalities that control how @racket[hash/c] contracts behave. @itemlist[@item{ If the @racket[flat?] argument is @racket[#t], then the resulting contract is a @tech{flat contract}, and the @racket[key] and @racket[val] arguments must also be @tech{flat contracts}. @examples[#:eval (contract-eval) #:once (flat-contract? (hash/c integer? boolean?)) (flat-contract? (hash/c integer? boolean? #:flat? #t)) (eval:error (hash/c integer? (-> integer? integer?) #:flat? #t))] Such @tech{flat contracts} will be unsound if applied to mutable hash tables, as they will not check future mutations to the hash table. @examples[#:eval (contract-eval) #:once (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)]} @item{ If the @racket[immutable] argument is @racket[#t] and the @racket[key] and @racket[val] arguments are @racket[flat-contract?]s, the result will be a @racket[flat-contract?]. @examples[#:eval (contract-eval) #:once (flat-contract? (hash/c integer? boolean? #:immutable #t))] If either the domain or the range is a @racket[chaperone-contract?], then the result will be a @racket[chaperone-contract?]. @examples[#:eval (contract-eval) #:once (flat-contract? (hash/c (-> integer? integer?) boolean? #:immutable #t)) (chaperone-contract? (hash/c (-> integer? integer?) boolean? #:immutable #t))] } @item{ If the @racket[key] argument is a @racket[chaperone-contract?] but not a @racket[flat-contract?], then the resulting contract can be applied only to @racket[equal?]-based hash tables. @examples[#:eval (contract-eval) #:once (eval:error (define/contract h (hash/c (-> integer? integer?) any/c) (make-hasheq)))] Also, when such a @racket[hash/c] contract is applied to a hash table, the result is not @racket[eq?] to the input. The result of applying the contract will be a copy for immutable hash tables, and either a @tech{chaperone} or @tech{impersonator} of the original hash table for mutable hash tables. }]} @defform[(hash/dc [key-id key-contract-expr] [value-id (key-id) value-contract-expr] hash/dc-option) #:grammar ([hash/dc-option (code:line) (code:line #:immutable immutable?-expr hash/dc-option) (code:line #:kind kind-expr hash/dc-option)])]{ Creates a contract for @racket[hash?] tables with keys matching @racket[key-contract-expr] and where the contract on the values can depend on the key itself, since @racket[key-id] will be bound to the corresponding key before evaluating the @racket[values-contract-expr]. If @racket[immutable?-expr] is @racket[#t], then only @racket[immutable?] hashes are accepted. If it is @racket[#f] then @racket[immutable?] hashes are always rejected. It defaults to @racket['dont-care], in which case both mutable and immutable hashes are accepted. If @racket[kind-expr] evaluates to @racket['flat], then @racket[key-contract-expr] and @racket[value-contract-expr] are expected to evaluate to @racket[flat-contract?]s. If it is @racket['chaperone], then they are expected to be @racket[chaperone-contract?]s, and it may also be @racket['impersonator], in which case they may be any @racket[contract?]s. The default is @racket['chaperone]. @examples[#:eval (contract-eval) #:once (define/contract h (hash/dc [k real?] [v (k) (>=/c k)]) (hash 1 3 2 4)) (eval:error (define/contract h (hash/dc [k real?] [v (k) (>=/c k)]) (hash 3 1 4 2)))] } @defproc[(channel/c [val contract?]) contract?]{ Produces a contract that recognizes @tech{channel}s that communicate values as specified by the @racket[val] argument. If the @racket[val] argument is a @tech{chaperone contract}, then the resulting contract is a @tech{chaperone contract}. Otherwise, the resulting contract is an impersonator contract. When a channel contract is applied to a channel, the resulting channel is not @racket[eq?] to the input. @examples[#:eval (contract-eval) #:once (define/contract chan (channel/c string?) (make-channel)) (thread (λ () (channel-get chan))) (eval:error (channel-put chan 'not-a-string)) ]} @defform/subs[#:literals (values) (prompt-tag/c contract ... maybe-call/cc) ([maybe-call/cc (code:line) (code:line #:call/cc contract) (code:line #:call/cc (values contract ...))]) #:contracts ([contract contract?])]{ Takes any number of contracts and returns a contract that recognizes continuation prompt tags and will check any aborts or prompt handlers that use the contracted prompt tag. Each @racket[contract] will check the corresponding value passed to an @racket[abort-current-continuation] and handled by the handler of a call to @racket[call-with-continuation-prompt]. If all of the @racket[contract]s are @tech{chaperone contracts}, the resulting contract will also be a @tech{chaperone} contract. Otherwise, the contract is an @tech{impersonator} contract. If @racket[maybe-call/cc] is provided, then the provided contracts are used to check the return values from a continuation captured with @racket[call-with-current-continuation]. @examples[#:eval (contract-eval) #:once (define/contract tag (prompt-tag/c (-> number? string?)) (make-continuation-prompt-tag)) (eval:error (call-with-continuation-prompt (lambda () (number->string (call-with-composable-continuation (lambda (k) (abort-current-continuation tag k))))) tag (lambda (k) (k "not a number")))) ] } @defproc[(continuation-mark-key/c [contract contract?]) contract?]{ Takes a single contract and returns a contract that recognizes continuation marks and will check any mappings of marks to values or any accesses of the mark value. If the argument @racket[contract] is a @tech{chaperone contract}, the resulting contract will also be a @tech{chaperone} contract. Otherwise, the contract is an @tech{impersonator} contract. @examples[#:eval (contract-eval) #:once (define/contract mark-key (continuation-mark-key/c (-> symbol? (listof symbol?))) (make-continuation-mark-key)) (eval:error (with-continuation-mark mark-key (lambda (s) (append s '(truffle fudge ganache))) (let ([mark-value (continuation-mark-set-first (current-continuation-marks) mark-key)]) (mark-value "chocolate-bar")))) ] } @defproc[(evt/c [contract chaperone-contract?] ...) chaperone-contract?]{ Returns a contract that recognizes @tech{synchronizable event}s whose @tech{synchronization result}s are checked by the given @racket[contract]s. The resulting contract is always a @tech{chaperone} contract and its arguments must all be @tech{chaperone contracts}. @examples[#:eval (contract-eval) #:once (define/contract my-evt (evt/c evt?) always-evt) (define/contract failing-evt (evt/c number? number?) (alarm-evt (+ (current-inexact-milliseconds) 50))) (sync my-evt) (eval:error (sync failing-evt)) ] } @defform[(flat-rec-contract id flat-contract-expr ...)]{ Constructs a recursive @tech{flat contract}. A @racket[flat-contract-expr] can refer to @racket[id] to refer recursively to the generated contract. For example, the contract @racketblock[ (flat-rec-contract sexp (cons/c sexp sexp) number? symbol?) ] is a @tech{flat contract} that checks for (a limited form of) S-expressions. It says that a @racket[_sexp] is either two @racket[_sexp]s combined with @racket[cons], or a number, or a symbol. Note that if the contract is applied to a circular value, contract checking will not terminate.} @defform[(flat-murec-contract ([id flat-contract-expr ...] ...) body ...+)]{ A generalization of @racket[flat-rec-contract] for defining several mutually recursive @tech{flat contracts} simultaneously. Each @racket[id] is visible in the entire @racket[flat-murec-contract] form, and the result of the final @racket[body] is the result of the entire form.} @defidform[any]{ Represents a contract that is always satisfied. In particular, it can accept multiple values. It can only be used in a result position of contracts like @racket[->]. Using @racket[any] elsewhere is a syntax error.} @defproc[(promise/c [c contract?]) contract?]{ Constructs a contract on a promise. The contract does not force the promise, but when the promise is forced, the contract checks that the result value meets the contract @racket[c].} @defproc[(flat-contract [predicate (-> any/c any/c)]) flat-contract?]{ Constructs a @tech{flat contract} from @racket[predicate]. A value satisfies the contract if the predicate returns a true value. This function is a holdover from before predicates could be used directly as @tech{flat contracts}. It exists today for backwards compatibility. } @defproc[(flat-contract-predicate [v flat-contract?]) (-> any/c any/c)]{ Extracts the predicate from a @tech{flat contract}. Note that most @tech{flat contracts} can be used directly as predicates, but not all. This function can be used to build predicates for ordinary Racket values that double as contracts, such as numbers and symbols. When building a @tech{contract combinator} that needs to explicitly convert ordinary racket values to flat contracts, consider using @racket[coerce-flat-contract] instead of @racket[flat-contract-predicate] so that the combinator can raise errors that use the combinator's name in the error message. } @defproc[(property/c [accessor (-> any/c any/c)] [ctc flat-contract?] [#:name name any/c (object-name accessor)]) flat-contract?]{ Constructs a @tech{flat contract} that checks that the first-order property accessed by @racket[accessor] satisfies @racket[ctc]. The resulting contract is equivalent to @racketblock[(lambda (v) (ctc (accessor v)))] except that more information is included in error messages produced by violations of the contract. The @racket[name] argument is used to describe the property being checked in error messages. @examples[#:eval (contract-eval) #:once (define/contract (sum-triple lst) (-> (and/c (listof number?) (property/c length (=/c 3))) number?) (+ (first lst) (second lst) (third lst))) (eval:check (sum-triple '(1 2 3)) 6) (eval:error (sum-triple '(1 2)))] @history[#:added "7.3.0.11"] } @defproc[(suggest/c [c contract?] [field string?] [message string?]) contract?]{ Returns a contract that behaves like @racket[c], except that it adds an extra line to the error message on a contract violation. The @racket[field] and @racket[message] strings are added following the guidelines in @secref["err-msg-conventions"]. @examples[#:eval (contract-eval) #:once (define allow-calls? #f) (define/contract (f) (suggest/c (->* () #:pre allow-calls? any) "suggestion" "maybe you should set! allow-calls? to #t") 5) (eval:error (f))] } @; ------------------------------------------------------------------------ @section[#:tag "function-contracts"]{Function Contracts} @declare-exporting-ctc[racket/contract/base] A @deftech{function contract} wraps a procedure to delay checks for its arguments and results. There are three primary function contract combinators that have increasing amounts of expressiveness and increasing additional overheads. The first @racket[->] is the cheapest. It generates wrapper functions that can call the original function directly. Contracts built with @racket[->*] require packaging up arguments as lists in the wrapper function and then using either @racket[keyword-apply] or @racket[apply]. Finally, @racket[->i] is the most expensive (along with @racket[->d]), because it requires delaying the evaluation of the contract expressions for the domain and range until the function itself is called or returns. The @racket[case->] contract is a specialized contract, designed to match @racket[case-lambda] and @racket[unconstrained-domain->] allows range checking without requiring that the domain have any particular shape (see below for an example use). @(define lit-ellipsis (racket ...)) @defform*/subs[#:literals (any values) [(-> dom ... range) (-> dom ... ellipsis dom-expr ... range)] ([dom dom-expr (code:line keyword dom-expr)] [range range-expr (values range-expr ...) any] [ellipsis #,lit-ellipsis])]{ Produces a contract for a function that accepts the argument specified by the @racket[dom-expr] contracts and returns either a fixed number of results or completely unspecified results (the latter when @racket[any] is specified). Each @racket[dom-expr] is a contract on an argument to a function, and each @racket[range-expr] is a contract on a result of the function. If the domain contain @racket[...] then the function accepts as many arguments as the rest of the contracts in the domain portion specify, as well as arbitrarily many more that match the contract just before the @racket[...]. Otherwise, the contract accepts exactly the argument specified. @margin-note{Using a @racket[->] between two whitespace-delimited @racketparenfont{.}s is the same as putting the @racket[->] right after the enclosing opening parenthesis. See @guidesecref["lists-and-syntax"] or @secref["parse-pair"] for more information.} For example, @racketblock[(integer? boolean? . -> . integer?)] produces a contract on functions of two arguments. The first argument must be an integer, and the second argument must be a boolean. The function must produce an integer. @examples[#:eval (contract-eval) #:once (define/contract (maybe-invert i b) (-> integer? boolean? integer?) (if b (- i) i)) (maybe-invert 1 #t) (eval:error (maybe-invert #f 1))] A domain specification may include a keyword. If so, the function must accept corresponding (mandatory) keyword arguments, and the values for the keyword arguments must match the corresponding contracts. For example: @racketblock[(integer? #:invert? boolean? . -> . integer?)] is a contract on a function that accepts a by-position argument that is an integer and an @racket[#:invert?] argument that is a boolean. @examples[#:eval (contract-eval) #:once (define/contract (maybe-invert i #:invert? b) (-> integer? #:invert? boolean? integer?) (if b (- i) i)) (maybe-invert 1 #:invert? #t) (eval:error (maybe-invert 1 #f))] As an example that uses an @racket[...], this contract: @racketblock[(integer? string? ... integer? . -> . any)] on a function insists that the first and last arguments to the function must be integers (and there must be at least two arguments) and any other arguments must be strings. @examples[#:eval (contract-eval) #:once (define/contract (string-length/between? lower-bound s1 . more-args) (-> integer? string? ... integer? boolean?) (define all-but-first-arg-backwards (reverse (cons s1 more-args))) (define upper-bound (first all-but-first-arg-backwards)) (define strings (rest all-but-first-arg-backwards)) (define strings-length (for/sum ([str (in-list strings)]) (string-length str))) (<= lower-bound strings-length upper-bound)) (string-length/between? 4 "farmer" "john" 40) (eval:error (string-length/between? 4 "farmer" 'john 40)) (eval:error (string-length/between? 4 "farmer" "john" "fourty"))] If @racket[any] is used as the last sub-form for @racket[->], no contract checking is performed on the result of the function, and thus any number of values is legal (even different numbers on different invocations of the function). @examples[#:eval (contract-eval) #:once (define/contract (multiple-xs n x) (-> natural? any/c any) (apply values (for/list ([_ (in-range n)]) n))) (multiple-xs 4 "four")] If @racket[(values range-expr ...)] is used as the last sub-form of @racket[->], the function must produce a result for each contract, and each value must match its respective contract. @examples[#:eval (contract-eval) #:once (define/contract (multiple-xs n x) (-> natural? any/c (values any/c any/c any/c)) (apply values (for/list ([_ (in-range n)]) n))) (multiple-xs 3 "three") (eval:error (multiple-xs 4 "four"))] @history[#:changed "6.4.0.5" @list{Added support for ellipses}] } @defform*/subs[#:literals (any values) [(->* (mandatory-dom ...) optional-doms rest pre range post)] ([mandatory-dom dom-expr (code:line keyword dom-expr)] [optional-doms (code:line) (optional-dom ...)] [optional-dom dom-expr (code:line keyword dom-expr)] [rest (code:line) (code:line #:rest rest-expr)] [pre (code:line) (code:line #:pre pre-cond-expr) (code:line #:pre/desc pre-cond-expr)] [range range-expr (values range-expr ...) any] [post (code:line) (code:line #:post post-cond-expr) (code:line #:post/desc post-cond-expr)])]{ The @racket[->*] contract combinator produces contracts for functions that accept optional arguments (either keyword or positional) and/or arbitrarily many arguments. The first clause of a @racket[->*] contract describes the mandatory arguments, and is similar to the argument description of a @racket[->] contract. The second clause describes the optional arguments. The range of description can either be @racket[any] or a sequence of contracts, indicating that the function must return multiple values. If present, the @racket[rest-expr] contract governs the arguments in the rest parameter. Note that the @racket[rest-expr] contract governs only the arguments in the rest parameter, not those in mandatory arguments. For example, this contract: @racketblock[(->* () #:rest (cons/c integer? (listof integer?)) any)] does not match the function @racketblock[(λ (x . rest) x)] because the contract insists that the function accept zero arguments (because there are no mandatory arguments listed in the contract). The @racket[->*] contract does not know that the contract on the rest argument is going to end up disallowing empty argument lists. The @racket[pre-cond-expr] and @racket[post-cond-expr] expressions are checked as the function is called and returns, respectively, and allow checking of the environment without an explicit connection to an argument (or a result). If the @racket[#:pre] or @racket[#:post] keywords are used, then a @racket[#f] result is treated as a failure and any other result is treated as success. If the @racket[#:pre/desc] or @racket[#:post/desc] keyword is used, the result of the expression must be either a boolean, a string, or a list of strings, where @racket[#t] means success and any of the other results mean failure. If the result is a string or a list of strings, the strings are expected to have at exactly one space after each newline and multiple are used as lines in the error message; the contract itself adds single space of indentation to each of the strings in that case. The formatting requirements are not checked but they match the recommendations in @secref["err-msg-conventions"]. As an example, the contract @racketblock[(->* () (boolean? #:x integer?) #:rest (listof symbol?) symbol?)] matches functions that optionally accept a boolean, an integer keyword argument @racket[#:x] and arbitrarily more symbols, and that return a symbol. } @defform*/subs[#:literals (any values) [(->i maybe-chaperone (mandatory-dependent-dom ...) dependent-rest pre-condition dependent-range post-condition) (->i maybe-chaperone (mandatory-dependent-dom ...) (optional-dependent-dom ...) dependent-rest pre-condition dependent-range post-condition)] ([maybe-chaperone #:chaperone (code:line)] [mandatory-dependent-dom id+ctc (code:line keyword id+ctc)] [optional-dependent-dom id+ctc (code:line keyword id+ctc)] [dependent-rest (code:line) (code:line #:rest id+ctc)] [pre-condition (code:line) (code:line #:pre (id ...) boolean-expr pre-condition) (code:line #:pre/desc (id ...) expr pre-condition) (code:line #:pre/name (id ...) string boolean-expr pre-condition)] [dependent-range any id+ctc un+ctc (values id+ctc ...) (values un+ctc ...)] [post-condition (code:line) (code:line #:post (id ...) boolean-expr post-condition) (code:line #:post/desc (id ...) expr post-condition) (code:line #:post/name (id ...) string boolean-expr post-condition)] [id+ctc [id contract-expr] [id (id ...) contract-expr]] [un+ctc [_ contract-expr] [_ (id ...) contract-expr]] )]{ The @racket[->i] contract combinator differs from the @racket[->*] combinator in that each argument and result is named and these names can be used in the subcontracts and in the pre-/post-condition clauses. In other words, @racket[->i] expresses dependencies among arguments and results. The optional first keyword argument to @racket[->i] indicates if the result contract will be a chaperone. If it is @racket[#:chaperone], all of the contract for the arguments and results must be @tech{chaperone contracts} and the result of @racket[->i] will be a @tech{chaperone contract}. If it is not present, then the result contract will not be a @tech{chaperone contract}. The first sub-form of a @racket[->i] contract covers the mandatory and the second sub-form covers the optional arguments. Following that is an optional rest-args contract, and an optional pre-condition. The pre-condition is introduced with the @racket[#:pre] keyword followed by the list of names on which it depends. If the @racket[#:pre/name] keyword is used, the string supplied is used as part of the error message; similarly with @racket[#:post/name]. If @racket[#:pre/desc] or @racket[#:post/desc] is used, the the result of the expression is treated the same way as @racket[->*]. The @racket[dependent-range] non-terminal specifies the possible result contracts. If it is @racket[any], then any value is allowed. Otherwise, the result contract pairs a name and a contract or a multiple values return with names and contracts. In the last two cases, the range contract may be optionally followed by a post-condition; the post-condition expression is not allowed if the range contract is @racket[any]. Like the pre-condition, the post-condition must specify the variables on which it depends. Consider this sample contract: @racketblock[(->i ([x number?] [y (x) (>=/c x)]) [result (x y) (and/c number? (>=/c (+ x y)))])] It specifies a function of two arguments, both numbers. The contract on the second argument (@racket[y]) demands that it is greater than the first argument. The result contract promises a number that is greater than the sum of the two arguments. While the dependency specification for @racket[y] signals that the argument contract depends on the value of the first argument, the dependency sequence for @racket[result] indicates that the contract depends on both argument values. @margin-note*{In general, an empty sequence is (nearly) equivalent to not adding a sequence at all except that the former is more expensive than the latter.} Since the contract for @racket[x] does not depend on anything else, it does not come with any dependency sequence, not even @racket[()]. This example is like the previous one, except the @racket[x] and @racket[y] arguments are now optional keyword arguments, instead of mandatory, by-position arguments: @racketblock[(->i () (#:x [x number?] #:y [y (x) (>=/c x)]) [result (x y) (and/c number? (if (and (number? x) (number? y)) (>=/c (+ x y)) any/c))])] The conditional in the range that tests @racket[_x] and @racket[_y] is necessary to cover the situation where @racket[_x] or @racket[_y] are not supplied by the calling context (meaning they might be bound to @racket[the-unsupplied-arg]). The contract expressions are not always evaluated in order. First, if there is no dependency for a given contract expression, the contract expression is evaluated at the time that the @racket[->i] expression is evaluated rather than the time when the function is called or returns. These dependency-free contract expressions are evaluated in the order in which they are listed. @; Second, the dependent contract sub-expressions are evaluated when the contracted function is called or returns in some order that satisfies the dependencies. That is, if a contract for an argument depends on the value of some other contract, the former is evaluated first (so that the argument, with its contract checked, is available for the other). When there is no dependency between two arguments (or the result and an argument), then the contract that appears earlier in the source text is evaluated first. If all of the identifier positions of a range contract with a dependency are @racket[_]s (underscores), then the range contract expressions are evaluated when the function is called instead of when it returns. Otherwise, dependent range expressions are evaluated when the function returns. If there are optional arguments that are not supplied, then the corresponding variables will be bound to a special value called @racket[the-unsupplied-arg] value. For example, in this contract: @racketblock[(->i ([x (y) (if (unsupplied-arg? y) real? (>=/c y))]) ([y real?]) any)] the contract on @racket[x] depends on @racket[_y], but @racket[_y] might not be supplied at the call site. In that case, the value of @racket[_y] in the contract on @racket[_x] is @racket[the-unsupplied-arg] and the @racket[->i] contract must check for it and tailor the contract on @racket[_x] to account for @racket[_y] not being supplied. When the contract expressions for unsupplied arguments are dependent, and the argument is not supplied at the call site, the contract expressions are not evaluated at all. For example, in this contract, @racket[_y]'s contract expression is evaluated only when @racket[_y] is supplied: @racketblock[(->i () ([x real?] [y (x) (>=/c x)]) any)] In contrast, @racket[_x]'s expression is always evaluated (indeed, it is evaluated when the @racket[->i] expression is evaluated because it does not have any dependencies). } @defform*/subs[#:literals (any values) [(->d (mandatory-dependent-dom ...) dependent-rest pre-condition dependent-range post-condition) (->d (mandatory-dependent-dom ...) (optional-dependent-dom ...) dependent-rest pre-condition dependent-range post-condition)] ([mandatory-dependent-dom [id dom-expr] (code:line keyword [id dom-expr])] [optional-dependent-dom [id dom-expr] (code:line keyword [id dom-expr])] [dependent-rest (code:line) (code:line #:rest id rest-expr)] [pre-condition (code:line) (code:line #:pre boolean-expr) (code:line #:pre-cond boolean-expr)] [dependent-range any [_ range-expr] (values [_ range-expr] ...) [id range-expr] (values [id range-expr] ...)] [post-condition (code:line) (code:line #:post-cond boolean-expr)] )]{ This contract is here for backwards compatibility; any new code should use @racket[->i] instead. This contract is similar to @racket[->i], but is ``lax'', meaning that it does not enforce contracts internally. For example, using this contract @racketblock[(->d ([f (-> integer? integer?)]) #:pre (zero? (f #f)) any)] will allow @racket[f] to be called with @racket[#f], trigger whatever bad behavior the author of @racket[f] was trying to prohibit by insisting that @racket[f]'s contract accept only integers. The @racket[#:pre-cond] and @racket[#:post-cond] keywords are aliases for @racket[#:pre] and @racket[#:post] and are provided for backwards compatibility. } @defform*/subs[#:literals (any values ->) [(case-> (-> dom-expr ... rest range) ...)] ([rest (code:line) (code:line #:rest rest-expr)] [range range-expr (values range-expr ...) any])]{ This contract form is designed to match @racket[case-lambda]. Each argument to @racket[case->] is a contract that governs a clause in the @racket[case-lambda]. If the @racket[#:rest] keyword is present, the corresponding clause must accept an arbitrary number of arguments. The @racket[range] specification is just like that for @racket[->] and @racket[->*]. For example, this contract matches a function with two cases, one that accepts an integer, returning void, and one that accepts no arguments and returns an integer. @racketblock[(case-> (-> integer? void?) (-> integer?))] Such a contract could be used to guard a function that controls access to a single shared integer. } @defproc[(dynamic->* [#:mandatory-domain-contracts mandatory-domain-contracts (listof contract?) '()] [#:optional-domain-contracts optional-domain-contracts (listof contract?) '()] [#:mandatory-keywords mandatory-keywords (listof keyword?) '()] [#:mandatory-keyword-contracts mandatory-keyword-contracts (listof contract?) '()] [#:optional-keywords optional-keywords (listof keyword?) '()] [#:optional-keyword-contracts optional-keyword-contracts (listof contract?) '()] [#:rest-contract rest-contract (or/c #f contract?) #f] [#:range-contracts range-contracts (or/c #f (listof contract?))]) contract?]{ Like @racket[->*], except the number of arguments and results can be computed at runtime, instead of being fixed at compile-time. Passing @racket[#f] as the @racket[#:range-contracts] argument produces a contract like one where @racket[any] is used with @racket[->] or @racket[->*]. For many uses, @racket[dynamic->*]'s result is slower than @racket[->*] (or @racket[->]), but for some it has comparable speed. The name of the contract returned by @racket[dynamic->*] uses the @racket[->] or @racket[->*] syntax. } @defform[(unconstrained-domain-> range-expr ...)]{ Constructs a contract that accepts a function, but makes no constraint on the function's domain. The @racket[range-expr]s determine the number of results and the contract for each result. Generally, this contract must be combined with another contract to ensure that the domain is actually known to be able to safely call the function itself. For example, the contract @racketblock[ (provide (contract-out [f (->d ([size natural-number/c] [proc (and/c (unconstrained-domain-> number?) (lambda (p) (procedure-arity-includes? p size)))]) () [_ number?])])) ] says that the function @racket[f] accepts a natural number and a function. The domain of the function that @racket[f] accepts must include a case for @racket[size] arguments, meaning that @racket[f] can safely supply @racket[size] arguments to its input. For example, the following is a definition of @racket[f] that cannot be blamed using the above contract: @racketblock[ (define (f i g) (apply g (build-list i add1))) ]} @defthing[predicate/c contract?]{ Use this contract to indicate that some function is a predicate. It is semantically equivalent to @racket[(-> any/c boolean?)]. This contract also includes an optimization so that functions returning @racket[#t] from @racket[struct-predicate-procedure?] are just returned directly, without being wrapped. This contract is used by @racket[provide/contract]'s @racket[struct] sub-form so that struct predicates end up not being wrapped. } @defthing[the-unsupplied-arg unsupplied-arg?]{ Used by @racket[->i] (and @racket[->d]) to bind optional arguments that are not supplied by a call site. } @defproc[(unsupplied-arg? [v any/c]) boolean?]{ A predicate to determine whether @racket[v] is @racket[the-unsupplied-arg]. } @section[#:tag "parametric-contracts"]{Parametric Contracts} @defmodule*/no-declare[(racket/contract/parametric)] @declare-exporting-ctc[racket/contract/parametric] The most convenient way to use parametric contract is to use @racket[contract-out]'s @racket[#:exists] keyword. The @racketmodname[racket/contract/parametric] provides a few more, general-purpose parametric contracts. @defform[(parametric->/c (x ...) c)]{ Creates a contract for parametric polymorphic functions. Each function is protected by @racket[c], where each @racket[x] is bound in @racket[c] and refers to a polymorphic type that is instantiated each time the function is applied. At each application of a function, the @racket[parametric->/c] contract constructs a new opaque wrapper for each @racket[x]; values flowing into the polymorphic function (i.e. values protected by some @racket[x] in negative position with respect to @racket[parametric->/c]) are wrapped in the corresponding opaque wrapper. Values flowing out of the polymorphic function (i.e. values protected by some @racket[x] in positive position with respect to @racket[parametric->/c]) are checked for the appropriate wrapper. If they have it, they are unwrapped; if they do not, a contract violation is signaled. @examples[#:eval (contract-eval) #:once (define swap-ctc (parametric->/c [A B] (-> A B (values B A)))) (define/contract (good-swap a b) swap-ctc (values b a)) (good-swap 1 2) (define/contract (bad-swap a b) swap-ctc (values a b)) (eval:error (bad-swap 1 2)) (define/contract (copy-first a _b) swap-ctc (values a a)) (eval:error (let ((v 'same-symbol)) (copy-first v v))) (define/contract (inspect-first a b) swap-ctc (if (integer? a) (+ a b) (raise-user-error "an opaque wrapped value is not an integer"))) (eval:error (inspect-first 1 2)) ] } @defproc[(new-∀/c [name (or/c symbol? #f) #f]) contract?]{ Constructs a new universal contract. Universal contracts accept all values when in negative positions (e.g., function inputs) and wrap them in an opaque struct, hiding the precise value. In positive positions (e.g. function returns), a universal contract accepts only values that were previously accepted in negative positions (by checking for the wrappers). The name is used to identify the contract in error messages and defaults to a name based on the lexical context of @racket[new-∀/c]. For example, this contract: @racketblock[(let ([a (new-∀/c 'a)]) (-> a a))] describes the identity function (or a non-terminating function). That is, the first use of the @racket[a] appears in a negative position and thus inputs to that function are wrapped with an opaque struct. Then, when the function returns, it is checked to determine whether the result is wrapped, since the second @racket[a] appears in a positive position. The @racket[new-∀/c] contract constructor is dual to @racket[new-∃/c]. } @defproc[(new-∃/c [name (or/c symbol? #f) #f]) contract?]{ Constructs a new existential contract. Existential contracts accept all values when in positive positions (e.g., function returns) and wrap them in an opaque struct, hiding the precise value. In negative positions (e.g. function inputs), they accepts only values that were previously accepted in positive positions (by checking for the wrappers). The name is used to identify the contract in error messages and defaults to a name based on the lexical context of @racket[new-∀/c]. For example, this contract: @racketblock[(let ([a (new-∃/c 'a)]) (-> (-> a a) any/c))] describes a function that accepts the identity function (or a non-terminating function) and returns an arbitrary value. That is, the first use of the @racket[a] appears in a positive position and thus inputs to that function are wrapped with an opaque struct. Then, when the function returns, it is checked to see if the result is wrapped, since the second @racket[a] appears in a negative position. The @racket[new-∃/c] construct constructor is dual to @racket[new-∀/c]. } @; ------------------------------------------------------------------------ @section{Lazy Data-structure Contracts} @defform[(contract-struct id (field-id ...))]{ @deprecated[@racket[struct]]{Lazy struct contracts no longer require a separate struct declaration; instead @racket[struct/dc] and @racket[struct/c] work directly with @racket[struct] and @racket[define-struct]. } Like @racket[struct], but with two differences: they do not define field mutators, and they define two contract constructors: @racket[id]@racketidfont{/c} and @racket[id]@racketidfont{/dc}. The first is a procedure that accepts as many arguments as there are fields and returns a contract for struct values whose fields match the arguments. The second is a syntactic form that also produces contracts on the structs, but the contracts on later fields may depend on the values of earlier fields. The generated contract combinators are @italic{lazy}: they only verify the contract holds for the portion of some data structure that is actually inspected. More precisely, a lazy data structure contract is not checked until a selector extracts a field of a struct. @specsubform/subs[ (#,(elem (racket id) (racketidfont "/dc")) field-spec ...) ([field-spec [field-id contract-expr] [field-id (field-id ...) contract-expr]]) ]{ In each @racket[field-spec] case, the first @racket[field-id] specifies which field the contract applies to; the fields must be specified in the same order as the original @racket[contract-struct]. The first case is for when the contract on the field does not depend on the value of any other field. The second case is for when the contract on the field does depend on some other fields, and the parenthesized @racket[field-id]s indicate which fields it depends on; these dependencies can only be to earlier fields.}} @defform[(define-contract-struct id (field-id ...))]{ @deprecated[@racket[struct]]{Lazy struct contracts no longer require a separate struct declaration; instead @racket[struct/dc] and @racket[struct/c] work directly with @racket[struct] and @racket[define-struct]. } Like @racket[contract-struct], but where the constructor's name is @racketidfont["make-"]@racket[id], much like @racket[define-struct]. } @; ------------------------------------------------------------------------ @include-section["contracts-struct-prop.scrbl"] @; ------------------------------------------------------------------------ @section[#:tag "attaching-contracts-to-values"]{Attaching Contracts to Values} @declare-exporting-ctc[racket/contract/base] @defform/subs[ #:literals (struct rename) (contract-out unprotected-submodule contract-out-item ...) ([unprotected-submodule (code:line) (code:line #:unprotected-submodule submodule-name)] [contract-out-item (struct id/ignored ((id contract-expr) ...) struct-option) (rename orig-id id contract-expr) (id contract-expr) (code:line #:∃ poly-variables) (code:line #:exists poly-variables) (code:line #:∀ poly-variables) (code:line #:forall poly-variables)] [poly-variables id (id ...)] [id/ignored id (id ignored-id)] [struct-option (code:line) #:omit-constructor])]{ A @racket[_provide-spec] for use in @racket[provide] (currently only for the same @tech{phase level} as the @racket[provide] form; for example, @racket[contract-out] cannot be nested within @racket[for-syntax]). Each @racket[id] is provided from the module. In addition, clients of the module must live up to the contract specified by @racket[contract-expr] for each export. The @racket[contract-out] form treats modules as units of blame. The module that defines the provided variable is expected to meet the positive (co-variant) positions of the contract. Each module that imports the provided variable must obey the negative (contra-variant) positions of the contract. Each @racket[contract-expr] in a @racket[contract-out] form is effectively moved to the end of the enclosing module, so a @racket[contract-expr] can refer to variables that are defined later in the same module. Only uses of the contracted variable outside the module are checked. Inside the module, no contract checking occurs. The @racket[rename] form of @racket[contract-out] exports the first variable (the internal name) with the name specified by the second variable (the external name). The @racket[struct] form of @racket[contract-out] provides a structure-type definition @racket[id], and each field has a contract that dictates the contents of the fields. Unlike a @racket[struct] definition, however, all of the fields (and their contracts) must be listed. The contract on the fields that the sub-struct shares with its parent are only used in the contract for the sub-struct's constructor, and the selector or mutators for the super-struct are not provided. The exported structure-type name always doubles as a constructor, even if the original structure-type name does not act as a constructor. If the @racket[#:omit-constructor] option is present, the constructor is not provided. The second form of @racket[id/ignored], which has both @racket[id] and @racket[ignored-id], is deprecated and allowed in the grammar only for backward compatability, where @racket[ignored-id] is ignored. The first form should be used instead. Note that if the struct is created with @racket[serializable-struct] or @racket[define-serializable-struct], @racket[contract-out] does not protect struct instances that are created via @racket[deserialize]. Consider using @racket[struct-guard/c] instead. The @racket[#:∃], @racket[#:exists], @racket[#:∀], and @racket[#:forall] clauses define new abstract contracts. The variables are bound in the remainder of the @racket[contract-out] form to new contracts that hide the values they accept and ensure that the exported functions are treated parametrically. See @racket[new-∃/c] and @racket[new-∀/c] for details on how the clauses hide the values. If @racket[#:unprotected-submodule] appears, the identifier that follows it is used as the name of a submodule that @racket[contract-out] generates. The submodule exports all of the names in the @racket[contract-out], but without contracts. The implementation of @racket[contract-out] uses @racket[syntax-property] to attach properties to the code it generates that records the syntax of the contracts in the fully expanded program. Specifically, the symbol @indexed-racket['provide/contract-original-contract] is bound to vectors of two elements, the exported identifier and a syntax object for the expression that produces the contract controlling the export. @history[#:changed "7.3.0.3" @list{Added @racket[#:unprotected-submodule].} #:changed "7.7.0.9" @list{Started ignoring @racket[ignored-id].}] } @defform[(recontract-out id ...)]{ A @racket[_provide-spec] for use in @racket[provide] (currently, just like @racket[contract-out], only for the same @tech{phase level} as the @racket[provide] form). It re-exports @racket[id], but with positive blame associated to the module containing @racket[recontract-out] instead of the location of the original site of @racket[id]. This can be useful when a public module wants to export an identifier from a private module but where any contract violations should be reported in terms of the public module instead of the private one. @examples[#:eval (contract-eval) #:once (module private-implementation racket/base (require racket/contract) (define (recip x) (/ 1 x)) (define (non-zero? x) (not (= x 0))) (provide/contract [recip (-> (and/c real? non-zero?) (between/c -1 1))])) (module public racket/base (require racket/contract 'private-implementation) (provide (recontract-out recip))) (require 'public) (eval:error (recip +nan.0))] Replacing the use of @racket[recontract-out] with just @racket[recip] would result in a contract violation blaming the private module. } @defform[(provide/contract unprotected-submodule contract-out-item ...)]{ A legacy shorthand for @racket[(provide (contract-out unprotected-submodule contract-out-item ...))], except that a @racket[_contract-expr] within @racket[provide/contract] is evaluated at the position of the @racket[provide/contract] form instead of at the end of the enclosing module.} @defform[(struct-guard/c contract-expr ...)]{ Returns a procedure suitable to be passed as the @racket[#:guard] argument to @racket[struct], @racket[serializable-struct] (and related forms). The guard procedure ensures that each contract protects the corresponding field values, as long as the struct is not mutated. Mutations are not protected. @examples[#:eval (contract-eval) #:once (struct snake (weight hungry?) #:guard (struct-guard/c real? boolean?)) (eval:error (snake 1.5 "yep"))] } @subsection{Nested Contract Boundaries} @defmodule*/no-declare[(racket/contract/region)] @declare-exporting-ctc[racket/contract/region] @defform*/subs[ [(with-contract blame-id (wc-export ...) free-var-list ... body ...+) (with-contract blame-id results-spec free-var-list ... body ...+)] ([wc-export (id contract-expr)] [result-spec (code:line #:result contract-expr) (code:line #:results (contract-expr ...))] [free-var-list (code:line) (code:line #:freevar id contract-expr) (code:line #:freevars ([id contract-expr] ...))])]{ Generates a local contract boundary. The first @racket[with-contract] form cannot appear in expression position. All names defined within the first @racket[with-contract] form are visible externally, but those names listed in the @racket[wc-export] list are protected with the corresponding contract. The @racket[body] of the form allows definition/expression interleaving if its context does. The second @racket[with-contract] form must appear in expression position. The final @racket[body] expression should return the same number of values as the number of contracts listed in the @racket[result-spec], and each returned value is contracted with its respective contract. The sequence of @racket[body] forms is treated as for @racket[let]. The @racket[blame-id] is used for the positive positions of contracts paired with exported @racket[id]s. Contracts broken within the @racket[with-contract] @racket[body] will use the @racket[blame-id] for their negative position. If a @racket[free-var-list] is given, then any uses of the free variables inside the @racket[body] will be protected with contracts that blame the context of the @racket[with-contract] form for the positive positions and the @racket[with-contract] form for the negative ones.} @(define furlongs->feet-eval (contract-eval)) @defform*[[(define/contract id contract-expr free-var-list init-value-expr) (define/contract (head args) contract-expr free-var-list body ...+)]]{ Works like @racket[define], except that the contract @racket[contract-expr] is attached to the bound value. For the definition of @racket[head] and @racket[args], see @racket[define]. For the definition of @racket[free-var-list], see @racket[with-contract]. @examples[#:eval furlongs->feet-eval (define/contract distance (>=/c 0) 43.52) (define/contract (furlongs->feet fr) (-> real? real?) (* 660 fr)) (code:comment "a contract violation expected here:") (eval:error (furlongs->feet "not a furlong")) ] The @racket[define/contract] form treats the individual definition as a contract region. The definition itself is responsible for positive (co-variant) positions of the contract, and references to @racket[id] outside of the definition must meet the negative positions of the contract. Since the contract boundary is between the definition and the surrounding context, references to @racket[id] inside the @racket[define/contract] form are not checked. @examples[#:eval (contract-eval) #:once (code:comment "an unsual predicate that prints when called") (define (printing-int? x) (displayln "I was called") (exact-integer? x)) (define/contract (fact n) (-> printing-int? printing-int?) (if (zero? n) 1 (* n (fact (sub1 n))))) (code:line (fact 5) (code:comment "only prints twice, not for each recursive call")) ] If a free-var-list is given, then any uses of the free variables inside the @racket[body] will be protected with contracts that blame the context of the @racket[define/contract] form for the positive positions and the @racket[define/contract] form for the negative ones. @examples[#:eval (contract-eval) #:once (define (integer->binary-string n) (number->string n 2)) (define/contract (numbers->strings lst) (-> (listof number?) (listof string?)) #:freevar integer->binary-string (-> exact-integer? string?) (code:comment "mistake, lst might contain inexact numbers") (map integer->binary-string lst)) (eval:error (numbers->strings '(4.0 3.3 5.8))) ]} @defform*[[(struct/contract struct-id ([field contract-expr] ...) struct-option ...) (struct/contract struct-id super-struct-id ([field contract-expr] ...) struct-option ...)]]{ Works like @racket[struct], except that the arguments to the constructor, accessors, and mutators are protected by contracts. For the definitions of @racket[field] and @racket[struct-option], see @racket[struct]. The @racket[struct/contract] form only allows a subset of the @racket[struct-option] keywords: @racket[#:mutable], @racket[#:transparent], @racket[#:auto-value], @racket[#:omit-define-syntaxes], @racket[#:property] and @racket[#:omit-define-values]. @examples[#:eval (contract-eval) #:once (struct/contract fruit ([seeds number?])) (fruit 60) (eval:error (fruit #f)) (struct/contract apple fruit ([type string?])) (apple 14 "golden delicious") (eval:error (apple 5 30)) (eval:error (apple #f "granny smith")) ]} @defform*[[(define-struct/contract struct-id ([field contract-expr] ...) struct-option ...) (define-struct/contract (struct-id super-struct-id) ([field contract-expr] ...) struct-option ...)]]{ Works like @racket[struct/contract], except that the syntax for supplying a @racket[super-struct-id] is different, and a @racket[_constructor-id] that has a @racketidfont{make-} prefix on @racket[struct-id] is implicitly supplied. For the definitions of @racket[field] and @racket[struct-option], see @racket[define-struct]. The @racket[define-struct/contract] form only allows a subset of the @racket[struct-option] keywords: @racket[#:mutable], @racket[#:transparent], @racket[#:auto-value], @racket[#:omit-define-syntaxes], @racket[#:property] and @racket[#:omit-define-values]. @examples[#:eval (contract-eval) #:once (define-struct/contract fish ([color number?])) (make-fish 5) (eval:error (make-fish #f)) (define-struct/contract (salmon fish) ([ocean symbol?])) (make-salmon 5 'atlantic) (eval:error (make-salmon 5 #f)) (eval:error (make-salmon #f 'pacific)) ]} @defform[(invariant-assertion invariant-expr expr)]{ Establishes an invariant of @racket[expr], determined by @racket[invariant-expr]. Unlike the specification of a contract, an @racket[invariant-assertion] does not establish a boundary between two parties. Instead, it simply attaches a logical assertion to the value. Because the form uses contract machinery to check the assertion, the surrounding module is treated as the party to be blamed for any violations of the assertion. This means, for example, that the assertion is checked on recursive calls, when an invariant is used on the right-hand side of a definition: @examples[#:eval furlongs->feet-eval (define furlongss->feets (invariant-assertion (-> (listof real?) (listof real?)) (λ (l) (cond [(empty? l) empty] [else (if (= 327 (car l)) (furlongss->feets (list "wha?")) (cons (furlongs->feet (first l)) (furlongss->feets (rest l))))])))) (furlongss->feets (list 1 2 3)) (eval:error (furlongss->feets (list 1 327 3)))] @history[#:added "6.0.1.11"] } @defidform[current-contract-region]{ Bound by @racket[define-syntax-parameter], this contains information about the current contract region, used by the above forms to determine the candidates for blame assignment. } @subsection{Low-level Contract Boundaries} @declare-exporting-ctc[racket/contract/base] @defform[(define-module-boundary-contract id orig-id contract-expr pos-blame-party source-loc name-for-blame context-limit) #:grammar ([pos-blame-party (code:line) (code:line #:pos-source pos-source-expr)] [source-loc (code:line) (code:line #:srcloc srcloc-expr)] [name-for-blame (code:line) (code:line #:name-for-blame blame-id)] [context-limit (code:line) (code:line #:context-limit limit-expr)])]{ Defines @racket[id] to be @racket[orig-id], but with the contract @racket[contract-expr]. The identifier @racket[id] is defined as a macro transformer that consults the context of its use to determine the name for negative blame assignment (using the entire module where a reference appears as the negative party). The positive party defaults to the module containing the use of @racket[define-module-boundary-contract], but can be specified explicitly via the @racket[#:pos-source] keyword. The source location used in the blame error messages for the location of the place where the contract was put on the value defaults to the source location of the use of @racket[define-module-boundary-contract], but can be specified via the @racket[#:srcloc] argument, in which case it can be any of the things that the third argument to @racket[datum->syntax] can be. The name used in the error messages will be @racket[orig-id], unless @racket[#:name-for-blame] is supplied, in which case the identifier following it is used as the name in the error messages. If @racket[#:context-limit] is supplied, it behaves the same as it does when supplied to @racket[contract]. @examples[#:eval (contract-eval) #:once (module server racket/base (require racket/contract/base) (define (f x) #f) (define-module-boundary-contract g f (-> integer? integer?)) (provide g)) (module client racket/base (require 'server) (define (clients-fault) (g #f)) (define (servers-fault) (g 1)) (provide servers-fault clients-fault)) (require 'client) (eval:error (clients-fault)) (eval:error (servers-fault))] @history[#:changed "6.7.0.4" @elem{Added the @racket[#:name-for-blame] argument.} #:changed "6.90.0.29" @elem{Added the @racket[#:context-limit] argument.}] } @defform*[[(contract contract-expr to-protect-expr positive-blame-expr negative-blame-expr) (contract contract-expr to-protect-expr positive-blame-expr negative-blame-expr #:context-limit limit-expr) (contract contract-expr to-protect-expr positive-blame-expr negative-blame-expr value-name-expr source-location-expr)]]{ The primitive mechanism for attaching a contract to a value. The purpose of @racket[contract] is as a target for the expansion of some higher-level contract specifying form. The @racket[contract] expression adds the contract specified by @racket[contract-expr] to the value produced by @racket[to-protect-expr]. The result of a @racket[contract] expression is the result of the @racket[to-protect-expr] expression, but with the contract specified by @racket[contract-expr] enforced on @racket[to-protect-expr]. The values of @racket[positive-blame-expr] and @racket[negative-blame-expr] indicate how to assign blame for positive and negative positions of the contract specified by @racket[contract-expr]. They may be any value, and are formatted as by @racket[display] for purposes of contract violation error messages. If specified, @racket[value-name-expr] indicates a name for the protected value to be used in error messages. If not supplied, or if @racket[value-name-expr] produces @racket[#f], no name is printed. Otherwise, it is also formatted as by @racket[display]. More precisely, the @racket[value-name-expr] ends up in the @racket[blame-name] field of the blame record, which is used as the first portion of the error message. @examples[#:eval (contract-eval) #:once (eval:error (contract integer? #f 'pos 'neg 'timothy #f)) (eval:error (contract integer? #f 'pos 'neg #f #f))] If specified, @racket[source-location-expr] indicates the source location reported by contract violations. The expression must produce a @racket[srcloc] structure, @tech{syntax object}, @racket[#f], or a list or vector in the format accepted by the third argument to @racket[datum->syntax]. If @racket[#:context-limit] is supplied, the following expression must evaluate to either @racket[#f] or a natural number. If the expression evaluates to an natural number, the number of layers of context information is limited to at most that many. For example, if the number is @racket[0], no context information is recorded and the error messages do not contain the section that starts with @litchar{in:}. } @; ------------------------------------------------------------------------ @section{Building New Contract Combinators} @defmodule*/no-declare[(racket/contract/combinator)] @declare-exporting-ctc[racket/contract/combinator] @deftogether[( @defproc[(make-contract [#:name name any/c 'anonymous-contract] [#:first-order first-order (-> any/c any/c) (λ (x) #t)] [#:late-neg-projection late-neg-proj (or/c #f (-> blame? (-> any/c any/c any/c))) #f] [#:collapsible-late-neg-projection collapsible-late-neg-proj (or/c #f (-> blame? (values (-> any/c any/c any/c) collapsible-contract?))) #f] [#:val-first-projection val-first-proj (or/c #f (-> blame? (-> any/c (-> any/c any/c)))) #f] [#:projection proj (-> blame? (-> any/c any/c)) (λ (b) (λ (x) (if (first-order x) x (raise-blame-error b x '(expected: "~a" given: "~e") name x))))] [#:stronger stronger (or/c #f (-> contract? contract? boolean?)) #f] [#:equivalent equivalent (or/c #f (-> contract? contract? boolean?)) #f] [#:list-contract? is-list-contract? boolean? #f]) contract?] @defproc[(make-chaperone-contract [#:name name any/c 'anonymous-chaperone-contract] [#:first-order first-order (-> any/c any/c) (λ (x) #t)] [#:late-neg-projection late-neg-proj (or/c #f (-> blame? (-> any/c any/c any/c))) #f] [#:collapsible-late-neg-projection collapsible-late-neg-proj (or/c #f (-> blame? (values (-> any/c any/c any/c) collapsible-contract?))) #f] [#:val-first-projection val-first-proj (or/c #f (-> blame? (-> any/c (-> any/c any/c)))) #f] [#:projection proj (-> blame? (-> any/c any/c)) (λ (b) (λ (x) (if (first-order x) x (raise-blame-error b x '(expected: "~a" given: "~e") name x))))] [#:stronger stronger (or/c #f (-> contract? contract? boolean?)) #f] [#:equivalent equivalent (or/c #f (-> contract? contract? boolean?)) #f] [#:list-contract? is-list-contract? boolean? #f]) chaperone-contract?] @defproc[(make-flat-contract [#:name name any/c 'anonymous-flat-contract] [#:first-order first-order (-> any/c any/c) (λ (x) #t)] [#:late-neg-projection late-neg-proj (or/c #f (-> blame? (-> any/c any/c any/c))) #f] [#:collapsible-late-neg-projection collapsible-late-neg-proj (or/c #f (-> blame? (values (-> any/c any/c any/c) collapsible-contract?))) #f] [#:val-first-projection val-first-proj (or/c #f (-> blame? (-> any/c (-> any/c any/c)))) #f] [#:projection proj (-> blame? (-> any/c any/c)) (λ (b) (λ (x) (if (first-order x) x (raise-blame-error b x '(expected: "~a" given: "~e") name x))))] [#:stronger stronger (or/c #f (-> contract? contract? boolean?)) #f] [#:equivalent equivalent (or/c #f (-> contract? contract? boolean?)) #f] [#:list-contract? is-list-contract? boolean? #f]) flat-contract?] )]{ These functions build simple higher-order contracts, @tech{chaperone contracts}, and @tech{flat contracts}, respectively. They all take the same set of three optional arguments: a name, a first-order predicate, and a blame-tracking projection. For @racket[make-flat-contract], see also @racket[flat-contract-with-explanation]. The @racket[name] argument is any value to be rendered using @racket[display] to describe the contract when a violation occurs. The default name for simple higher-order contracts is @racketresult[anonymous-contract], for @tech{chaperone contracts} is @racketresult[anonymous-chaperone-contract], and for @tech{flat contracts} is @racketresult[anonymous-flat-contract]. The first-order predicate @racket[first-order] is used to determine which values the contract applies to. This test is used by @racket[contract-first-order-passes?], and indirectly by @racket[or/c] and @racket[first-or/c] to determine which higher-order contract to wrap a value with when there are multiple higher-order contracts to choose from. The default value accepts any value, but it must match the behavior of the projection argument (see below for how). The predicate should be influenced by the value of @racket[(contract-first-order-okay-to-give-up?)] (see it's documentation for more explanation). The @racket[late-neg-proj] argument defines the behavior of applying the contract via a @deftech{late neg projection}. If it is supplied, this argument accepts a @tech{blame object} that is missing one party (see also @racket[blame-missing-party?]). Then it must return a function that accepts both the value that is getting the contract and the name of the missing blame party, in that order. The result must either be the value (perhaps suitably wrapped with a @tech{chaperone} or @tech{impersonator} to enforce the contract), or signal a contract violation using @racket[raise-blame-error]. The default is @racket[#f]. The @racket[collapsible-late-neg-proj] argument takes the place of the @racket[late-neg-proj] argument for contracts that support collapsing. If it is supplied, this argument accepts a @tech{blame object} that is missing one party. It must return two values. The first value must be a function that accepts both the value that is getting the contract and the name of the missing blame party, in that order. The second value should be a @tech[#:key "collapsible contract"]{collapsible} representation of the contract. The projection @racket[proj] and @racket[val-first-proj] are older mechanisms for defining the behavior of applying the contract. The @racket[proj] argument is a curried function of two arguments: the first application accepts a blame object, and the second accepts a value to protect with the contract. The projection must either produce the value, suitably wrapped to enforce any higher-order aspects of the contract, or signal a contract violation using @racket[raise-blame-error]. The default projection produces an error when the first-order test fails, and produces the value unchanged otherwise. The @racket[val-first-proj] is like @racket[late-neg-proj], except with an extra layer of currying. At least one of the @racket[late-neg-proj], @racket[proj], @racket[val-first-proj], or @racket[first-order] must be non-@racket[#f]. The projection arguments (@racket[late-neg-proj], @racket[proj], and @racket[val-first-proj]) must be in sync with the @racket[first-order] argument. In particular, if the @racket[first-order] argument returns @racket[#f] for some value, then the projections must raise a blame error for that value and if the @racket[first-order] argument returns @racket[#t] for some value, then the projection must not signal any blame for this value, unless there are higher-order interactions later. In other words, for @tech{flat contracts}, the @racket[first-order] and @racket[projection] arguments must check the same predicate. For convenience, the the default projection uses the @racket[first-order] argument, signalling an error when it returns @racket[#f] and never signalling one otherwise. Projections for @tech{chaperone contracts} must produce a value that passes @racket[chaperone-of?] when compared with the original, uncontracted value. Projections for @tech{flat contracts} must fail precisely when @racket[first-order] does, and must produce the input value unchanged otherwise. Applying a @tech{flat contract} may result in either an application of the predicate, or the projection, or both; therefore, the two must be consistent. The existence of a separate projection only serves to provide more specific error messages. Most @tech{flat contracts} do not need to supply an explicit projection. The @racket[stronger] argument is used to implement @racket[contract-stronger?]. The first argument is always the contract itself and the second argument is whatever was passed as the second argument to @racket[contract-stronger?]. If no @racket[stronger] argument is supplied, then a default that compares its arguments with @racket[equal?] is used for @tech{flat contracts} and @tech{chaperone contracts}. For @tech{impersonator contracts} constructed with @racket[make-contract] that do not supply the @racket[stronger] argument, @racket[contract-stronger?] returns @racket[#f]. Similarly, the @racket[equivalent] argument is used to implement @racket[contract-equivalent?]. If it isn't supplied or @racket[#false] is supplied, then @racket[equal?] is used for chaperone and flat contracts, and @racket[(λ (x y) #f)] is used otherwise. The @racket[is-list-contract?] argument is used by the @racket[list-contract?] predicate to determine if this is a contract that accepts only @racket[list?] values. @examples[#:eval (contract-eval) #:once (define int/c (make-flat-contract #:name 'int/c #:first-order integer?)) (contract int/c 1 'positive 'negative) (eval:error (contract int/c "not one" 'positive 'negative)) (int/c 1) (int/c "not one") (define int->int/c (make-contract #:name 'int->int/c #:first-order (λ (x) (and (procedure? x) (procedure-arity-includes? x 1))) #:projection (λ (b) (let ([domain ((contract-projection int/c) (blame-swap b))] [range ((contract-projection int/c) b)]) (λ (f) (if (and (procedure? f) (procedure-arity-includes? f 1)) (λ (x) (range (f (domain x)))) (raise-blame-error b f '(expected "a function of one argument" given: "~e") f))))))) (eval:error (contract int->int/c "not fun" 'positive 'negative)) (define halve (contract int->int/c (λ (x) (/ x 2)) 'positive 'negative)) (halve 2) (eval:error (halve 1/2)) (eval:error (halve 1)) ] @history[#:changed "6.0.1.13" @list{Added the @racket[#:list-contract?] argument.} #:changed "6.90.0.30" @list{Added the @racket[#:equivalent] argument.} #:changed "7.1.0.10" @list{Added the @racket[#:collapsible-late-neg-projection] argument.}] } @defproc[(build-compound-type-name [c/s any/c] ...) any]{ Produces an S-expression to be used as a name for a contract. The arguments should be either contracts or symbols. It wraps parentheses around its arguments and extracts the names from any contracts it is supplied with.} @defproc[(coerce-contract [id symbol?] [v any/c]) contract?]{ Converts a regular Racket value into an instance of a contract struct, converting it according to the description of @tech{contracts}. If @racket[v] is not one of the coercible values, @racket[coerce-contract] signals an error, using the first argument in the error message.} @defproc[(coerce-contracts [id symbol?] [vs (listof any/c)]) (listof contract?)]{ Coerces all of the arguments in @racket[vs] into contracts (via @racket[coerce-contract/f]) and signals an error if any of them are not contracts. The error messages assume that the function named by @racket[id] got @racket[vs] as its entire argument list. } @defproc[(coerce-chaperone-contract [id symbol?] [v any/c]) chaperone-contract?]{ Like @racket[coerce-contract], but requires the result to be a @tech{chaperone contract}, not an arbitrary contract. } @defproc[(coerce-chaperone-contracts [id symbol?] [vs (listof any/c)]) (listof chaperone-contract?)]{ Like @racket[coerce-contracts], but requires the results to be @tech{chaperone contracts}, not arbitrary contracts. } @defproc[(coerce-flat-contract [id symbol?] [v any/c]) flat-contract?]{ Like @racket[coerce-contract], but requires the result to be a @tech{flat contract}, not an arbitrary contract. } @defproc[(coerce-flat-contracts [id symbol?] [v (listof any/c)]) (listof flat-contract?)]{ Like @racket[coerce-contracts], but requires the results to be @tech{flat contracts}, not arbitrary contracts. } @defproc[(coerce-contract/f [v any/c]) (or/c contract? #f)]{ Like @racket[coerce-contract], but returns @racket[#f] if the value cannot be coerced to a contract. } @defparam[skip-projection-wrapper? wrap? boolean? #:value #f]{ The functions @racket[make-chaperone-contract] and @racket[build-chaperone-contract-property] wrap their arguments to ensure that the result of the projections are chaperones of the input. This layer of wrapping can, in some cases, introduce unwanted overhead into contract checking. If this parameter's value is @racket[#t] during the dynamic extent of the call to either of those functions, the wrapping (and thus the checks) are skipped. } @defform*[[(with-contract-continuation-mark blame body ...) (with-contract-continuation-mark blame+neg-party body ...)]]{ Inserts a continuation mark that informs the contract profiler (see @other-doc['(lib "contract-profile/scribblings/contract-profile.scrbl") #:indirect "contract profiling"]) that contract checking is happening. For the costs from checking your new combinator to be included, you should wrap any deferred, higher-order checks with this form. First-order checks are recognized automatically and do not require this form. If your combinator's projections operate on complete @tech{blame objects} (i.e., no missing blame parties), the @tech{blame object} should be the first argument to this form. Otherwise (e.g., in the case of @racket[_late-neg] projections), a pair of the @tech{blame object} and the missing party should be used instead. @history[#:added "6.4.0.4"] } @defform[(contract-pos/neg-doubling e1 e2)]{ Some contract combinators need to build projections for subcontracts with both regular and @racket[blame-swap]ed versions of the blame that they are given in order to check both access and mutations (e.g., @racket[vector/c] and @racket[vectorof]). In the case that such combinators are nested deeply inside each other, there is a potential for an exponential explosion of nested projections being built. To avoid that explosion, wrap each of the calls to the blame-accepting portion of the combinator in @racket[contract-pos/neg-doubling]. It returns three values. The first is a boolean, indicating how to interpret the other two results. If the boolean is @racket[#t], then the other two results are the values of @racket[e1] and @racket[e2] and we are not too deep in the nesting. If the boolean is @racket[#f], then we have passed a threshold and it is not safe to evaluate @racket[e1] and @racket[e2] yet, as we are in danger of running into the exponential slowdown. In that case, the last two results are thunks that, when invoked, compute the values of @racket[e1] and @racket[e2]. As an example, @racket[vectorof] uses @racket[contract-pos/neg-doubling] wrapping its two calls to the blame-accepting part of the projection for its subcontract. When it receives a @racket[#f] as that first boolean, it does not invoke the thunks right away, but waits until the interposition procedure that it attaches to the chaperoned vector is called. Then it invokes them (and caches the result). This delays the construction of the projections until they are actually needed, avoiding the exponential blowup. @history[#:added "6.90.0.27"] } @subsection{Blame Objects} This section describes @deftech{blame objects} and operations on them. @defproc[(blame? [v any/c]) boolean?]{ This predicate recognizes @|blame-objects|. } @defproc[(raise-blame-error [b blame?] [#:missing-party missing-party #f] [v any/c] [fmt (or/c string? (listof (or/c string? 'given 'given: 'expected 'expected:)))] [v-fmt any/c] ...) none/c]{ Signals a contract violation. The first argument, @racket[b], records the current blame information, including positive and negative parties, the name of the contract, the name of the value, and the source location of the contract application. The @racket[#:missing-party] argument supplies one of the blame parties. It should be non-@racket[#f] when the @racket[b] object was created without supplying a negative party. See @racket[blame-add-missing-party] and the description of the @racket[_late-neg-proj] argument of @racket[make-contract]. The second positional argument, @racket[v], is the value that failed to satisfy the contract. The remaining arguments are a format string, @racket[fmt], and its arguments, @racket[v-fmt ...], specifying an error message specific to the precise violation. If @racket[fmt] is a list, then the elements are concatenated together (with spaces added, unless there are already spaces at the ends of the strings), after first replacing symbols with either their string counterparts, or replacing @racket['given] with @racket["produced"] and @racket['expected] with @racket["promised"], depending on whether or not the @racket[b] argument has been swapped or not (see @racket[blame-swap]). If @racket[fmt] contains the symbols @racket['given:] or @racket['expected:], they are replaced like @racket['given] and @racket['expected] are, but the replacements are prefixed with the string @racket["\n "] to conform to the error message guidelines in @secref["err-msg-conventions"]. } @defproc[(blame-add-context [blame blame?] [context (or/c string? #f)] [#:important important (or/c string? #f) #f] [#:swap? swap? boolean? #f]) blame?]{ Adds some context information to blame error messages that explicates which portion of the contract failed (and that gets rendered by @racket[raise-blame-error]). The @racket[context] argument describes one layer of the portion of the contract, typically of the form @racket["the 1st argument of"] (in the case of a function contract) or @racket["a conjunct of"] (in the case of an @racket[and/c] contract). For example, consider this contract violation: @examples[#:label #f #:eval (contract-eval) #:once (define/contract f (list/c (-> integer? integer?)) (list (λ (x) x))) (eval:error ((car f) #f)) ] It shows that the portion of the contract being violated is the first occurrence of @racket[integer?], because the @racket[->] and the @racket[list/c] combinators each internally called @racket[blame-add-context] to add the two lines following ``in'' in the error message. The @racket[important] argument is used to build the beginning part of the contract violation. The last @racket[important] argument that gets added to a @|blame-object| is used. The @racket[class/c] contract adds an important argument, as does the @racket[->] contract (when @racket[->] knows the name of the function getting the contract). The @racket[swap?] argument has the effect of calling @racket[blame-swap] while adding the layer of context, but without creating an extra @|blame-object|. Passing @racket[#f] as the context string argument is no longer relevant. For backwards compatibility, @racket[blame-add-context] returns @racket[b] when @racket[context] is @racket[#f]. @history[#:changed "6.90.0.29" @elem{The @racket[context] argument being @racket[#f] is no longer relevant.}] } @defproc[(blame-context [blame blame?]) (listof string?)]{ Returns the context information that would be supplied in an error message, if @racket[blame] is passed to @racket[raise-blame-error]. } @deftogether[( @defproc[(blame-positive [b blame?]) any/c] @defproc[(blame-negative [b blame?]) any/c] )]{ These functions produce printable descriptions of the current positive and negative parties of a @|blame-object|. } @defproc[(blame-contract [b blame?]) any/c]{ This function produces a description of the contract associated with a blame object (the result of @racket[contract-name]). } @defproc[(blame-value [b blame?]) any/c]{ This function produces the name of the value to which the contract was applied, or @racket[#f] if no name was provided. } @defproc[(blame-source [b blame?]) srcloc?]{ This function produces the source location associated with a contract. If no source location was provided, all fields of the structure will contain @racket[#f]. } @defproc[(blame-swap [b blame?]) blame?]{ This function swaps the positive and negative parties of a @|blame-object|. (See also @racket[blame-add-context].) } @deftogether[( @defproc[(blame-original? [b blame?]) boolean?] @defproc[(blame-swapped? [b blame?]) boolean?] )]{ These functions report whether the current blame of a given @|blame-object| is the same as in the original contract invocation (possibly of a compound contract containing the current one), or swapped, respectively. Each is the negation of the other; both are provided for convenience and clarity. } @defproc[(blame-replace-negative [b blame?] [neg any/c]) blame?]{ Produces a @racket[blame?] object just like @racket[b] except that it uses @racket[neg] instead of the negative position @racket[b] has. } @defproc[(blame-replaced-negative? [b blame?]) boolean?]{ Returns @racket[#t] if @racket[b] is the result of calling @racket[blame-replace-negative] (or the result of some other function whose input was the result of @racket[blame-replace-negative]). } @defproc[(blame-update [b blame?] [pos any/c] [neg any/c]) blame?]{ Produces a @racket[blame?] object just like @racket[b] except that it adds @racket[pos] and @racket[neg] to the positive and negative parties of @racket[b] respectively. } @defproc[(blame-missing-party? [b blame?]) boolean?]{ Returns @racket[#t] when @racket[b] does not have both parties. } @defproc[(blame-add-missing-party [b (and/c blame? blame-missing-party?)] [missing-party any/c]) (and/c blame? (not/c blame-missing-party?))]{ Produces a new @tech{blame object} like @racket[b], except that the missing party is replaced with @racket[missing-party]. } @defstruct[(exn:fail:contract:blame exn:fail:contract) ([object blame?])]{ This exception is raised to signal a contract error. The @racket[object] field contains a @|blame-object| associated with a contract violation. } @defparam[current-blame-format proc (-> blame? any/c string? string?)]{ A @tech{parameter} that is used when constructing a contract violation error. Its value is procedure that accepts three arguments: @itemize[ @item{the @|blame-object| for the violation,} @item{the value that the contract applies to, and} @item{a message indicating the kind of violation.}] The procedure then returns a string that is put into the contract error message. Note that the value is often already included in the message that indicates the violation. @examples[#:eval (contract-eval) #:once (define (show-blame-error blame value message) (string-append "Contract Violation!\n" (format "Guilty Party: ~a\n" (blame-positive blame)) (format "Innocent Party: ~a\n" (blame-negative blame)) (format "Contracted Value Name: ~a\n" (blame-value blame)) (format "Contract Location: ~s\n" (blame-source blame)) (format "Contract Name: ~a\n" (blame-contract blame)) (format "Offending Value: ~s\n" value) (format "Offense: ~a\n" message))) (current-blame-format show-blame-error) (define/contract (f x) (-> integer? integer?) (/ x 2)) (f 2) (eval:error (f 1)) (eval:error (f 1/2)) ] } @subsection{Contracts as structs} @para{ The property @racket[prop:contract] allows arbitrary structures to act as contracts. The property @racket[prop:chaperone-contract] allows arbitrary structures to act as @tech{chaperone contracts}; @racket[prop:chaperone-contract] inherits @racket[prop:contract], so @tech{chaperone contract} structures may also act as general contracts. The property @racket[prop:flat-contract] allows arbitrary structures to act as @tech{flat contracts}; @racket[prop:flat-contract] inherits both @racket[prop:chaperone-contract] and @racket[prop:procedure], so @tech{flat contract} structures may also act as @tech{chaperone contracts}, as general contracts, and as predicate procedures. } @deftogether[( @defthing[prop:contract struct-type-property?] @defthing[prop:chaperone-contract struct-type-property?] @defthing[prop:flat-contract struct-type-property?] )]{ These properties declare structures to be contracts or @tech{flat contracts}, respectively. The value for @racket[prop:contract] must be a @tech{contract property} constructed by @racket[build-contract-property]; likewise, the value for @racket[prop:chaperone-contract] must be a @tech{chaperone contract property} constructed by @racket[build-chaperone-contract-property] and the value for @racket[prop:flat-contract] must be a @tech{flat contract property} constructed by @racket[build-flat-contract-property]. } @deftogether[( @defthing[prop:contracted struct-type-property?] @defthing[impersonator-prop:contracted impersonator-property?] )]{ These properties attach a contract value to the protected structure, chaperone, or impersonator value. The function @racket[has-contract?] returns @racket[#t] for values that have one of these properties, and @racket[value-contract] extracts the value from the property (which is expected to be the contract on the value). } @deftogether[( @defthing[prop:blame struct-type-property?] @defthing[impersonator-prop:blame impersonator-property?] )]{ These properties attach a blame information to the protected structure, chaperone, or impersonator value. The function @racket[has-blame?] returns @racket[#t] for values that have one of these properties, and @racket[value-blame] extracts the value from the property. The value is expected to be the blame record for the contract on the value or a @racket[cons]-pair of a blame record with a missing party and the missing party. The @racket[value-blame] function reassembles the arguments of the pair into a complete blame record using @racket[blame-add-missing-party]. If the value has one of the properties, but the value is not a @tech{blame object} or a pair whose @racket[car] position is a @tech{blame object}, then @racket[has-blame?] returns @racket[#f] but @racket[value-blame] returns @racket[#f]. } @deftogether[( @defproc[(build-flat-contract-property [#:name get-name (-> contract? any/c) (λ (c) 'anonymous-flat-contract)] [#:first-order get-first-order (-> contract? (-> any/c boolean?)) (λ (c) (λ (x) #t))] [#:late-neg-projection late-neg-proj (or/c #f (-> contract? (-> blame? (-> any/c any/c any/c)))) #f] [#:collapsible-late-neg-projection collapsible-late-neg-proj (or/c #f (-> contract? (-> blame? (values (-> any/c any/c any/c) collapsible-contract?)))) #f] [#:val-first-projection val-first-proj (or/c #f (-> contract? blame? (-> any/c (-> any/c any/c)))) #f] [#:projection get-projection (-> contract? (-> blame? (-> any/c any/c))) (λ (c) (λ (b) (λ (x) (if ((get-first-order c) x) x (raise-blame-error b x '(expected: "~a" given: "~e") (get-name c) x)))))] [#:stronger stronger (or/c (-> contract? contract? boolean?) #f) #f] [#:equivalent equivalent (or/c #f (-> contract? contract? boolean?)) #f] [#:generate generate (->i ([c contract?]) [generator (c) (-> (and/c positive? real?) (or/c (-> (or/c contract-random-generate-fail? c)) #f))]) (λ (c) (λ (fuel) #f))] [#:list-contract? is-list-contract? (-> contract? boolean?) (λ (c) #f)]) flat-contract-property?] @defproc[(build-chaperone-contract-property [#:name get-name (-> contract? any/c) (λ (c) 'anonymous-chaperone-contract)] [#:first-order get-first-order (-> contract? (-> any/c boolean?)) (λ (c) (λ (x) #t))] [#:late-neg-projection late-neg-proj (or/c #f (-> contract? (-> blame? (-> any/c any/c any/c)))) #f] [#:collapsible-late-neg-projection collapsible-late-neg-proj (or/c #f (-> contract? (-> blame? (values (-> any/c any/c any/c) collapsible-contract?)))) #f] [#:val-first-projection val-first-proj (or/c #f (-> contract? blame? (-> any/c (-> any/c any/c)))) #f] [#:projection get-projection (-> contract? (-> blame? (-> any/c any/c))) (λ (c) (λ (b) (λ (x) (if ((get-first-order c) x) x (raise-blame-error b x '(expected: "~a" given: "~e") (get-name c) x)))))] [#:stronger stronger (or/c (-> contract? contract? boolean?) #f) #f] [#:equivalent equivalent (or/c #f (-> contract? contract? boolean?)) #f] [#:generate generate (->i ([c contract?]) [generator (c) (-> (and/c positive? real?) (or/c (-> (or/c contract-random-generate-fail? c)) #f))]) (λ (c) (λ (fuel) #f))] [#:exercise exercise (->i ([c contract?]) [result (c) (-> (and/c positive? real?) (values (-> c void?) (listof contract?)))]) (λ (c) (λ (fuel) (values void '())))] [#:list-contract? is-list-contract? (-> contract? boolean?) (λ (c) #f)]) chaperone-contract-property?] @defproc[(build-contract-property [#:name get-name (-> contract? any/c) (λ (c) 'anonymous-contract)] [#:first-order get-first-order (-> contract? (-> any/c boolean?)) (λ (c) (λ (x) #t))] [#:late-neg-projection late-neg-proj (or/c #f (-> contract? (-> blame? (-> any/c any/c any/c)))) #f] [#:collapsible-late-neg-projection collapsible-late-neg-proj (or/c #f (-> contract? (-> blame? (values (-> any/c any/c any/c) collapsible-contract?)))) #f] [#:val-first-projection val-first-proj (or/c #f (-> contract? blame? (-> any/c (-> any/c any/c)))) #f] [#:projection get-projection (-> contract? (-> blame? (-> any/c any/c))) (λ (c) (λ (b) (λ (x) (if ((get-first-order c) x) x (raise-blame-error b x '(expected: "~a" given: "~e") (get-name c) x)))))] [#:stronger stronger (or/c (-> contract? contract? boolean?) #f) #f] [#:equivalent equivalent (or/c #f (-> contract? contract? boolean?)) #f] [#:generate generate (->i ([c contract?]) [generator (c) (-> (and/c positive? real?) (or/c (-> (or/c contract-random-generate-fail? c)) #f))]) (λ (c) (λ (fuel) #f))] [#:exercise exercise (->i ([c contract?]) [result (c) (-> (and/c positive? real?) (values (-> c void?) (listof contract?)))]) (λ (c) (λ (fuel) (values void '())))] [#:list-contract? is-list-contract? (-> contract? boolean?) (λ (c) #f)]) contract-property?])]{ These functions build the arguments for @racket[prop:contract], @racket[prop:chaperone-contract], and @racket[prop:flat-contract], respectively. A @deftech{contract property} specifies the behavior of a structure when used as a contract. It is specified in terms of seven properties: @itemlist[ @item{@racket[get-name] which produces a description to @racket[write] as part of a contract violation;} @item{@racket[get-first-order], which produces a first-order predicate to be used by @racket[contract-first-order-passes?];} @item{@racket[late-neg-proj], which produces a blame-tracking projection defining the behavior of the contract (The @racket[get-projection] and @racket[val-first-proj] arguments also specify the projection, but using a different signature. They are here for backwards compatibility.);} @item{@racket[collapsible-late-neg-proj], similar to @racket[late-neg-proj] which produces a blame-tracking projection defining the behavior of the contract, this function additionally specifies the @tech[#:key "collapsible contract"]{collapsible} behavior of the contract;} @item{@racket[stronger], a predicate that determines whether this contract (passed in the first argument) is stronger than some other contract (passed in the second argument) and whose default always returns @racket[#f];} @item{@racket[equivalent], a predicate that determines whether this contract (passed in the first argument) is equivalent to some other contract (passed in the second argument); the default for flat and chaperone contracts is @racket[equal?] and for impersonator contracts returns @racket[#f];} @item{@racket[generate], which returns a thunk that generates random values matching the contract (using @racket[contract-random-generate-fail]) to indicate failure) or @racket[#f] to indicate that random generation for this contract isn't supported;} @item{@racket[exercise], which returns a function that exercises values matching the contract (e.g., if it is a function contract, it may call the function) and a list of contracts whose values will be generated by this process;} @item{and @racket[is-list-contract?], which is used by @racket[flat-contract?] to determine if this contract accepts only @racket[list?]s.} ] At least one of the @racket[late-neg-proj], @racket[collapsible-late-neg-proj], @racket[get-projection], @racket[val-first-proj], or @racket[get-first-order] must be non-@racket[#f]. These accessors are passed as (optional) keyword arguments to @racket[build-contract-property], and are applied to instances of the appropriate structure type by the contract system. Their results are used analogously to the arguments of @racket[make-contract]. A @deftech{chaperone contract property} specifies the behavior of a structure when used as a chaperone contract. It is specified using @racket[build-chaperone-contract-property], and accepts exactly the same set of arguments as @racket[build-contract-property]. The only difference is that the projection accessor must return a value that passes @racket[chaperone-of?] when compared with the original, uncontracted value. A @deftech{flat contract property} specifies the behavior of a structure when used as a @tech{flat contract}. It is specified using @racket[build-flat-contract-property], and accepts similar arguments as @racket[build-contract-property]. The differences are: @itemlist[ @item{the projection accessor is expected not to wrap its argument in a higher-order fashion, analogous to the constraint on projections in @racket[make-flat-contract];} @item{the @racket[#:exercise] keyword argument is omitted because it is not relevant for flat contracts.}] @history[#:changed "6.0.1.13" @list{Added the @racket[#:list-contract?] argument.} #:changed "6.1.1.4" @list{Allow @racket[generate] to return @racket[contract-random-generate-fail].} #:changed "6.90.0.30" @list{Added the @racket[#:equivalent] argument.} #:changed "7.1.0.10" @list{Added the @racket[#:collapsible-late-neg-projection] argument.}] } @deftogether[( @defproc[(contract-property? [v any/c]) boolean?] @defproc[(chaperone-contract-property? [v any/c]) boolean?] @defproc[(flat-contract-property? [v any/c]) boolean?] )]{ These predicates detect whether a value is a @tech{contract property}, @tech{chaperone contract property}, or a @tech{flat contract property}, respectively. } @subsection{Obligation Information in Check Syntax} @seclink[#:doc '(lib "scribblings/drracket/drracket.scrbl") "buttons" #:indirect? #t]{Check Syntax} in DrRacket shows obligation information for contracts according to @racket[syntax-property]s that the contract combinators leave in the expanded form of the program. These properties indicate where contracts appear in the source and where the positive and negative positions of the contracts appear. To make Check Syntax show obligation information for your new contract combinators, use the following properties (some helper macros and functions are below): @itemize[@item{@index["racket/contract:contract"] @racketblock0['racket/contract:contract : (vector/c symbol? (listof syntax?) (listof syntax?))] This property should be attached to the result of a transformer that implements a contract combinator. It signals to Check Syntax that this is where a contract begins. The first element in the vector should be a unique (in the sense of @racket[eq?]) value that Check Syntax can use a tag to match up this contract with its subpieces (specified by the two following syntax properties). The second and third elements of the vector are syntax objects from pieces of the contract, and Check Syntax will color them. The first list should contain subparts that are the responsibility of parties (typically modules) that provide implementations of the contract. The second list should contain subparts that are the responsibility of clients. For example, in @racket[(->* () #:pre #t any/c #:post #t)], the @racket[->*] and the @racket[#:post] should be in the first list and @racket[#:pre] in the second list.} @item{@index["racket/contract:negative-position"] @racketblock0['racket/contract:negative-position : symbol?] This property should be attached to sub-expressions of a contract combinator that are expected to be other contracts. The value of the property should be the key (the first element from the vector for the @racket['racket/contract:contract] property) indicating which contract this is. This property should be used when the expression's value is a contract that clients are responsible for. } @item{@index["racket/contract:positive-position"] @racketblock0['racket/contract:positive-position : symbol?] This form is just like @racket['racket/contract:negative-position], except that it should be used when the expression's value is a contract that the original party should be responsible for. } @item{@index["racket/contract:contract-on-boundary"] @racketblock0['racket/contract:contract-on-boundary : symbol?] The presence of this property tells Check Syntax that it should start coloring from this point. It expects the expression to be a contract (and, thus, to have the @racket['racket/contract:contract] property); this property indicates that this contract is on a (module) boundary. (The value of the property is not used.) } @item{@index["racket/contract:internal-contract"] @racketblock0['racket/contract:internal-contract : symbol?] Like @racket['racket/contract:contract-on-boundary], the presence of this property triggers coloring, but this is meant for use when the party (module) containing the contract (regardless of whether or not this module exports anything matching the contract) can be blamed for violating the contract. This comes into play for @racket[->i] contracts, since the contract itself has access to values under contract via the dependency. } ] @defform/subs[(define/final-prop header body ...) ([header main-id (main-id id ...) (main-id id ... . id)])]{ The same as @racket[(define header body ...)], except that uses of @racket[main-id] in the header are annotated with the @racket['racket/contract:contract] property (as above). } @defform/subs[(define/subexpression-pos-prop header body ...) ([header main-id (main-id id ...) (main-id id ... . id)])]{ The same as @racket[(define header body ...)], except that uses of @racket[main-id] in the header are annotated with the @racket['racket/contract:contract] property (as above) and arguments are annotated with the @racket['racket/contract:positive-position] property. } @; ------------------------------------------------------------------------ @subsection{Utilities for Building New Combinators} @defproc[(contract-stronger? [c1 contract?] [c2 contract?]) boolean?]{ Returns @racket[#t] if the contract @racket[c1] accepts either fewer or the same set of values that @racket[c2] does. @tech{Chaperone contracts} and @tech{flat contracts} that are the same (i.e., where @racket[c1] is @racket[equal?] to @racket[c2]) are considered to always be stronger than each other. This function is conservative, so it may return @racket[#f] when @racket[c1] does, in fact, accept fewer values. @examples[#:eval (contract-eval) #:once (contract-stronger? integer? integer?) (contract-stronger? (between/c 25 75) (between/c 0 100)) (contract-stronger? (between/c 0 100) (between/c 25 75)) (contract-stronger? (between/c -10 0) (between/c 0 10)) (contract-stronger? (λ (x) (and (real? x) (<= x 0))) (λ (x) (and (real? x) (<= x 100))))] } @defproc[(contract-equivalent? [c1 contract?] [c2 contract?]) boolean?]{ Returns @racket[#t] if the contract @racket[c1] accepts the same set of values that @racket[c2] does. @tech{Chaperone contracts} and @tech{flat contracts} that are the same (i.e., where @racket[c1] is @racket[equal?] to @racket[c2]) are considered to always be equivalent to each other. This function is conservative, so it may return @racket[#f] when @racket[c1] does, in fact, accept the same set of values that @racket[c2] does. @examples[#:eval (contract-eval) #:once (contract-equivalent? integer? integer?) (contract-equivalent? (non-empty-listof integer?) (cons/c integer? (listof integer?))) (contract-equivalent? (λ (x) (and (real? x) (and (number? x) (>= (sqr x) 0)))) (λ (x) (and (real? x) (real? x))))] @history[#:added "6.90.0.30"] } @defproc[(contract-first-order-passes? [contract contract?] [v any/c]) boolean?]{ Returns a boolean indicating whether the first-order tests of @racket[contract] pass for @racket[v]. If it returns @racket[#f], the contract is guaranteed not to hold for that value; if it returns @racket[#t], the contract may or may not hold. If the contract is a first-order contract, a result of @racket[#t] guarantees that the contract holds. See also @racket[contract-first-order-okay-to-give-up?] and @racket[contract-first-order-try-less-hard]. } @defproc[(contract-first-order [c contract?]) (-> any/c boolean?)]{ Produces the first-order test used by @racket[or/c] to match values to higher-order contracts. } @section[#:tag "contract-utilities"]{Contract Utilities} @declare-exporting-ctc[racket/contract/base] @defproc[(contract? [v any/c]) boolean?]{ Returns @racket[#t] if its argument is a @tech{contract} (i.e., constructed with one of the combinators described in this section or a value that can be used as a contract) and @racket[#f] otherwise.} @defproc[(chaperone-contract? [v any/c]) boolean?]{ Returns @racket[#t] if its argument is a @tech{chaperone contract}, i.e., one that guarantees that it returns a value which passes @racket[chaperone-of?] when compared to the original, uncontracted value.} @defproc[(impersonator-contract? [v any/c]) boolean?]{ Returns @racket[#t] if its argument is an @tech{impersonator contract}, i.e., a @tech{contract} that is neither a @tech{chaperone contract} nor a @tech{flat contract}.} @defproc[(flat-contract? [v any/c]) boolean?]{ Returns @racket[#t] when its argument is a contract that can be checked immediately (unlike, say, a function contract). For example, @racket[flat-contract] constructs @tech{flat contracts} from predicates, and symbols, booleans, numbers, and other ordinary Racket values (that are defined as @tech{contracts}) are also @tech{flat contracts}.} @defproc[(list-contract? [v any/c]) boolean?]{ Recognizes certain @racket[contract?] values that accept @racket[list?]s. A list contract is one that insists that its argument is a @racket[list?], meaning that the value cannot be cyclic and must either be the empty list or a pair constructed with @racket[cons] and another list. @history[#:added "6.0.1.13"] } @defproc[(contract-name [c contract?]) any/c]{ Produces the name used to describe the contract in error messages. } @defproc[(value-contract [v has-contract?]) (or/c contract? #f)]{ Returns the contract attached to @racket[v], if recorded. Otherwise it returns @racket[#f]. To support @racket[value-contract] and @racket[value-contract] in your own contract combinators, use @racket[prop:contracted] or @racket[impersonator-prop:contracted]. } @defproc[(has-contract? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is a value that has a recorded contract attached to it. } @defproc[(value-blame [v has-blame?]) (or/c blame? #f)]{ Returns the @|blame-object| for the contract attached to @racket[v], if recorded. Otherwise it returns @racket[#f]. To support @racket[value-contract] and @racket[value-blame] in your own contract combinators, use @racket[prop:blame] or @racket[impersonator-prop:blame]. @history[#:added "6.0.1.12"] } @defproc[(has-blame? [v any/c]) boolean?]{ Returns @racket[#t] if @racket[v] is a value that has a contract with blame information attached to it. @history[#:added "6.0.1.12"] } @defproc[(contract-late-neg-projection [c contract?]) (-> blame? (-> any/c (or/c #f any/c) any/c))]{ Produces the projection defining a contract's behavior. The first argument, @racket[blame?] object encapsulates information about the contract checking, mostly used to create a meaningful error message if a contract violation is detected. The resulting function's first argument is the value that should have the contract and its second argument is a missing party for the @tech{blame object}, to be passed to @racket[raise-contract-error]. If possible, use this function instead of @racket[contract-val-first-projection] or @racket[contract-projection]. } @defproc[(contract-projection [c contract?]) (-> blame? (-> any/c any/c))]{ Produces a projection defining a contract's behavior. This projection is a curried function of two arguments: the first application accepts a blame object, and the second accepts a value to protect with the contract. If possible, use @racket[contract-late-neg-projection] instead. } @defproc[(contract-val-first-projection [c contract?]) (-> blame? (-> any/c (-> any/c any/c)))]{ Produces a projection defining a contract's behavior. This projection is similar to the result of @racket[contract-late-neg-projection] except with an extra layer of currying. If possible, use @racket[contract-late-neg-projection] instead. } @defproc[(make-none/c [sexp-name any/c]) contract?]{ Makes a contract that accepts no values, and reports the name @racket[sexp-name] when signaling a contract violation.} @defform*[[(recursive-contract contract-expr recursive-contract-option ...) (recursive-contract contract-expr type recursive-contract-option ...)] #:grammar ([recursive-contract-option #:list-contract? #:extra-delay] [type #:impersonator #:chaperone #:flat])]{ Delays the evaluation of its argument until the contract is checked, making recursive contracts possible. If @racket[type] is not given, an impersonator contract is created. If the @racket[recursive-contract-option] @racket[#:list-contract?] is given, then the result is a @racket[list-contract?] and the @racket[contract-expr] must evaluate to a @racket[list-contract?]. If the @racket[recursive-contract-option] @racket[#:extra-delay] is given, then the @racket[contract-expr] expression is evaluated only when the first value to be checked against the contract is supplied to the contract. Without it, the @racket[contract-expr] is evaluated earlier. This option is supported only when @racket[type] is @racket[#:flat]. @examples[#:eval (contract-eval) (define even-length-list/c (or/c null? (cons/c any/c (cons/c any/c (recursive-contract even-length-list/c #:flat))))) (even-length-list/c '(A B)) (even-length-list/c '(1 2 3)) ] @history[#:changed "6.0.1.13" @list{Added the @racket[#:list-contract?] option.} #:changed "6.7.0.3" @list{Added the @racket[#:extra-delay] option.}] } @defform/subs[(opt/c contract-expr maybe-name) ([maybe-name (code:line) (code:line #:error-name id)])]{ This optimizes its argument contract expression by traversing its syntax and, for known contract combinators, fuses them into a single contract combinator that avoids as much allocation overhead as possible. The result is a contract that should behave identically to its argument, except faster. If the @racket[#:error-name] argument is present, and @racket[contract-expr] evaluates to a non-contract expression, then @racket[opt/c] raises an error using @racket[id] as the name of the primitive, instead of using the name @racket[opt/c]. @examples[#:eval (contract-eval) #:once (eval:error (define/contract (f x) (opt/c '(not-a-contract)) x)) (eval:error (define/contract (f x) (opt/c '(not-a-contract) #:error-name define/contract) x))] } @defform[(define-opt/c (id id ...) expr)]{ This defines a recursive contract and simultaneously optimizes it. As long as the defined function terminates, @racket[define-opt/c] behaves just as if the @racket[-opt/c] were not present, defining a function on contracts (except that the body expression must return a contract). But, it also optimizes that contract definition, avoiding extra allocation, much like @racket[opt/c] does. For example, @racketblock[ (define-contract-struct bt (val left right)) (define-opt/c (bst-between/c lo hi) (or/c null? (bt/c [val (real-in lo hi)] [left (val) (bst-between/c lo val)] [right (val) (bst-between/c val hi)]))) (define bst/c (bst-between/c -inf.0 +inf.0)) ] defines the @racket[bst/c] contract that checks the binary search tree invariant. Removing the @racket[-opt/c] also makes a binary search tree contract, but one that is (approximately) 20 times slower. Note that in some cases, a call to a function defined by @racket[define-opt/c] may terminate, even if the corresponding @racket[define]-based function would not terminate. This is a shortcoming in @racket[define-opt/c] that we hope to understand and fix at some point, but have no concrete plans currently. } @defthing[contract-continuation-mark-key continuation-mark-key?]{ Key used by continuation marks that are present during contract checking. The value of these marks are the @|blame-objects| that correspond to the contract currently being checked. @history[#:added "6.4.0.4"] } @defproc[(contract-custom-write-property-proc [c contract?] [p output-port?] [mode (or/c #f #t 0 1)]) void?]{ Prints @racket[c] to @racket[p] using the contract's name. @history[#:added "6.1.1.5"] } @defproc[(rename-contract [contract contract?] [name any/c]) contract?]{ Produces a contract that acts like @racket[contract] but with the name @racket[name]. The resulting contract is a @tech{flat contract} if @racket[contract] is a @tech{flat contract}. @history[#:added "6.3"] } @defform[(contract-first-order-okay-to-give-up?)]{ This form returns a boolean that controls the result of first-order contact checks. More specifically, if it returns @racket[#t], then a first-order check may return @racket[#t] even when the entire first-order checks have not happened. If it returns @racket[#f] then the first order checks must continue until a definitive answer is returned. This will only return @racket[#t] in the dynamic extent of @racket[or/c] or @racket[first-or/c]'s checking to determine which branch to use. @history[#:added "6.3.0.9"] } @defform[(contract-first-order-try-less-hard e)]{ Encourages first-order checks that happen in the dynamic-extent of @racket[e] to be more likely to give up. That is, makes it more likely that @racket[contract-first-order-okay-to-give-up?] might return @racket[#t]. If not in the dynamic-extent of @racket[or/c]'s or @racket[first-or/c]'s checking to determine the branch, then this form has no effect. @history[#:added "6.3.0.9"] } @defproc[(if/c [predicate (-> any/c any/c)] [then-contract contract?] [else-contract contract?]) contract?]{ Produces a contract that, when applied to a value, first tests the value with @racket[predicate]; if @racket[predicate] returns true, the @racket[then-contract] is applied; otherwise, the @racket[else-contract] is applied. The resulting contract is a @tech{flat contract} if both @racket[then-contract] and @racket[else-contract] are @tech{flat contracts}. For example, the following contract enforces that if a value is a procedure, it is a thunk; otherwise it can be any (non-procedure) value: @racketblock[(if/c procedure? (-> any) any/c)] Note that the following contract is @bold{not} equivalent: @racketblock[(or/c (-> any) any/c) (code:comment "wrong!")] The last contract is the same as @racket[any/c] because @racket[or/c] tries @tech{flat contracts} before higher-order contracts. @history[#:added "6.3"] } @defthing[failure-result/c contract?]{ A contract that describes the failure result arguments of procedures such as @racket[hash-ref]. Equivalent to @racket[(if/c procedure? (-> any) any/c)]. @history[#:added "6.3"] } @defproc[(get/build-val-first-projection [c contract?]) (-> blame? (-> any/c (-> any/c any/c)))]{ Returns the @racket[_val-first] projection for @racket[c]. See @racket[make-contract] for more details. @history[#:added "6.1.1.5"] } @defproc[(get/build-late-neg-projection [c contract?]) (-> blame? (-> any/c any/c any/c))]{ Returns the @racket[_late-neg] projection for @racket[c]. If @racket[c] does not have a @racket[_late-neg] contract, then this function uses the original projection for it and logs a warning to the @racket['racket/contract] logger. See @racket[make-contract] for more details. @history[#:added "6.2.900.11"] } @section{@racketmodname[racket/contract/base]} @defmodule[racket/contract/base] The @racketmodname[racket/contract/base] module provides a subset of the exports of @racketmodname[racket/contract] module. In particular, it contains everything in the @itemize[@item{@secref["data-structure-contracts"]} @item{@secref["function-contracts"]} @item{@secref["attaching-contracts-to-values"] and} @item{@secref["contract-utilities"] sections.}] Unfortunately, using @racketmodname[racket/contract/base] does not yield a significantly smaller memory footprint than @racketmodname[racket/contract], but it can still be useful to add contracts to libraries that @racketmodname[racket/contract] uses to implement some of the more sophisticated parts of the contract system. @; ------------------------------------------------------------------------ @section[#:tag "collapsible"]{Collapsible Contracts} @defmodule*/no-declare[(racket/contract/collapsible)] @declare-exporting-ctc[racket/contract/collapsible] @history[#:added "7.1.0.10"] @deftech{Collapsible contracts} are an optimization in the contract system designed to avoid a particular pathological build up of contract wrappers on higher-order values. The @racket[vectorof], @racket[vector/c], and @racket[->] contract combinators support collapsing for vector contracts and function contracts for functions returning a single value. Intuitively, a collapsible contract is a tree structure. The @racketlink[collapsible-ho/c]{tree nodes} represent higher-order contracts (e.g., @racket[->]) and the @racketlink[collapsible-leaf/c]{tree leaves} represent sequences of flat contracts. Two trees can collapse into one tree via the @racket[merge] procedure, which removes unnecessary flat contracts from the leaves. For more information on the motivation and design of collapsible contracts, see @cite["Feltey18"]. For the theoretical foundations, see @cite["Greenberg15"]. @bold{Warning}: the features described in this section are experimental and may not be sufficient to implement new collapsible contracts. Implementing new collapsible contracts requires the use of unsafe chaperones and impersonators which are only supported for vector and procedure values. This documentation exists primarily to allow future maintenance of the @racket[racket/contract/collapsible] library. @bold{End Warning} @defproc[(get/build-collapsible-late-neg-projection [c contract?]) (-> blame? (values (-> any/c any/c any/c) collapsible-contract?))]{ Returns the @racket[_collapsible-late-neg] projection for @racket[c]. If @racket[c] does not have a @racket[_collapsible-late-neg] projection, then this function uses the original projection for it and constructs a leaf as its collapsible representation. } @defthing[collapsible-contract-continuation-mark-key continuation-mark-key?]{ Key used by continuation marks that are present during collapsible contract checking. The value of these marks are @racket[#t] if the current contract is collapsible. } @defform[(with-collapsible-contract-continuation-mark body ...)]{ Inserts a continuation mark that informs the contract profiler that the current contract is collapsible. } @defthing[prop:collapsible-contract struct-type-property?]{ Structures implementing this property are usable as collapsible contracts. The value associated with this property should be constructed by calling @racket[build-collapsible-contract-property]. } @defproc[(collapsible-contract? [v any/c]) boolean?]{ A predicate recognizing structures with the @racket[prop:collapsible-contract] property.} @defproc[(merge [new-cc collapsible-contract?] [new-neg any/c] [old-cc collapsible-contract?] [old-neg any/c]) collapsible-contract?]{ Combine two collapsible contracts into a single collapsible contract. The @racket[new-neg] and @racket[old-neg] arguments are expected to be blame parties similar to those passed to a @tech{late neg projection}. } @defproc[(collapsible-guard [cc collapsible-contract?] [val any/c] [neg-party any/c]) any/c]{ Similar to a @tech{late neg projection}, this function guards the value @racket[val] with the collapsible contract @racket[cc]. } @defproc[(collapsible-contract-property? [v any/c]) boolean?]{ This predicate indicates that a value can be used as the property for @racket[prop:collapsible-contract]. } @defproc[(build-collapsible-contract-property [#:try-merge try-merge (or/c #f (-> collapsible-contract? any/c collapsible-contract? any/c (or/c #f collapsible-contract?))) #f] [#:collapsible-guard collapsible-guard (-> collapsible-contract? any/c any/c any/c) (λ (cc v neg) (error "internal error: contract does not support `collapsible-guard`" cc))]) collapsible-contract-property?]{ Constructs a @deftech{collapsible contract property} from a merging function and a guard. The @racket[try-merge] argument is similar to @racket[merge], but may return @racket[#f] instead of a collapsible contract and may be specialized to a particular collapsible contract. The @racket[collapsible-guard] argument should be specialized to the particular collapsible contract being implemented. } @defstruct*[collapsible-ho/c ([latest-blame blame?] [missing-party any/c] [latest-ctc contract?])]{ A common parent structure for collapsible contracts for higher-order values. The @racket[latest-blame] field holds the blame object for the most recent contract attached. Similarly, the @racket[missing-party] field holds the latest missing party passed to the contract. The @racket[latest-contract] field stores the most recent contract attached to the value. } @defstruct*[collapsible-leaf/c ([proj-list (listof (-> any/c any/c any/c))] [contract-list (listof contract?)] [blame-list (listof blame?)] [missing-party-list (listof any/c)])]{ A structure representing the leaf nodes of a collapsible contract. The @racket[proj-list] field holds a list of partially applied @tech{late neg projections}. The @racket[contract-list], @racket[blame-list], and @racket[missing-party-list] fields hold a list of contracts, blame objects, and blame missing parties respectively. } @deftogether[(@defthing[impersonator-prop:collapsible impersonator-property?] @defproc[(has-impersonator-prop:collapsible? [v any/c]) boolean?] @defproc[(get-impersonator-prop:collapsible [v any/c]) collapsible-property?])]{ An impersonator property (and its accessors) that should be attached to chaperoned or impersonated values that are guarded with a collapsible contract. } @defstruct*[collapsible-property ([c-c collapsible-contract?] [neg-party any/c] [ref (or/c #f impersonator?)])]{ The parent struct of properties that should be attached to chaperones or impersonators of values protected with a collapsible contract. The @racket[c-c] field stores the collapsible contract that is or will in the future be attached to the the value. The @racket[neg-party] field stores the latest missing blame party passed to the contract on the value. The @racket[ref] field is mutable and stores a reference to the chaperone or impersonator to which this property is attached. This is necessary to determine whether an unknown chaperone has been attached to a value after it has been protected by a collapsible contract. } @defstruct*[(collapsible-count-property collapsible-property) ([count natural-number/c] [prev (or/c collapsible-count-property? any/c)])]{ This property is associated with the @racket[impersonator-prop:collapsible] property before the value completely enters the collapsible mode. These properties keep track of the number of contracts on a value in the @racket[_count] field, and hold a reference to the previous @deftech{count property} in the @racket[prev] field or the original value without a contract. This allows the contract system to traverse the chain of attached contracts and merge them into a single collapsible contract to protect the original value. } @defstruct*[(collapsible-wrapper-property collapsible-property) ([checking-wrapper impersonator?])]{ This property is used when a value is guarded by a collapsible contract. The @racket[checking-wrapper] field holds a chaperone or impersonator that dispatches to the collapsible contract stored in this property to perform any necessary contract checks. When the value receives another contract and merging happens, the checking wrapper will remain the same even though the specific collapsible contract attached to the value may change. } @; ------------------------------------------------------------------------ @section{Legacy Contracts} @defproc[(make-proj-contract [name any/c] [proj (or/c (-> any/c any/c (list/c any/c any/c) contact? (-> any/c any/c)) (-> any/c any/c (list/c any/c any/c) contact? boolean? (-> any/c any/c)))] [first-order (-> any/c boolean?)]) contract?]{ Builds a contract using an old interface. Modulo errors, it is equivalent to: @racketblock[(make-contract #:name name #:first-order first-order #:projection (cond [(procedure-arity-includes? proj 5) (lambda (blame) (proj (blame-positive blame) (blame-negative blame) (list (blame-source blame) (blame-value blame)) (blame-contract blame) (not (blame-swapped? blame))))] [(procedure-arity-includes? proj 4) (lambda (blame) (proj (blame-positive blame) (blame-negative blame) (list (blame-source blame) (blame-value blame)) (blame-contract blame)))]))] } @defproc[(raise-contract-error [val any/c] [src any/c] [pos any/c] [name any/c] [fmt string?] [arg any/c] ...) any/c]{ Calls @racket[raise-blame-error] after building a @racket[blame] struct from the @racket[val], @racket[src], @racket[pos], and @racket[name] arguments. The @racket[fmt] string and following arguments are passed to @racket[format] and used as the string in the error message. } @defproc[(contract-proc [c contract?]) (->* (symbol? symbol? (or/c syntax? (list/c any/c any/c))) (boolean?) (-> any/c any))]{ Constructs an old-style projection from a contract. The resulting function accepts the information that is in a @racket[blame] struct and returns a projection function that checks the contract. } @section{Random generation} @defproc[(contract-random-generate [ctc contract?] [fuel 5 exact-nonnegative-integer?] [fail (or/c #f (-> any) (-> boolean? any)) #f]) any/c]{ Attempts to randomly generate a value which will match the contract. The @racket[_fuel] argument limits how hard the generator tries to generate a value matching the contract and is a rough limit of the size of the resulting value. The generator may fail to generate a value, either because some contracts do not have corresponding generators (for example, not all predicates have generators) or because there is not enough fuel. In either case, the function @racket[fail] is invoked. If @racket[fail] accepts an argument, it is called with @racket[#t] when there is no generator for @racket[ctc] and called with @racket[#f] when there is a generator, but the generator ended up returning @racket[contract-random-generate-fail]. @examples[#:eval (contract-eval) #:once (for/list ([i (in-range 10)]) (contract-random-generate (or/c integer? #f)))] @history[#:changed "6.1.1.5" @list{Allow @racket[fail] to accept a boolean.}] } @defproc[(contract-exercise [#:fuel fuel exact-nonnegative-integer? 10] [#:shuffle? shuffle? any/c #f] [val any/c] ...+) void?]{ Attempts to get the @racket[val]s to break their contracts (if any). Uses @racket[value-contract] to determine if any of the @racket[val]s have a contract and, for those that do, uses information about the contract's shape to poke and prod at the value. For example, if the value is function, it will use the contract to tell it what arguments to supply to the value. The argument @racket[_fuel] determines how hard @racket[contract-exercise] tries to break the values. It controls both the number of exercise iterations and the size of the intermediate values generated during the exercises. The argument @racket[_shuffle?] controls whether @racket[contract-exercise] randomizes the exercise order or not. If @racket[_shuffle?] is not @racket[#f], @racket[contract-exercise] would shuffle the order of the contracts in each exercise iteration. @examples[#:eval (contract-eval) #:once (define/contract (returns-false x) (-> integer? integer?) (code:comment "does not obey its contract") #f) (eval:error (contract-exercise returns-false)) (define/contract (calls-its-argument-with-eleven f) (-> (-> integer? integer?) boolean?) (code:comment "f returns an integer, but") (code:comment "we're supposed to return a boolean") (f 11)) (eval:error (contract-exercise calls-its-argument-with-eleven))] @history[#:changed "7.0.0.18" @elem{Added the @racket[shuffle?] optional argument.}] } @defproc[(contract-random-generate/choose [c contract?] [fuel exact-nonnegative-integer?]) (or/c #f (-> c))]{ This function is like @racket[contract-random-generate], but it is intended to be used with combinators that generate values based on sub-contracts they have. It must be called when @racket[contract-random-generate] (and @racket[contract-exercise]) creates the generators. To be more precise, @racket[contract-random-generate/choose] is available only for the @racket[_generate] and @racket[_exercise] arguments in @racket[build-contract-property], @racket[build-chaperone-contract-property] or @racket[build-flat-contract-property] and only during the dynamic extent of the call to @racket[_generate] (and @racket[_exercise]). That is, after it receives the @racket[_c] and @racket[_fuel] arguments and before it returns the thunk (or the exerciser). @racket[contract-random-generate/choose] will never fail, but it might escape back to an enclosing call or to the original call to @racket[contract-random-generate]. It chooses one of several possible generation strategies, and thus it may not actually use the generator associated with @racket[c], but might instead use a stashed value that matches @racket[c] that it knows about via @racket[contract-random-generate-stash]. @history[#:added "6.1.1.5"] } @defthing[contract-random-generate-fail contract-random-generate-fail?]{ An atomic value that is used to indicate that a generator failed to generate a value. @history[#:added "6.1.1.5"] } @defproc[(contract-random-generate-fail? [v any/c]) boolean?]{ A predicate to recognize @racket[contract-random-generate-fail]. @history[#:added "6.1.1.5"] } @defproc[(contract-random-generate-env? [v any/c]) boolean?]{ Recognizes contract generation environments. @history[#:added "6.1.1.5"] } @defproc[(contract-random-generate-stash [env contract-random-generate-env?] [c contract?] [v c]) void?]{ This should be called with values that the program under test supplies during contract generation. For example, when @racket[(-> (-> integer? integer?) integer?)] is generated, it may call its argument function. That argument function may return an integer and, if so, that integer should be saved by calling @racket[contract-random-generate-stash], so it can be used by other integer generators. @history[#:added "6.1.1.5"] } @defproc[(contract-random-generate-get-current-environment) contract-random-generate-env?]{ Returns the environment currently being for generation. This function can be called only during the dynamic extent of contract generation. It is intended to be grabbed during the construction of a contract generator and then used with @racket[contract-random-generate-stash] while generation is happening. @history[#:added "6.1.1.5"] }