Contract Miscellanea
(require contract-etc) | package: contract-etc-lib |
1 Combinators
This library is experimental; compatibility may not be maintained.
procedure
(dynamic->d make-contract) → contract?
make-contract :
(-> (unconstrained-domain-> contract?) contract?)
> (define increasing/c (dynamic->d (λ (x) (-> integer? (>/c x))))) > (define/contract add1* increasing/c add1) > (add1* 42) 43
> (define/contract values* increasing/c values) > (values* 42) values*: broke its own contract
promised: a number strictly greater than 42
produced: 42
in: the range of
dynamic->d
contract from: (definition values*)
blaming: (definition values*)
(assuming the contract is correct)
at: eval:4:0
procedure
(self/c make-contract [ #:chaperone? chaperone?]) → contract? make-contract : (-> any/c contract?) chaperone? : boolean? = #f
> (define cdr-returns-car/c (self/c (λ (p) (match-define (cons x f) p) (cons/c any/c (-> x))))) > (define/contract good-self cdr-returns-car/c (cons 1 (const 1))) > ((cdr good-self)) 1
> 1 1
> (define/contract bad-self cdr-returns-car/c (cons 1 (const 2))) > ((cdr bad-self)) bad-self: broke its own contract
promised: 1
produced: 2
in: the range of
the cdr of
self/c
contract from: (definition bad-self)
blaming: (definition bad-self)
(assuming the contract is correct)
at: eval:10:0
procedure
(elementof/c contract get-element) → flat-contract?
contract : contract? get-element : (-> any/c any/c)
> (define car-is-int? (elementof/c integer? car)) > (define/contract good-pair car-is-int? (cons 1 2)) > (define/contract bad-pair car-is-int? (cons "hi" 2)) bad-pair: broke its own contract
promised: integer?
produced: "hi"
in: (elementof/c integer?)
contract from: (definition bad-pair)
blaming: (definition bad-pair)
(assuming the contract is correct)
at: eval:14:0
> (define/contract might-count (case->i (-> string? integer?) (->i ([s string?] [n (s) (=/c (string-length s))]) [res integer?])) (lambda (s . args) (string-length s))) > (might-count "hi") 2
> (might-count "hi" 2) 2
> (might-count "hi" 3) might-count: contract violation
expected: (=/c 2)
given: 3
in: the n argument of
(case->i
((-> string? integer?)
(->i
((s string?)
(n (s) (=/c (string-length s))))
(res integer?))))
contract from: (definition might-count)
blaming: top-level
(assuming the contract is correct)
at: eval:15:0
syntax
(apply/c [contract-expr to-protect-expr maybe-swap] ...+)
maybe-swap =
| #:swap
syntax
(return/c [contract-expr to-protect-expr maybe-swap] ...+)
maybe-swap =
| #:swap
> (define (apply-at-most-once/c) (define count 0) (define (incr n) (set! count (+ count n)) (<= count 1)) (apply/c [incr 1])) > (define/contract f (apply-at-most-once/c) void) > (f) > (f) f: contract violation
expected: incr
given: 1
in: apply/c
contract from: (definition f)
blaming: top-level
(assuming the contract is correct)
at: eval:20:0
procedure
(class-object/c class-contract object-contract) → contract? class-contract : contract? object-contract : contract?
> (define cat%/c (class-object/c (class/c [meow (->m integer? string?)]) (object/c [meow (->m positive? string?)])))
> (define/contract cat% cat%/c (class object% (define/public (meow n) (string-join (map (const "meow") (range n)))) (super-new))) > (define leo (new cat%)) > (send leo meow 1/2) meow: contract violation
expected: integer?
given: 1/2
in: the 1st argument of
the meow method in
the class contract of
(class-object/c
(class/c (meow (->m integer? string?)))
(object/c (meow (->m positive? string?))))
contract from: (definition cat%)
contract on: cat%
blaming: top-level
(assuming the contract is correct)
at: eval:24:0
> (send leo meow -2) meow: contract violation
expected: positive?
given: -2
in: the 1st argument of
the meow method in
the object contract of
(class-object/c
(class/c (meow (->m integer? string?)))
(object/c (meow (->m positive? string?))))
contract from: (definition cat%)
contract on: cat%
blaming: top-level
(assuming the contract is correct)
at: eval:24:0
> (send leo meow 4) "meow meow meow meow"
procedure
(dependent-class-object/c class-contract make-object-contract) → contract? class-contract : contract? make-object-contract : procedure?
> (define dog%/c (dependent-class-object/c (class/c [bark (->m string? string?)]) (λ (#:sound sound) (object/c [bark (->m string? (λ (s) (equal? s sound)))]))))
> (define/contract dog% dog%/c (class object% (init sound) (define/public (bark x) x) (super-new))) > (define spot (new dog% [sound "woof"])) > (send spot bark "meow") bark: broke its own contract
promised: ???
produced: "meow"
in: the range of
the bark method in
the object contract of
(dependent-class-object/c
(class/c (bark (->m string? string?)))
eval:29:0)
contract from: (definition dog%)
contract on: dog%
blaming: (definition dog%)
(assuming the contract is correct)
at: eval:30:0
> (send spot bark "woof") "woof"
procedure
(dependent-classof/c make-object-contract) → contract?
make-object-contract : procedure?
procedure
(channel*/c get-contract put-contract) → contract?
get-contract : contract? put-contract : contract?
> (define/contract x (channel*/c integer? number?) (make-channel)) > (thread (λ () (channel-put x 11.5))) #<thread>
> (channel-get x) x: broke its own contract
promised: integer?
produced: 11.5
in: the channel get of
(channel*/c integer? number?)
contract from: (definition x)
blaming: (definition x)
(assuming the contract is correct)
at: eval:34:0
procedure
(async-channel*/c get-contract put-contract) → contract? get-contract : contract? put-contract : contract?
2 provide Forms
syntax
(exercise-out id ...)
> (module inner racket (require contract-etc racket/contract/option) (provide (exercise-out foo) (rename-out [foo unchecked-foo])) (define/contract (foo) (option/c (-> integer?)) "nan")) > (require 'inner) > (unchecked-foo) "nan"
> (foo) foo: broke its own contract
promised: integer?
produced: "nan"
in: the range of
the option of
(option/c (-> integer?))
contract from: (function foo)
blaming: (function foo)
(assuming the contract is correct)
at: eval:37:0
syntax
(waive-out id ...)
3 Annotations
(require contract-etc/annotate) | package: contract-etc-lib |
Typically, programmers will only attach contracts at module or library boundaries with contract-out and not use contracts at the definition level with define/contract. This is because fine-grained contract boundaries cause major performance problems due to the overhead of repeated checking.
Contract annotations provide a convenient means of enabling and disabling internal contract checks as needed. For example, you may decide that for local testing you want to disable internal contract checks, but enable them during continuous integration testing.
syntax
(: id contract-expr)
Where, and whether, that option is enabled depends on the environment variables present at run time.
If CONTRACT_EXERCISE is set, then the option is enabled by default.
If CONTRACT_EXERCISE_TEST is set, then the option is enabled by default only in the test submodule of the current file.
If neither are set, then the option is disabled by default.
> (: sub2 (-> number? number?)) > (define (sub2) 42) sub2: broke its own contract
promised: a procedure that accepts 1 non-keyword argument
produced: #<procedure:sub2>
sub2 accepts: 0 arguments
in: (option/c
(-> number? number?)
#:tester
#<procedure:...arrow-val-first.rkt:1639:0>)
contract from: (function sub2)
blaming: (function sub2)
(assuming the contract is correct)
at: eval:42:0
> (: add2 (-> integer? integer?))
> (define (add2 x) (+ x 2)) > (add2 1.5) 3.5
> ((exercise-option add2) 1.5) add2: contract violation
expected: integer?
given: 1.5
in: the 1st argument of
the option of
(option/c
(-> integer? integer?)
#:tester
#<procedure:...arrow-val-first.rkt:1639:0>)
contract from: (function add2)
blaming: top-level
(assuming the contract is correct)
at: eval:44:0