make or/c and contract-stronger? collaborate

in order to make contract-stronger? work better when given the result of or/c
This commit is contained in:
Robby Findler 2014-05-06 15:54:51 -05:00
parent 6f259fbd42
commit 4de1583c68
6 changed files with 450 additions and 349 deletions

View File

@ -53,14 +53,25 @@
(ctest #t contract-stronger? (or/c null? any/c) (or/c null? any/c))
(ctest #f contract-stronger? (or/c null? any/c) (or/c boolean? any/c))
(ctest #t contract-stronger? (or/c null? boolean?) (or/c null? boolean?))
(ctest #f contract-stronger? (or/c null? boolean?) (or/c boolean? null?))
(ctest #t contract-stronger? (or/c null? boolean?) (or/c boolean? null?))
(ctest #t contract-stronger?
(or/c null? (-> integer? integer?))
(or/c null? (-> integer? integer?)))
(ctest #f contract-stronger?
(or/c null? (-> boolean? boolean?))
(or/c null? (-> integer? integer?)))
(ctest #f contract-stronger? (or/c number? #f) number?)
(ctest #t contract-stronger? number? (or/c number? #f))
(ctest #f contract-stronger? (or/c (-> number? number?) #f) (-> number? number?))
(ctest #t contract-stronger? (-> number? number?) (or/c (-> number? number?) #f))
(ctest #f contract-stronger? (or/c (-> number? number?) (-> number? number? number?) #f) #f)
(ctest #t contract-stronger? #f (or/c (-> number? number?) (-> number? number? number?) #f))
(ctest #t contract-stronger? (or/c real?) (or/c integer? real?))
(ctest #t contract-stronger? (-> number?) (-> (or/c #f number?)))
(ctest #t contract-stronger? (-> (or/c #f number?) any/c) (-> number? any/c))
(ctest #f contract-stronger? (-> (or/c #f number?)) (-> number?))
(ctest #f contract-stronger? (-> number? any/c) (-> (or/c #f number?) any/c))
(ctest #t contract-stronger? number? number?)
(ctest #f contract-stronger? boolean? number?)
@ -102,7 +113,7 @@
(ctest #f contract-stronger?
(or/c (-> string?) (-> integer? integer?) integer? char?)
(or/c (-> string?) (-> integer? integer?) integer? boolean?))
(ctest #f contract-stronger?
(ctest #t contract-stronger?
(or/c (-> string?) (-> integer? integer?) integer?)
(or/c (-> string?) (-> integer? integer?) integer? boolean?))
(ctest #f contract-stronger?

View File

@ -16,7 +16,8 @@
"private/basic-opters.rkt" ;; required for effect to install the opters
"private/opt.rkt"
"private/out.rkt"
"private/arrow-val-first.rkt")
"private/arrow-val-first.rkt"
"private/orc.rkt")
(provide
(except-out (all-from-out "private/arrow.rkt")
@ -48,6 +49,7 @@
(except-out (all-from-out "private/misc.rkt")
check-between/c
check-unary-between/c)
symbols or/c one-of/c
provide/contract
;(for-syntax make-provide/contract-transformer) ;; not documented!
contract-out

View File

@ -355,9 +355,9 @@
(build-flat-contract-property
#:stronger
(λ (this that)
(and (predicate-contract? that)
(procedure-closure-contents-eq? (predicate-contract-pred this)
(predicate-contract-pred that))))
(and (predicate-contract? that)
(procedure-closure-contents-eq? (predicate-contract-pred this)
(predicate-contract-pred that))))
#:name (λ (ctc) (predicate-contract-name ctc))
#:first-order (λ (ctc) (predicate-contract-pred ctc))
#:val-first-projection

View File

@ -11,7 +11,6 @@
(provide flat-rec-contract
flat-murec-contract
or/c
and/c
not/c
=/c >=/c <=/c </c >/c between/c
@ -21,7 +20,6 @@
string-len/c
false/c
printable/c
symbols one-of/c
listof non-empty-listof cons/c list/c
promise/c
syntax/c
@ -57,7 +55,6 @@
contract-name
n->th
blame-add-or-context
blame-add-car-context
blame-add-cdr-context
raise-not-cons-blame-error)
@ -115,307 +112,6 @@
(define (flat-murec-contract/init x) (error 'flat-murec-contract "applied too soon"))
(define/subexpression-pos-prop or/c
(case-lambda
[() (make-none/c '(or/c))]
[raw-args
(define args (coerce-contracts 'or/c raw-args))
(define-values (ho-contracts flat-contracts)
(let loop ([ho-contracts '()]
[flat-contracts '()]
[args args])
(cond
[(null? args) (values ho-contracts (reverse flat-contracts))]
[else
(let ([arg (car args)])
(cond
[(flat-contract? arg)
(loop ho-contracts (cons arg flat-contracts) (cdr args))]
[else
(loop (cons arg ho-contracts) flat-contracts (cdr args))]))])))
(define pred
(cond
[(null? flat-contracts) not]
[else
(let loop ([fst (car flat-contracts)]
[rst (cdr flat-contracts)])
(let ([fst-pred (flat-contract-predicate fst)])
(cond
[(null? rst) fst-pred]
[else
(let ([r (loop (car rst) (cdr rst))])
(λ (x) (or (fst-pred x) (r x))))])))]))
(cond
[(null? ho-contracts)
(make-flat-or/c pred flat-contracts)]
[(null? (cdr ho-contracts))
(define name (apply build-compound-type-name 'or/c args))
(if (chaperone-contract? (car ho-contracts))
(make-chaperone-single-or/c name pred flat-contracts (car ho-contracts))
(make-impersonator-single-or/c name pred flat-contracts (car ho-contracts)))]
[else
(define name (apply build-compound-type-name 'or/c args))
(if (andmap chaperone-contract? ho-contracts)
(make-chaperone-multi-or/c name flat-contracts ho-contracts)
(make-impersonator-multi-or/c name flat-contracts ho-contracts))])]))
(define (single-or/c-projection ctc)
(let ([c-proc (contract-projection (single-or/c-ho-ctc ctc))]
[pred (single-or/c-pred ctc)])
(λ (blame)
(define partial-contract
(c-proc (blame-add-or-context blame)))
(λ (val)
(cond
[(pred val) val]
[else (partial-contract val)])))))
(define (single-or/c-val-first-projection ctc)
(define c-proj (get/build-val-first-projection (single-or/c-ho-ctc ctc)))
(define pred (single-or/c-pred ctc))
(λ (blame)
(define p-app (c-proj (blame-add-or-context blame)))
(λ (val)
(if (pred val)
(λ (neg-party) val)
(p-app val)))))
(define (blame-add-or-context blame)
(blame-add-context blame "a disjunct of"))
(define (single-or/c-first-order ctc)
(let ([pred (single-or/c-pred ctc)]
[ho (contract-first-order (single-or/c-ho-ctc ctc))])
(λ (x) (or (ho x) (pred x)))))
(define (single-or/c-stronger? this that)
(and (single-or/c? that)
(contract-stronger? (single-or/c-ho-ctc this)
(single-or/c-ho-ctc that))
(let ([this-ctcs (single-or/c-flat-ctcs this)]
[that-ctcs (single-or/c-flat-ctcs that)])
(and (= (length this-ctcs) (length that-ctcs))
(andmap contract-stronger?
this-ctcs
that-ctcs)))))
(define-struct single-or/c (name pred flat-ctcs ho-ctc))
(define-struct (chaperone-single-or/c single-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:chaperone-contract
(parameterize ([skip-projection-wrapper? #t])
(build-chaperone-contract-property
#:projection single-or/c-projection
#:val-first-projection single-or/c-val-first-projection
#:name single-or/c-name
#:first-order single-or/c-first-order
#:stronger single-or/c-stronger?)))
(define-struct (impersonator-single-or/c single-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:contract
(build-contract-property
#:projection single-or/c-projection
#:val-first-projection single-or/c-val-first-projection
#:name single-or/c-name
#:first-order single-or/c-first-order
#:stronger single-or/c-stronger?))
(define (multi-or/c-proj ctc)
(let* ([ho-contracts (multi-or/c-ho-ctcs ctc)]
[c-procs (map (λ (x) (contract-projection x)) ho-contracts)]
[first-order-checks (map (λ (x) (contract-first-order x)) ho-contracts)]
[predicates (map flat-contract-predicate (multi-or/c-flat-ctcs ctc))])
(λ (blame)
(define disj-blame (blame-add-context blame "a disjunct of"))
(define partial-contracts
(for/list ([c-proc (in-list c-procs)])
(c-proc disj-blame)))
(λ (val)
(cond
[(ormap (λ (pred) (pred val)) predicates)
val]
[else
(let loop ([checks first-order-checks]
[procs partial-contracts]
[contracts ho-contracts]
[candidate-proc #f]
[candidate-contract #f])
(cond
[(null? checks)
(if candidate-proc
(candidate-proc val)
(raise-blame-error blame val
'("none of the branches of the or/c matched" given: "~e")
val))]
[((car checks) val)
(if candidate-proc
(raise-blame-error blame val
'("two of the clauses in the or/c might both match: ~s and ~s"
given:
"~e")
(contract-name candidate-contract)
(contract-name (car contracts))
val)
(loop (cdr checks)
(cdr procs)
(cdr contracts)
(car procs)
(car contracts)))]
[else
(loop (cdr checks)
(cdr procs)
(cdr contracts)
candidate-proc
candidate-contract)]))])))))
(define (multi-or/c-val-first-proj ctc)
(define ho-contracts (multi-or/c-ho-ctcs ctc))
(define c-projs (map get/build-val-first-projection ho-contracts))
(define first-order-checks (map (λ (x) (contract-first-order x)) ho-contracts))
(define predicates (map flat-contract-predicate (multi-or/c-flat-ctcs ctc)))
(λ (blame)
(define blame-w-context (blame-add-or-context blame))
(λ (val)
(cond
[(for/or ([pred (in-list predicates)])
(pred val))
(λ (neg-party) val)]
[else
(let loop ([checks first-order-checks]
[c-projs c-projs]
[contracts ho-contracts]
[candidate-c-proj #f]
[candidate-contract #f])
(cond
[(null? checks)
(cond
[candidate-c-proj
((candidate-c-proj blame-w-context) val)]
[else
(λ (neg-party)
(raise-blame-error blame val #:missing-party neg-party
'("none of the branches of the or/c matched" given: "~e")
val))])]
[((car checks) val)
(if candidate-c-proj
(λ (neg-party)
(raise-blame-error blame val #:missing-party neg-party
'("two of the clauses in the or/c might both match: ~s and ~s"
given:
"~e")
(contract-name candidate-contract)
(contract-name (car contracts))
val))
(loop (cdr checks)
(cdr c-projs)
(cdr contracts)
(car c-projs)
(car contracts)))]
[else
(loop (cdr checks)
(cdr c-projs)
(cdr contracts)
candidate-c-proj
candidate-contract)]))]))))
(define (multi-or/c-first-order ctc)
(let ([flats (map flat-contract-predicate (multi-or/c-flat-ctcs ctc))]
[hos (map (λ (x) (contract-first-order x)) (multi-or/c-ho-ctcs ctc))])
(λ (x)
(or (ormap (λ (f) (f x)) hos)
(ormap (λ (f) (f x)) flats)))))
(define (multi-or/c-stronger? this that)
(and (multi-or/c? that)
(let ([this-ctcs (multi-or/c-ho-ctcs this)]
[that-ctcs (multi-or/c-ho-ctcs that)])
(and (= (length this-ctcs) (length that-ctcs))
(andmap contract-stronger? this-ctcs that-ctcs)))
(let ([this-ctcs (multi-or/c-flat-ctcs this)]
[that-ctcs (multi-or/c-flat-ctcs that)])
(and (= (length this-ctcs) (length that-ctcs))
(andmap contract-stronger? this-ctcs that-ctcs)))))
(define-struct multi-or/c (name flat-ctcs ho-ctcs))
(define-struct (chaperone-multi-or/c multi-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:chaperone-contract
(parameterize ([skip-projection-wrapper? #t])
(build-chaperone-contract-property
#:projection multi-or/c-proj
#:val-first-projection multi-or/c-val-first-proj
#:name multi-or/c-name
#:first-order multi-or/c-first-order
#:stronger multi-or/c-stronger?)))
(define-struct (impersonator-multi-or/c multi-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:contract
(build-contract-property
#:projection multi-or/c-proj
#:val-first-projection multi-or/c-val-first-proj
#:name multi-or/c-name
#:first-order multi-or/c-first-order
#:stronger multi-or/c-stronger?))
(define-struct flat-or/c (pred flat-ctcs)
#:property prop:custom-write custom-write-property-proc
#:property prop:flat-contract
(build-flat-contract-property
#:name
(λ (ctc)
(apply build-compound-type-name
'or/c
(flat-or/c-flat-ctcs ctc)))
#:stronger
(λ (this that)
(and (flat-or/c? that)
(let ([this-ctcs (flat-or/c-flat-ctcs this)]
[that-ctcs (flat-or/c-flat-ctcs that)])
(cond
[(and (<= (length this-ctcs) (length that-ctcs))
(for/and ([this-ctc (in-list this-ctcs)]
[that-ctc (in-list that-ctcs)])
(contract-stronger? this-ctc that-ctc)))
#t]
[(and (andmap (λ (x) (or (eq-contract? x) (equal-contract? x))) this-ctcs)
(andmap (λ (x) (or (eq-contract? x) (equal-contract? x))) that-ctcs))
(define ht (make-hash))
(for ([x (in-list that-ctcs)])
(hash-set! ht
(if (equal-contract? x)
(equal-contract-val x)
(eq-contract-val x))
#t))
(for/and ([x (in-list this-ctcs)])
(hash-ref ht
(if (equal-contract? x)
(equal-contract-val x)
(eq-contract-val x))
#f))]
[else #f]))))
#:first-order
(λ (ctc) (flat-or/c-pred ctc))
#:generate
(λ (ctc)
(λ (fuel)
(define choices
(filter
values
(for/list ([ctc (in-list (flat-or/c-flat-ctcs ctc))])
(generate/choose ctc fuel))))
(cond
[(null? choices) #f]
[else
(lambda ()
((oneof choices)))])))))
(define (and-name ctc)
(apply build-compound-type-name 'and/c (base-and/c-ctcs ctc)))
@ -554,39 +250,6 @@
(and (string? x)
((string-length x) . < . n)))))
(define/final-prop (symbols s1 . s2s)
(define ss (cons s1 s2s))
(for ([arg (in-list ss)]
[i (in-naturals)])
(unless (symbol? arg)
(raise-argument-error 'symbols
"symbol?"
i
ss)))
(apply or/c ss))
(define atomic-value?
(λ (x)
(or (char? x) (symbol? x) (boolean? x)
(null? x) (keyword? x) (number? x)
(void? x))))
(define/final-prop (one-of/c . elems)
(for ([arg (in-list elems)]
[i (in-naturals)])
(unless (atomic-value? arg)
(raise-argument-error 'one-of/c
"char, symbol, boolean, null, keyword, number, or void"
i
elems)))
(define or/c-args
(map (λ (x)
(cond
[(void? x) void?]
[else x]))
elems))
(apply or/c or/c-args))
(define-struct between/c (low high)
#:property prop:custom-write custom-write-property-proc
#:omit-define-syntaxes

View File

@ -0,0 +1,409 @@
#lang racket/base
(require "prop.rkt"
"blame.rkt"
"guts.rkt"
"rand.rkt"
"generate.rkt"
"misc.rkt")
(provide symbols or/c one-of/c
blame-add-or-context)
(define/subexpression-pos-prop or/c
(case-lambda
[() (make-none/c '(or/c))]
[raw-args
(define args (coerce-contracts 'or/c raw-args))
(define-values (ho-contracts flat-contracts)
(let loop ([ho-contracts '()]
[flat-contracts '()]
[args args])
(cond
[(null? args) (values ho-contracts (reverse flat-contracts))]
[else
(let ([arg (car args)])
(cond
[(flat-contract? arg)
(loop ho-contracts (cons arg flat-contracts) (cdr args))]
[else
(loop (cons arg ho-contracts) flat-contracts (cdr args))]))])))
(define pred
(cond
[(null? flat-contracts) not]
[else
(let loop ([fst (car flat-contracts)]
[rst (cdr flat-contracts)])
(let ([fst-pred (flat-contract-predicate fst)])
(cond
[(null? rst) fst-pred]
[else
(let ([r (loop (car rst) (cdr rst))])
(λ (x) (or (fst-pred x) (r x))))])))]))
(cond
[(null? ho-contracts)
(make-flat-or/c pred flat-contracts)]
[(null? (cdr ho-contracts))
(define name (apply build-compound-type-name 'or/c args))
(if (chaperone-contract? (car ho-contracts))
(make-chaperone-single-or/c name pred flat-contracts (car ho-contracts))
(make-impersonator-single-or/c name pred flat-contracts (car ho-contracts)))]
[else
(define name (apply build-compound-type-name 'or/c args))
(if (andmap chaperone-contract? ho-contracts)
(make-chaperone-multi-or/c name flat-contracts ho-contracts)
(make-impersonator-multi-or/c name flat-contracts ho-contracts))])]))
(define (single-or/c-projection ctc)
(let ([c-proc (contract-projection (single-or/c-ho-ctc ctc))]
[pred (single-or/c-pred ctc)])
(λ (blame)
(define partial-contract
(c-proc (blame-add-or-context blame)))
(λ (val)
(cond
[(pred val) val]
[else (partial-contract val)])))))
(define (single-or/c-val-first-projection ctc)
(define c-proj (get/build-val-first-projection (single-or/c-ho-ctc ctc)))
(define pred (single-or/c-pred ctc))
(λ (blame)
(define p-app (c-proj (blame-add-or-context blame)))
(λ (val)
(if (pred val)
(λ (neg-party) val)
(p-app val)))))
(define (blame-add-or-context blame)
(blame-add-context blame "a disjunct of"))
(define (single-or/c-first-order ctc)
(let ([pred (single-or/c-pred ctc)]
[ho (contract-first-order (single-or/c-ho-ctc ctc))])
(λ (x) (or (ho x) (pred x)))))
(define (single-or/c-stronger? this that)
(or (and (single-or/c? that)
(contract-stronger? (single-or/c-ho-ctc this)
(single-or/c-ho-ctc that))
(let ([this-ctcs (single-or/c-flat-ctcs this)]
[that-ctcs (single-or/c-flat-ctcs that)])
(and (= (length this-ctcs) (length that-ctcs))
(andmap contract-stronger?
this-ctcs
that-ctcs))))
(generic-or/c-stronger? this that)))
(define (generic-or/c-stronger? this that)
(define this-sub-ctcs (or/c-sub-contracts this))
(define that-sub-ctcs (or/c-sub-contracts that))
(and this-sub-ctcs
that-sub-ctcs
(for/and ([this-sub-ctc (in-list this-sub-ctcs)])
(for/or ([that-sub-ctc (in-list that-sub-ctcs)])
(contract-stronger? this-sub-ctc that-sub-ctc)))))
(define (or/c-sub-contracts ctc)
(cond
[(single-or/c? ctc)
(cons (single-or/c-ho-ctc ctc)
(single-or/c-flat-ctcs ctc))]
[(multi-or/c? ctc)
(append (multi-or/c-flat-ctcs ctc)
(multi-or/c-ho-ctcs ctc))]
[(flat-or/c? ctc)
(flat-or/c-flat-ctcs ctc)]
[else #f]))
(define (or/c-exercise ho-contracts)
(λ (fuel)
(define env (generate-env))
(values (λ (val)
(let loop ([ho-contracts ho-contracts])
(unless (null? ho-contracts)
(define ctc (car ho-contracts))
(cond
[((contract-first-order ctc) val)
(define-values (exercise ctcs) ((contract-struct-exercise ctc) fuel))
(exercise val)
(env-stash env ctc val)]
[else
(loop (cdr ho-contracts))]))))
'())))
(define (or/c-generate ctcs)
(λ (fuel)
(define choices
(filter
values
(for/list ([ctc (in-list ctcs)])
(generate/choose ctc fuel))))
(cond
[(null? choices) #f]
[else
(lambda ()
((oneof choices)))])))
(define-struct single-or/c (name pred flat-ctcs ho-ctc)
#:property prop:orc-contract
(λ (this) (cons (single-or/c-ho-ctc this)
(single-or/c-flat-ctcs this))))
(define-struct (chaperone-single-or/c single-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:chaperone-contract
(parameterize ([skip-projection-wrapper? #t])
(build-chaperone-contract-property
#:projection single-or/c-projection
#:val-first-projection single-or/c-val-first-projection
#:name single-or/c-name
#:first-order single-or/c-first-order
#:stronger single-or/c-stronger?
#:generate (λ (ctc) (or/c-generate (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)))))))
(define-struct (impersonator-single-or/c single-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:contract
(build-contract-property
#:projection single-or/c-projection
#:val-first-projection single-or/c-val-first-projection
#:name single-or/c-name
#:first-order single-or/c-first-order
#:stronger single-or/c-stronger?
#:generate (λ (ctc) (or/c-generate (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))))))
(define (multi-or/c-proj ctc)
(let* ([ho-contracts (multi-or/c-ho-ctcs ctc)]
[c-procs (map (λ (x) (contract-projection x)) ho-contracts)]
[first-order-checks (map (λ (x) (contract-first-order x)) ho-contracts)]
[predicates (map flat-contract-predicate (multi-or/c-flat-ctcs ctc))])
(λ (blame)
(define disj-blame (blame-add-context blame "a disjunct of"))
(define partial-contracts
(for/list ([c-proc (in-list c-procs)])
(c-proc disj-blame)))
(λ (val)
(cond
[(ormap (λ (pred) (pred val)) predicates)
val]
[else
(let loop ([checks first-order-checks]
[procs partial-contracts]
[contracts ho-contracts]
[candidate-proc #f]
[candidate-contract #f])
(cond
[(null? checks)
(if candidate-proc
(candidate-proc val)
(raise-blame-error blame val
'("none of the branches of the or/c matched" given: "~e")
val))]
[((car checks) val)
(if candidate-proc
(raise-blame-error blame val
'("two of the clauses in the or/c might both match: ~s and ~s"
given:
"~e")
(contract-name candidate-contract)
(contract-name (car contracts))
val)
(loop (cdr checks)
(cdr procs)
(cdr contracts)
(car procs)
(car contracts)))]
[else
(loop (cdr checks)
(cdr procs)
(cdr contracts)
candidate-proc
candidate-contract)]))])))))
(define (multi-or/c-val-first-proj ctc)
(define ho-contracts (multi-or/c-ho-ctcs ctc))
(define c-projs (map get/build-val-first-projection ho-contracts))
(define first-order-checks (map (λ (x) (contract-first-order x)) ho-contracts))
(define predicates (map flat-contract-predicate (multi-or/c-flat-ctcs ctc)))
(λ (blame)
(define blame-w-context (blame-add-or-context blame))
(λ (val)
(cond
[(for/or ([pred (in-list predicates)])
(pred val))
(λ (neg-party) val)]
[else
(let loop ([checks first-order-checks]
[c-projs c-projs]
[contracts ho-contracts]
[candidate-c-proj #f]
[candidate-contract #f])
(cond
[(null? checks)
(cond
[candidate-c-proj
((candidate-c-proj blame-w-context) val)]
[else
(λ (neg-party)
(raise-blame-error blame val #:missing-party neg-party
'("none of the branches of the or/c matched" given: "~e")
val))])]
[((car checks) val)
(if candidate-c-proj
(λ (neg-party)
(raise-blame-error blame val #:missing-party neg-party
'("two of the clauses in the or/c might both match: ~s and ~s"
given:
"~e")
(contract-name candidate-contract)
(contract-name (car contracts))
val))
(loop (cdr checks)
(cdr c-projs)
(cdr contracts)
(car c-projs)
(car contracts)))]
[else
(loop (cdr checks)
(cdr c-projs)
(cdr contracts)
candidate-c-proj
candidate-contract)]))]))))
(define (multi-or/c-first-order ctc)
(let ([flats (map flat-contract-predicate (multi-or/c-flat-ctcs ctc))]
[hos (map (λ (x) (contract-first-order x)) (multi-or/c-ho-ctcs ctc))])
(λ (x)
(or (ormap (λ (f) (f x)) hos)
(ormap (λ (f) (f x)) flats)))))
(define (multi-or/c-stronger? this that)
(or (and (multi-or/c? that)
(let ([this-ctcs (multi-or/c-ho-ctcs this)]
[that-ctcs (multi-or/c-ho-ctcs that)])
(and (= (length this-ctcs) (length that-ctcs))
(andmap contract-stronger? this-ctcs that-ctcs)))
(let ([this-ctcs (multi-or/c-flat-ctcs this)]
[that-ctcs (multi-or/c-flat-ctcs that)])
(and (= (length this-ctcs) (length that-ctcs))
(andmap contract-stronger? this-ctcs that-ctcs))))
(generic-or/c-stronger? this that)))
(define-struct multi-or/c (name flat-ctcs ho-ctcs)
#:property prop:orc-contract
(λ (this) (append (multi-or/c-ho-ctcs this)
(multi-or/c-flat-ctcs this))))
(define-struct (chaperone-multi-or/c multi-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:chaperone-contract
(parameterize ([skip-projection-wrapper? #t])
(build-chaperone-contract-property
#:projection multi-or/c-proj
#:val-first-projection multi-or/c-val-first-proj
#:name multi-or/c-name
#:first-order multi-or/c-first-order
#:stronger multi-or/c-stronger?
#:generate (λ (ctc) (or/c-generate (append (multi-or/c-ho-ctcs ctc)
(multi-or/c-flat-ctcs ctc))))
#:exercise (λ (ctc) (or/c-exercise (multi-or/c-ho-ctcs ctc))))))
(define-struct (impersonator-multi-or/c multi-or/c) ()
#:property prop:custom-write custom-write-property-proc
#:property prop:contract
(build-contract-property
#:projection multi-or/c-proj
#:val-first-projection multi-or/c-val-first-proj
#:name multi-or/c-name
#:first-order multi-or/c-first-order
#:stronger multi-or/c-stronger?
#:generate (λ (ctc) (or/c-generate (append (multi-or/c-ho-ctcs ctc)
(multi-or/c-flat-ctcs ctc))))
#:exercise (λ (ctc) (or/c-exercise (multi-or/c-ho-ctcs ctc)))))
(define-struct flat-or/c (pred flat-ctcs)
#:property prop:custom-write custom-write-property-proc
#:property prop:orc-contract
(λ (this) (flat-or/c-flat-ctcs this))
#:property prop:flat-contract
(build-flat-contract-property
#:name
(λ (ctc)
(apply build-compound-type-name
'or/c
(flat-or/c-flat-ctcs ctc)))
#:stronger
(λ (this that)
(or (and (flat-or/c? that)
(let ([this-ctcs (flat-or/c-flat-ctcs this)]
[that-ctcs (flat-or/c-flat-ctcs that)])
(cond
[(and (<= (length this-ctcs) (length that-ctcs))
(for/and ([this-ctc (in-list this-ctcs)]
[that-ctc (in-list that-ctcs)])
(contract-stronger? this-ctc that-ctc)))
#t]
[(and (andmap (λ (x) (or (eq-contract? x) (equal-contract? x))) this-ctcs)
(andmap (λ (x) (or (eq-contract? x) (equal-contract? x))) that-ctcs))
(define ht (make-hash))
(for ([x (in-list that-ctcs)])
(hash-set! ht
(if (equal-contract? x)
(equal-contract-val x)
(eq-contract-val x))
#t))
(for/and ([x (in-list this-ctcs)])
(hash-ref ht
(if (equal-contract? x)
(equal-contract-val x)
(eq-contract-val x))
#f))]
[else #f])))
(generic-or/c-stronger? this that)))
#:first-order
(λ (ctc) (flat-or/c-pred ctc))
#:generate (λ (ctc) (or/c-generate (flat-or/c-flat-ctcs ctc)))))
(define/final-prop (symbols s1 . s2s)
(define ss (cons s1 s2s))
(for ([arg (in-list ss)]
[i (in-naturals)])
(unless (symbol? arg)
(raise-argument-error 'symbols
"symbol?"
i
ss)))
(apply or/c ss))
(define/final-prop (one-of/c . elems)
(for ([arg (in-list elems)]
[i (in-naturals)])
(unless (atomic-value? arg)
(raise-argument-error 'one-of/c
"char, symbol, boolean, null, keyword, number, or void"
i
elems)))
(define or/c-args
(map (λ (x)
(cond
[(void? x) void?]
[else x]))
elems))
(apply or/c or/c-args))
(define atomic-value?
(λ (x)
(or (char? x) (symbol? x) (boolean? x)
(null? x) (keyword? x) (number? x)
(void? x))))

View File

@ -36,8 +36,12 @@
skip-projection-wrapper?
prop:opt-chaperone-contract
prop:opt-chaperone-contract?
prop:opt-chaperone-contract-get-test)
prop:opt-chaperone-contract?
prop:opt-chaperone-contract-get-test
prop:orc-contract
prop:orc-contract?
prop:orc-contract-get-subcontracts)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@ -92,9 +96,16 @@
(get-projection c)))
(define (contract-struct-stronger? a b)
(let* ([prop (contract-struct-property a)]
[stronger (contract-property-stronger prop)])
(stronger a b)))
(define prop (contract-struct-property a))
(define stronger? (contract-property-stronger prop))
(let loop ([b b])
(cond
[(stronger? a b) #t]
[(prop:orc-contract? b)
(define sub-contracts ((prop:orc-contract-get-subcontracts b) b))
(for/or ([sub-contract (in-list sub-contracts)])
(loop sub-contract))]
[else #f])))
(define (contract-struct-generate c)
(define prop (contract-struct-property c))
@ -398,3 +409,8 @@
(build-contract make-make-chaperone-contract 'anonymous-chaperone-contract))
(define make-flat-contract (build-contract make-make-flat-contract 'anonymous-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
(define-values (prop:orc-contract prop:orc-contract? prop:orc-contract-get-subcontracts)
(make-struct-type-property 'prop:orc-contract))