add a proper stronger implementation based for recursive-contract

Following _Subtyping Recursive Types_ by Roberto M. Amadio and Luca Cardelli
This commit is contained in:
Robby Findler 2014-09-19 23:23:25 -05:00
parent 929ed92f40
commit eaf48bbbf1
3 changed files with 76 additions and 15 deletions

View File

@ -14,10 +14,22 @@
(ctest #f contract-stronger? (>=/c 2) (>=/c 3))
(ctest #f contract-stronger? (<=/c 3) (<=/c 2))
(ctest #t contract-stronger? (<=/c 2) (<=/c 3))
(ctest #f contract-stronger? (recursive-contract (<=/c 2)) (recursive-contract (<=/c 3)))
(ctest #t contract-stronger? (recursive-contract (<=/c 2)) (recursive-contract (<=/c 3)))
(ctest #f contract-stronger? (recursive-contract (<=/c 3)) (recursive-contract (<=/c 2)))
(let ([f (contract-eval '(λ (x) (recursive-contract (<=/c x))))])
(test #t (contract-eval 'contract-stronger?) (contract-eval `(,f 1)) (contract-eval `(,f 1))))
(ctest #t contract-stronger?
(letrec ([c (recursive-contract (-> (<=/c 5) c))]) c)
(letrec ([c (recursive-contract (-> (<=/c 3) c))]) c))
(ctest #t contract-stronger?
(letrec ([c (recursive-contract (-> (<=/c 3) c))]) c)
(letrec ([c (recursive-contract (-> (<=/c 1) c))]) c))
(ctest #t contract-stronger?
(letrec ([c (recursive-contract (-> (<=/c 3) c))]) c)
(letrec ([c (recursive-contract (-> (<=/c 1) (-> (<=/c 1) c)))]) c))
(ctest #t contract-stronger?
(letrec ([c (recursive-contract (-> (<=/c 1) (-> (<=/c 1) c)))]) c)
(letrec ([c (recursive-contract (-> (<=/c 1) (-> (<=/c 1) (-> (<=/c 1) c))))]) c))
(ctest #t contract-stronger? (-> integer? integer?) (-> integer? integer?))
(ctest #f contract-stronger? (-> boolean? boolean?) (-> integer? integer?))
(ctest #t contract-stronger? (-> (>=/c 3) (>=/c 3)) (-> (>=/c 4) (>=/c 3)))

View File

@ -174,16 +174,18 @@
(λ (val)
((f blame-known) val)))]))
(define (recursive-contract-stronger this that)
(and (recursive-contract? that)
(procedure-closure-contents-eq? (recursive-contract-thunk this)
(recursive-contract-thunk that))))
(define (recursive-contract-stronger this that) (equal? this that))
(define trail (make-parameter #f))
(define ((recursive-contract-first-order ctc) val)
(contract-first-order-passes? (force-recursive-contract ctc)
val))
(struct recursive-contract ([name #:mutable] thunk [ctc #:mutable] list-contract?))
(struct recursive-contract ([name #:mutable] thunk [ctc #:mutable] list-contract?)
#:property prop:recursive-contract (λ (this)
(force-recursive-contract this)
(recursive-contract-ctc this)))
(struct flat-recursive-contract recursive-contract ()
#:property prop:custom-write custom-write-property-proc

View File

@ -42,7 +42,16 @@
prop:orc-contract
prop:orc-contract?
prop:orc-contract-get-subcontracts)
prop:orc-contract-get-subcontracts
prop:recursive-contract
prop:recursive-contract?
prop:recursive-contract-unroll
prop:arrow-contract
prop:arrow-contract?
prop:arrow-contract-get-info
(struct-out arrow-contract-info))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@ -97,9 +106,28 @@
(and get-projection
(get-projection c)))
(define trail (make-parameter #f))
(define (contract-struct-stronger? a b)
(define prop (contract-struct-property a))
(define stronger? (contract-property-stronger prop))
(cond
[(let ([tc (trail)])
(and tc
(ormap (λ (pr) (and (equal? (car pr) a) (equal? (cdr pr) b)))
(unbox tc))))
#t]
[(or (prop:recursive-contract? a) (prop:recursive-contract? b))
(parameterize ([trail (or (trail) (box '()))])
(define trail-b (trail))
(define trail-c (unbox trail-b))
(set-box! trail-b (cons (cons a b) trail-c))
(contract-struct-stronger? (if (prop:recursive-contract? a)
((prop:recursive-contract-unroll a) a)
a)
(if (prop:recursive-contract? b)
((prop:recursive-contract-unroll b) b)
b)))]
[else
(let loop ([b b])
(cond
[(stronger? a b) #t]
@ -107,7 +135,7 @@
(define sub-contracts ((prop:orc-contract-get-subcontracts b) b))
(for/or ([sub-contract (in-list sub-contracts)])
(loop sub-contract))]
[else #f])))
[else #f]))]))
(define (contract-struct-generate c)
(define prop (contract-struct-property c))
@ -446,3 +474,22 @@
;; 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))
;; property should be bound to a function that accepts the contract
;; and returns a new contract, after unrolling one time
(define-values (prop:recursive-contract
prop:recursive-contract?
prop:recursive-contract-unroll)
(make-struct-type-property 'prop:recursive-contract))
;; get-info : (-> ctc arrow-contract-info?)
(define-values (prop:arrow-contract prop:arrow-contract? prop:arrow-contract-get-info)
(make-struct-type-property 'prop:arrow-contract))
;; chaperone-procedure :
;; (-> any/c[val] blame? procedure[suitable for second argument to chaperone-procedure])
;; check-first-order : any/c[val] blame? -> void?
;; raises a blame error if val doesn't satisfy the first-order checks for the function
;; accepts-arglist : (-> (listof keyword?)[sorted by keyword<?] exact-nonnegative-integer? boolean?)
(struct arrow-contract-info (chaperone-procedure check-first-order accepts-arglist)
#:transparent)