added list-contract?

and specialized a bunch of list-related contracts to track list?-ness,
notably recursive-contract now accepts a #:list-contract? argument
that means that it insists that values it accepts be list? (and
thus not cyclic)

related to PR 14559
This commit is contained in:
Robby Findler 2014-07-03 22:15:37 -05:00
parent 0db4df1d33
commit f49dd363fa
8 changed files with 323 additions and 68 deletions

View File

@ -187,6 +187,9 @@ For example, this contract
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[(and/c [contract contract?] ...) contract?]{
@ -369,14 +372,14 @@ Returns the same contract as @racket[(box/c c #:immutable #t)]. This form exists
reasons of backwards compatibility.}
@defproc[(listof [c contract?]) contract?]{
@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.}
@defproc[(non-empty-listof [c contract?]) contract?]{
@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
@ -387,10 +390,16 @@ a value, the result is not necessarily @racket[eq?] to the input.}
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.}
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?].
@history[#:changed "6.0.1.13" @list{Added the @racket[list-contract?] propagating behavior.}]
}
@defproc[(list/c [c contract?] ...) contract?]{
@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
@ -1858,7 +1867,8 @@ the contract library primitives below.
name x))))]
[#:stronger stronger
(or/c #f (-> contract? contract? boolean?))
#f])
#f]
[#:list-contract is-list-contract? boolean? #f])
contract?]
@defproc[(make-chaperone-contract
[#:name name any/c 'anonymous-chaperone-contract]
@ -1878,7 +1888,8 @@ the contract library primitives below.
name x))))]
[#:stronger stronger
(or/c #f (-> contract? contract? boolean?))
#f])
#f]
[#:list-contract is-list-contract? boolean? #f])
chaperone-contract?]
@defproc[(make-flat-contract
[#:name name any/c 'anonymous-flat-contract]
@ -1898,7 +1909,8 @@ the contract library primitives below.
name x))))]
[#:stronger stronger
(or/c #f (-> contract? contract? boolean?))
#f])
#f]
[#:list-contract is-list-contract? boolean? #f])
flat-contract?]
)]{
@ -1946,6 +1958,9 @@ The @racket[stronger] argument is used to implement @racket[contract-stronger?].
first argument is always the contract itself and the second argument is whatever
was passed as the second argument to @racket[contract-stronger?].
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.
@defexamples[#:eval (contract-eval)
(define int/c
(make-flat-contract #:name 'int/c #:first-order integer?))
@ -1977,6 +1992,7 @@ was passed as the second argument to @racket[contract-stronger?].
(halve 1)
]
@history[#:changed "6.0.1.13" @list{Added the @racket[#:list-contract?] argument.}]
}
@defproc[(build-compound-type-name [c/s any/c] ...) any]{
@ -2306,7 +2322,8 @@ is expected to be the blame record for the contract on the value).
(-> (and/c positive? real?)
(values
(-> c void?)
(listof contract?)))]))])
(listof contract?)))]))]
[#:list-contract? is-list-contract? (-> contract? boolean?) (λ (c) #f)])
flat-contract-property?]
@defproc[(build-chaperone-contract-property
[#:name
@ -2353,7 +2370,8 @@ is expected to be the blame record for the contract on the value).
(-> (and/c positive? real?)
(values
(-> c void?)
(listof contract?)))]))])
(listof contract?)))]))]
[#:list-contract? is-list-contract? (-> contract? boolean?) (λ (c) #f)])
chaperone-contract-property?]
@defproc[(build-contract-property
[#:name
@ -2400,7 +2418,8 @@ is expected to be the blame record for the contract on the value).
(-> (and/c positive? real?)
(values
(-> c void?)
(listof contract?)))]))])
(listof contract?)))]))]
[#:list-contract? is-list-contract? (-> contract? boolean?) (λ (c) #f)])
contract-property?])]{
@italic{The precise details of the
@ -2423,10 +2442,12 @@ produces a blame-tracking projection defining the behavior of the contract;
(passed in the first argument) is stronger than some other contract (passed
in the second argument); @racket[generate], which returns a thunk
that generates random values matching the contract or @racket[#f], indicating
that random generation for this contract isn't supported; and @racket[exercise],
that random generation for this contract isn't supported; @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.
whose values will be generated by this process; and @racket[is-flat-contract?],
which is used by @racket[flat-contract?] to determine if this contract
accepts only @racket[list?]s.
These accessors are passed as (optional) keyword arguments to
@racket[build-contract-property], and are applied to instances of the
@ -2448,6 +2469,7 @@ 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].
@history[#:changed "6.0.1.13" @list{Added the @racket[#:list-contract?] argument.}]
}
@deftogether[(
@ -2628,6 +2650,17 @@ symbols, booleans, numbers, and other ordinary Racket values
(that are defined as @tech{contracts}) are also
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.
}
@ -2670,13 +2703,22 @@ 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 contract-expr type)]]{
(recursive-contract contract-expr #:list-contract?)
(recursive-contract contract-expr type)
(recursive-contract contract-expr type #:list-contract?)]]{
Delays the evaluation of its argument until the contract is checked,
making recursive contracts possible. If @racket[type] is given, it
describes the expected type of contract and must be one of the keywords
@racket[#:impersonator], @racket[#:chaperone], or @racket[#:flat]. If
@racket[type] is not given, an impersonator contract is created.}
@racket[type] is not given, an impersonator contract is created.
If @racket[#:list-contract?] is returned, then the result is a
@racket[list-contract?] and the @racket[contract-expr] must evaluate
to a @racket[list-contract?].
@history[#:changed "6.0.1.13" @list{Added the @racket[#:list-contract?] argument.}]
}
@defform/subs[(opt/c contract-expr maybe-name)

View File

@ -0,0 +1,114 @@
#lang racket/base
(require "test-util.rkt")
(parameterize ([current-contract-namespace (make-basic-contract-namespace 'racket/list)])
(test/spec-passed/result
'list-contract-1
'(list-contract? 1)
#f)
(test/spec-passed/result
'list-contract-2
'(list-contract? (λ (a b c) a)) ;; somethign that's not coerceable to a contract
#f)
(test/spec-passed/result
'list-contract-3
'(list-contract? '())
#t)
(test/spec-passed/result
'list-contract-4
'(list-contract? null?)
#t)
(test/spec-passed/result
'list-contract-5
'(list-contract? empty?)
#t)
(test/spec-passed/result
'list-contract-6
'(list-contract? boolean?)
#f)
(test/spec-passed/result
'list-contract-7
'(list-contract? any/c)
#f)
(test/spec-passed/result
'list-contract-8
'(list-contract? (cons/c 1 empty?))
#t)
(test/spec-passed/result
'list-contract-9
'(list-contract? (cons/c 1 2))
#f)
(test/spec-passed/result
'list-contract-10
'(list-contract? (listof any/c))
#t)
(test/spec-passed/result
'list-contract-11
'(list-contract? (non-empty-listof any/c))
#t)
(test/spec-passed/result
'list-contract-12
'(list-contract? (list/c 1 2 3))
#t)
(test/spec-passed/result
'list-contract-13
'(list-contract? (or/c (cons/c 1 empty?) empty?))
#t)
(test/spec-passed/result
'list-contract-14
'(list-contract? (or/c (cons/c (-> integer? integer?) empty?)
empty?))
#t)
(test/spec-passed/result
'list-contract-15
'(list-contract? (or/c (cons/c (-> integer? integer?) empty?)
(cons/c (-> integer? integer? integer?) empty?)
empty?))
#t)
(test/spec-passed/result
'list-contract-16
'(list-contract?
(letrec ([c (recursive-contract (or/c (cons/c 1 c) empty?))])
c))
#f)
(test/spec-passed/result
'list-contract-17
'(list-contract?
(letrec ([c (recursive-contract (or/c (cons/c 1 c) empty?) #:list-contract?)])
c))
#t)
(test/pos-blame
'test-contract-18
'(contract (letrec ([c (recursive-contract (or/c (cons/c any/c c) empty?)
#:list-contract?)])
c)
(read (open-input-string "#1=(1 . #1#)"))
'pos 'neg))
(contract-error-test
'test-contract-19
'(contract (recursive-contract 1 #:list-contract?)
1
'pos 'neg)
(λ (x)
(and (exn:fail? x)
(regexp-match #rx"list-contract[?]" (exn-message x))))))

View File

@ -67,6 +67,7 @@
has-blame?
value-blame
contract-continuation-mark-key
list-contract?
;; from private/case-arrow.rkt
case->)

View File

@ -103,7 +103,7 @@
'#,(build-source-location-vector #'ctc))))]))
(define-syntax (-recursive-contract stx)
(define (do-recursive-contract arg type name)
(define (do-recursive-contract arg type name list-contract?)
(define local-name (syntax-local-infer-name stx))
(define maker
(case (syntax-e type)
@ -115,13 +115,18 @@
"type must be one of #:impersonator, #:chaperone, or #:flat"
stx
type)]))
#`(#,maker '#,name (λ () #,arg) '#,local-name))
#`(#,maker '#,name (λ () #,arg) '#,local-name #,list-contract?))
(syntax-case stx ()
[(_ arg type #:list-contract?)
(keyword? (syntax-e #'type))
(do-recursive-contract #'arg #'type #'(recursive-contract arg type) #t)]
[(_ arg #:list-contract?)
(do-recursive-contract #'arg #'#:impersonator #'(recursive-contract arg) #t)]
[(_ arg type)
(keyword? (syntax-e #'type))
(do-recursive-contract #'arg #'type #'(recursive-contract arg type))]
(do-recursive-contract #'arg #'type #'(recursive-contract arg type) #f)]
[(_ arg)
(do-recursive-contract #'arg #'#:impersonator #'(recursive-contract arg))]))
(do-recursive-contract #'arg #'#:impersonator #'(recursive-contract arg) #f)]))
(define (force-recursive-contract ctc)
(define current (recursive-contract-ctc ctc))
@ -138,19 +143,37 @@
(coerce-chaperone-contract 'recursive-contract (thunk))]
[(impersonator-recursive-contract? ctc)
(coerce-contract 'recursive-contract (thunk))]))
(when (recursive-contract-list-contract? ctc)
(unless (list-contract? forced-ctc)
(raise-argument-error 'recursive-contract "list-contract?" forced-ctc)))
(set-recursive-contract-ctc! ctc forced-ctc)
(set-recursive-contract-name! ctc (append `(recursive-contract ,(contract-name forced-ctc))
(cddr old-name)))
forced-ctc]
[else current]))
(define ((recursive-contract-projection ctc) blame)
(define r-ctc (force-recursive-contract ctc))
(define f (contract-projection r-ctc))
(define blame-known (blame-add-context blame #f))
(λ (val)
((f blame-known) val)))
(define (recursive-contract-projection ctc)
(cond
[(recursive-contract-list-contract? ctc)
(λ (blame)
(define r-ctc (force-recursive-contract ctc))
(define f (contract-projection r-ctc))
(define blame-known (blame-add-context blame #f))
(λ (val)
(unless (list? val)
(raise-blame-error blame-known
val
'(expected: "list?" given: "~e")
val))
((f blame-known) val)))]
[else
(λ (blame)
(define r-ctc (force-recursive-contract ctc))
(define f (contract-projection r-ctc))
(define blame-known (blame-add-context blame #f))
(λ (val)
((f blame-known) val)))]))
(define (recursive-contract-stronger this that)
(and (recursive-contract? that)
(procedure-closure-contents-eq? (recursive-contract-thunk this)
@ -160,7 +183,7 @@
(contract-first-order-passes? (force-recursive-contract ctc)
val))
(struct recursive-contract ([name #:mutable] thunk [ctc #:mutable]))
(struct recursive-contract ([name #:mutable] thunk [ctc #:mutable] list-contract?))
(struct flat-recursive-contract recursive-contract ()
#:property prop:custom-write custom-write-property-proc
@ -169,7 +192,8 @@
#:name recursive-contract-name
#:first-order recursive-contract-first-order
#:projection recursive-contract-projection
#:stronger recursive-contract-stronger))
#:stronger recursive-contract-stronger
#:list-contract? recursive-contract-list-contract?))
(struct chaperone-recursive-contract recursive-contract ()
#:property prop:custom-write custom-write-property-proc
#:property prop:chaperone-contract
@ -177,7 +201,8 @@
#:name recursive-contract-name
#:first-order recursive-contract-first-order
#:projection recursive-contract-projection
#:stronger recursive-contract-stronger))
#:stronger recursive-contract-stronger
#:list-contract? recursive-contract-list-contract?))
(struct impersonator-recursive-contract recursive-contract ()
#:property prop:custom-write custom-write-property-proc
#:property prop:contract
@ -185,4 +210,5 @@
#:name recursive-contract-name
#:first-order recursive-contract-first-order
#:projection recursive-contract-projection
#:stronger recursive-contract-stronger))
#:stronger recursive-contract-stronger
#:list-contract? recursive-contract-list-contract?))

View File

@ -6,6 +6,7 @@
"rand.rkt"
"generate-base.rkt"
racket/pretty
racket/list
(for-syntax racket/base
"helpers.rkt"))
@ -20,7 +21,8 @@
build-compound-type-name
contract-stronger?
list-contract?
contract-first-order
contract-first-order-passes?
@ -123,6 +125,10 @@
(coerce-contract 'contract-first-order-passes? c))
v))
(define (list-contract? raw-c)
(define c (coerce-contract/f raw-c))
(and c (contract-struct-list-contract? c)))
;; contract-stronger? : contract contract -> boolean
;; indicates if one contract is stronger (ie, likes fewer values) than another
;; this is not a total order.
@ -207,6 +213,7 @@
x
#f
(memq x the-known-good-contracts))]
[(null? x) (make-eq-contract x)]
[(or (symbol? x) (boolean? x) (char? x) (null? x) (keyword? x)) (make-eq-contract x)]
[(or (bytes? x) (string? x)) (make-equal-contract x)]
[(number? x) (make-=-contract x)]
@ -356,7 +363,8 @@
(eq? this-val (eq-contract-val that)))
(and (predicate-contract? that)
(predicate-contract-sane? that)
((predicate-contract-pred that) this-val))))))
((predicate-contract-pred that) this-val))))
#:list-contract? (λ (c) (null? (eq-contract-val c)))))
(define-struct equal-contract (val)
#:property prop:custom-write custom-write-property-proc
@ -451,7 +459,9 @@
(predicate-contract-name ctc)))
(λ (fuel)
(and built-in-generator
(λ () (built-in-generator fuel))))])))))
(λ () (built-in-generator fuel))))])))
#:list-contract? (λ (ctc) (or (equal? (predicate-contract-pred ctc) null?)
(equal? (predicate-contract-pred ctc) empty?)))))
(define (check-flat-named-contract predicate) (coerce-flat-contract 'flat-named-contract predicate))
(define (check-flat-contract predicate) (coerce-flat-contract 'flat-contract predicate))

View File

@ -466,7 +466,8 @@
#:projection (listof-*-ho-check (λ (p v) (for-each p v) v))
#:val-first-projection (listof-*-val-first-flat-proj predicate? ctc)
#:generate (generate ctc)
#:exercise (exercise ctc))]
#:exercise (exercise ctc)
#:list-contract? #t)]
[(chaperone-contract? ctc)
(make-chaperone-contract
#:name ctc-name
@ -474,14 +475,16 @@
#:projection (listof-*-ho-check (λ (p v) (map p v)))
#:val-first-projection (listof-*-val-first-ho-proj predicate? ctc)
#:generate (generate ctc)
#:exercise (exercise ctc))]
#:exercise (exercise ctc)
#:list-contract? #t)]
[else
(make-contract
#:name ctc-name
#:first-order fo-check
#:val-first-projection (listof-*-val-first-ho-proj predicate? ctc)
#:projection (listof-*-ho-check (λ (p v) (map p v)))
#:exercise (exercise ctc))])))
#:exercise (exercise ctc)
#:list-contract? #t)])))
(define (listof-*-val-first-flat-proj predicate? ctc)
(define vf-proj (get/build-val-first-projection ctc))
@ -593,6 +596,9 @@
cdr-gen
(λ () (cons (car-gen) (cdr-gen))))))
(define (cons/c-list-contract? c)
(list-contract? (the-cons/c-tl-ctc c)))
(define-struct the-cons/c (hd-ctc tl-ctc))
(define-struct (flat-cons/c the-cons/c) ()
#:property prop:custom-write custom-write-property-proc
@ -603,7 +609,8 @@
#:name cons/c-name
#:first-order cons/c-first-order
#:stronger cons/c-stronger?
#:generate cons/c-generate))
#:generate cons/c-generate
#:list-contract? cons/c-list-contract?))
(define-struct (chaperone-cons/c the-cons/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:chaperone-contract
@ -614,7 +621,8 @@
#:name cons/c-name
#:first-order cons/c-first-order
#:stronger cons/c-stronger?
#:generate cons/c-generate)))
#:generate cons/c-generate
#:list-contract? cons/c-list-contract?)))
(define-struct (impersonator-cons/c the-cons/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:contract
@ -624,7 +632,8 @@
#:name cons/c-name
#:first-order cons/c-first-order
#:stronger cons/c-stronger?
#:generate cons/c-generate))
#:generate cons/c-generate
#:list-contract? cons/c-list-contract?))
(define/subexpression-pos-prop (cons/c a b)
(define ctc-car (coerce-contract 'cons/c a))
@ -748,7 +757,8 @@
(((contract-projection arg/c)
(add-list-context blame i))
v))
x))))))
x))))
#:list-contract? (λ (c) #t)))
(define (list/c-chaperone/other-projection c)
(define args (map contract-projection (generic-list/c-args c)))
@ -830,7 +840,8 @@
#:generate list/c-generate
#:exercise list/c-exercise
#:projection list/c-chaperone/other-projection
#:val-first-projection list/c-chaperone/other-val-first-projection)))
#:val-first-projection list/c-chaperone/other-val-first-projection
#:list-contract? (λ (c) #t))))
(struct higher-order-list/c generic-list/c ()
#:property prop:custom-write custom-write-property-proc
@ -841,7 +852,8 @@
#:generate list/c-generate
#:exercise list/c-exercise
#:projection list/c-chaperone/other-projection
#:val-first-projection list/c-chaperone/other-val-first-projection))
#:val-first-projection list/c-chaperone/other-val-first-projection
#:list-contract? (λ (c) #t)))
(define/subexpression-pos-prop (syntax/c ctc-in)
(let ([ctc (coerce-flat-contract 'syntax/c ctc-in)])

View File

@ -168,6 +168,11 @@
[else (option)])])))]
[else #f]))
(define (single-or/c-list-contract? c)
(and (list-contract? (single-or/c-ho-ctc c))
(for/and ([c (in-list (single-or/c-flat-ctcs c))])
(list-contract? c))))
(define-struct single-or/c (name pred flat-ctcs ho-ctc)
#:property prop:orc-contract
(λ (this) (cons (single-or/c-ho-ctc this)
@ -186,7 +191,8 @@
#:generate (λ (ctc) (or/c-generate ctc
(cons (single-or/c-ho-ctc ctc)
(single-or/c-flat-ctcs ctc))))
#:exercise (λ (ctc) (or/c-exercise (list (single-or/c-ho-ctc ctc)))))))
#:exercise (λ (ctc) (or/c-exercise (list (single-or/c-ho-ctc ctc))))
#:list-contract? single-or/c-list-contract?)))
(define-struct (impersonator-single-or/c single-or/c) ()
#:property prop:custom-write custom-write-property-proc
@ -200,7 +206,8 @@
#:generate (λ (ctc) (or/c-generate ctc
(cons (single-or/c-ho-ctc ctc)
(single-or/c-flat-ctcs ctc))))
#:exercise (λ (ctc) (or/c-exercise (list (single-or/c-ho-ctc ctc))))))
#:exercise (λ (ctc) (or/c-exercise (list (single-or/c-ho-ctc ctc))))
#:list-contract? single-or/c-list-contract?))
(define (multi-or/c-proj ctc)
(let* ([ho-contracts (multi-or/c-ho-ctcs ctc)]
@ -319,6 +326,12 @@
(andmap contract-stronger? this-ctcs that-ctcs))))
(generic-or/c-stronger? this that)))
(define (mult-or/c-list-contract? c)
(and (for/and ([c (in-list (multi-or/c-flat-ctcs c))])
(list-contract? c))
(for/and ([c (in-list (multi-or/c-ho-ctcs c))])
(list-contract? c))))
(define-struct multi-or/c (name flat-ctcs ho-ctcs)
#:property prop:orc-contract
(λ (this) (append (multi-or/c-ho-ctcs this)
@ -337,7 +350,8 @@
#:generate (λ (ctc) (or/c-generate ctc
(append (multi-or/c-ho-ctcs ctc)
(multi-or/c-flat-ctcs ctc))))
#:exercise (λ (ctc) (or/c-exercise (multi-or/c-ho-ctcs ctc))))))
#:exercise (λ (ctc) (or/c-exercise (multi-or/c-ho-ctcs ctc)))
#:list-contract? mult-or/c-list-contract?)))
(define-struct (impersonator-multi-or/c multi-or/c) ()
#:property prop:custom-write custom-write-property-proc
@ -351,7 +365,8 @@
#:generate (λ (ctc) (or/c-generate ctc
(append (multi-or/c-ho-ctcs ctc)
(multi-or/c-flat-ctcs ctc))))
#:exercise (λ (ctc) (or/c-exercise (multi-or/c-ho-ctcs ctc)))))
#:exercise (λ (ctc) (or/c-exercise (multi-or/c-ho-ctcs ctc)))
#:list-contract? mult-or/c-list-contract?))
(define-struct flat-or/c (pred flat-ctcs)
#:property prop:custom-write custom-write-property-proc
@ -396,8 +411,11 @@
#:first-order
(λ (ctc) (flat-or/c-pred ctc))
#:generate (λ (ctc) (or/c-generate ctc (flat-or/c-flat-ctcs ctc)))))
#:generate (λ (ctc) (or/c-generate ctc (flat-or/c-flat-ctcs ctc)))
#:list-contract?
(λ (ctc)
(for/and ([c (in-list (flat-or/c-flat-ctcs ctc))])
(list-contract? c)))))
(define/final-prop (symbols s1 . s2s)

View File

@ -13,6 +13,7 @@
contract-struct-stronger?
contract-struct-generate
contract-struct-exercise
contract-struct-list-contract?
prop:flat-contract
flat-contract-struct?
@ -55,7 +56,8 @@
stronger
generate
exercise
val-first-projection ]
val-first-projection
list-contract? ]
#:omit-define-syntaxes)
(define (contract-property-guard prop info)
@ -121,6 +123,10 @@
(exercise c)
(λ (fuel) (values void '()))))
(define (contract-struct-list-contract? c)
(define prop (contract-struct-property c))
((contract-property-list-contract? prop) c))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Chaperone Contract Property
@ -215,7 +221,8 @@
#:val-first-projection [get-val-first-projection #f]
#:stronger [stronger #f]
#:generate [generate (λ (ctc) (λ (fuel) #f))]
#:exercise [exercise (λ (ctc) (λ (fuel) (values void '())))])
#:exercise [exercise (λ (ctc) (λ (fuel) (values void '())))]
#:list-contract? [list-contract? (λ (c) #f)])
;; this code is here to help me find the combinators that
;; are still using only #:projection and not #:val-first-projection
@ -242,10 +249,16 @@
get-name get-first-order)])]
[stronger (or stronger weakest)])
(mk get-name get-first-order get-projection stronger generate exercise get-val-first-projection)))
(mk get-name get-first-order
get-projection stronger
generate exercise
get-val-first-projection
list-contract?)))
(define build-contract-property
(build-property make-contract-property 'anonymous-contract values))
(procedure-rename
(build-property make-contract-property 'anonymous-contract values)
'build-contract-property))
;; Here we'll force the projection to always return the original value,
;; instead of assuming that the provided projection does so appropriately.
@ -257,9 +270,11 @@
(λ (v) (p v) v))))))
(define build-flat-contract-property
(build-property (compose make-flat-contract-property make-contract-property)
'anonymous-flat-contract
flat-projection-wrapper))
(procedure-rename
(build-property (compose make-flat-contract-property make-contract-property)
'anonymous-flat-contract
flat-projection-wrapper)
'build-flat-contract-property))
(define (chaperone-projection-wrapper f)
(λ (c)
@ -279,9 +294,11 @@
(c-proj (blame-add-unknown-context blame)))))
(define build-chaperone-contract-property
(build-property (compose make-chaperone-contract-property make-contract-property)
'anonymous-chaperone-contract
chaperone-projection-wrapper))
(procedure-rename
(build-property (compose make-chaperone-contract-property make-contract-property)
'anonymous-chaperone-contract
chaperone-projection-wrapper)
'build-chaperone-contract-property))
(define (get-any? c) any?)
(define (any? x) #t)
@ -309,7 +326,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-struct make-contract [ name first-order projection val-first-projection
stronger generate exercise ]
stronger generate exercise list-contract? ]
#:omit-define-syntaxes
#:property prop:custom-write
(λ (stct port display?)
@ -324,10 +341,11 @@
#:val-first-projection (lambda (c) (make-contract-val-first-projection c))
#:stronger (lambda (a b) ((make-contract-stronger a) a b))
#:generate (lambda (c) (make-contract-generate c))
#:exercise (lambda (c) (make-contract-exercise c))))
#:exercise (lambda (c) (make-contract-exercise c))
#:list-contract? (λ (c) (make-contract-list-contract? c))))
(define-struct make-chaperone-contract [ name first-order projection val-first-projection
stronger generate exercise ]
stronger generate exercise list-contract? ]
#:omit-define-syntaxes
#:property prop:custom-write
(λ (stct port display?)
@ -342,10 +360,11 @@
#:val-first-projection (lambda (c) (make-chaperone-contract-val-first-projection c))
#:stronger (lambda (a b) ((make-chaperone-contract-stronger a) a b))
#:generate (lambda (c) (make-chaperone-contract-generate c))
#:exercise (lambda (c) (make-chaperone-contract-exercise c))))
#:exercise (lambda (c) (make-chaperone-contract-exercise c))
#:list-contract? (λ (c) (make-chaperone-contract-list-contract? c))))
(define-struct make-flat-contract [ name first-order projection val-first-projection
stronger generate exercise ]
stronger generate exercise list-contract? ]
#:omit-define-syntaxes
#:property prop:custom-write
(λ (stct port display?)
@ -360,7 +379,8 @@
#:projection (lambda (c) (make-flat-contract-projection c))
#:stronger (lambda (a b) ((make-flat-contract-stronger a) a b))
#:generate (lambda (c) (make-flat-contract-generate c))
#:exercise (lambda (c) (make-flat-contract-exercise c))))
#:exercise (lambda (c) (make-flat-contract-exercise c))
#:list-contract? (λ (c) (make-flat-contract-list-contract? c))))
(define ((build-contract mk default-name)
#:name [name #f]
@ -369,7 +389,8 @@
#:val-first-projection [val-first-projection #f]
#:stronger [stronger #f]
#:generate [generate (λ (ctc) (λ (fuel) #f))]
#:exercise [exercise (λ (ctc) (λ (fuel) (values void '())))])
#:exercise [exercise (λ (ctc) (λ (fuel) (values void '())))]
#:list-contract? [list-contract? (λ (ctc) #f)])
(let* ([name (or name default-name)]
[first-order (or first-order any?)]
@ -379,7 +400,11 @@
(val-first-first-order-projection name first-order)))]
[stronger (or stronger as-strong?)])
(mk name first-order projection val-first-projection stronger generate exercise)))
(mk name first-order
projection val-first-projection
stronger
generate exercise
list-contract?)))
(define ((get-val-first-first-order-projection get-name get-first-order) c)
(val-first-first-order-projection (get-name c) (get-first-order c)))
@ -403,12 +428,19 @@
(contract-struct-projection b)))
(define make-contract
(build-contract make-make-contract 'anonymous-contract))
(procedure-rename
(build-contract make-make-contract 'anonymous-contract)
'make-contract))
(define make-chaperone-contract
(build-contract make-make-chaperone-contract 'anonymous-chaperone-contract))
(procedure-rename
(build-contract make-make-chaperone-contract 'anonymous-chaperone-contract)
'make-chaperone-contract))
(define make-flat-contract (build-contract make-make-flat-contract 'anonymous-flat-contract))
(define make-flat-contract
(procedure-rename
(build-contract make-make-flat-contract 'anonymous-flat-contract)
'make-flat-contract))
;; property should be bound to a function that accepts the contract and
;; returns a list of contracts that were the original arguments to the or/c