add a second argument to list*of
to control what the last piece of the list is more explicitly
This commit is contained in:
parent
b0d9653cbe
commit
f669eb4af5
|
@ -469,13 +469,14 @@ a value, the result is not necessarily @racket[eq?] to the input.
|
||||||
(list)))]
|
(list)))]
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(list*of [c contract?]) contract?]{
|
@defproc[(list*of [ele-c contract?] [last-c contract? ele-c]) contract?]{
|
||||||
|
|
||||||
Returns a contract that recognizes improper lists whose elements match
|
Returns a contract that recognizes improper lists whose elements match
|
||||||
the contract @racket[c]. If an improper list is created with @racket[cons],
|
the contract @racket[ele-c] and whose last position matches @racket[last-c].
|
||||||
then its @racket[car] position is expected to match @racket[c] and
|
If an improper list is created with @racket[cons],
|
||||||
its @racket[cdr] position is expected to be @racket[(list*of c)]. Otherwise,
|
then its @racket[car] position is expected to match @racket[ele-c] and
|
||||||
it is expected to match @racket[c]. Beware that when this contract is applied to
|
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.
|
a value, the result is not necessarily @racket[eq?] to the input.
|
||||||
|
|
||||||
@examples[#:eval (contract-eval) #:once
|
@examples[#:eval (contract-eval) #:once
|
||||||
|
@ -488,7 +489,8 @@ a value, the result is not necessarily @racket[eq?] to the input.
|
||||||
(list*of number?)
|
(list*of number?)
|
||||||
(list 1 2 3)))]
|
(list 1 2 3)))]
|
||||||
|
|
||||||
@history[#:added "6.1.1.1"]
|
@history[#:added "6.1.1.1"
|
||||||
|
#:changed "6.4.0.4" @list{Added the @racket[last-c] argument.}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,16 @@
|
||||||
'list-contract-10b
|
'list-contract-10b
|
||||||
'(list-contract? (list*of any/c))
|
'(list-contract? (list*of any/c))
|
||||||
#f)
|
#f)
|
||||||
|
|
||||||
|
(test/spec-passed/result
|
||||||
|
'list-contract-10c
|
||||||
|
'(list-contract? (list*of any/c boolean?))
|
||||||
|
#f)
|
||||||
|
|
||||||
|
(test/spec-passed/result
|
||||||
|
'list-contract-10d
|
||||||
|
'(list-contract? (list*of any/c null?))
|
||||||
|
#t)
|
||||||
|
|
||||||
(test/spec-passed/result
|
(test/spec-passed/result
|
||||||
'list-contract-11
|
'list-contract-11
|
||||||
|
|
|
@ -64,6 +64,29 @@
|
||||||
(test/pos-blame
|
(test/pos-blame
|
||||||
'imlistof5
|
'imlistof5
|
||||||
'(contract (list*of integer?) (cons #f #t) 'pos 'neg))
|
'(contract (list*of integer?) (cons #f #t) 'pos 'neg))
|
||||||
|
|
||||||
|
(test/spec-passed/result
|
||||||
|
'imlistof6
|
||||||
|
'(contract (list*of integer? char?) '(1 2 . #\3) 'pos 'neg)
|
||||||
|
'(1 2 . #\3))
|
||||||
|
(test/pos-blame
|
||||||
|
'imlistof7
|
||||||
|
'(contract (list*of integer? char?) '() 'pos 'neg))
|
||||||
|
(test/pos-blame
|
||||||
|
'imlistof8
|
||||||
|
'(contract (list*of integer? char?) #f 'pos 'neg))
|
||||||
|
(test/pos-blame
|
||||||
|
'imlistof9
|
||||||
|
'(contract (list*of integer? char?) (list 1 2) 'pos 'neg))
|
||||||
|
(test/pos-blame
|
||||||
|
'imlistof10
|
||||||
|
'(contract (list*of integer? char?) (cons #f #t) 'pos 'neg))
|
||||||
|
(test/spec-passed
|
||||||
|
'imlistof11
|
||||||
|
'(contract (list*of (-> integer? integer?)
|
||||||
|
(-> boolean? boolean? boolean?))
|
||||||
|
(cons (λ (x) x) (cons (λ (y) y) (λ (a b) a)))
|
||||||
|
'pos 'neg))
|
||||||
|
|
||||||
(test/pos-blame
|
(test/pos-blame
|
||||||
'cons/dc1
|
'cons/dc1
|
||||||
|
|
|
@ -273,6 +273,9 @@
|
||||||
(test-name '(list*of boolean?) (list*of boolean?))
|
(test-name '(list*of boolean?) (list*of boolean?))
|
||||||
(test-name '(list*of any/c) (list*of any/c))
|
(test-name '(list*of any/c) (list*of any/c))
|
||||||
(test-name '(list*of (-> boolean? boolean?)) (list*of (-> boolean? boolean?)))
|
(test-name '(list*of (-> boolean? boolean?)) (list*of (-> boolean? boolean?)))
|
||||||
|
(test-name '(list*of boolean? char?) (list*of boolean? char?))
|
||||||
|
(test-name '(list*of any/c char?) (list*of any/c char?))
|
||||||
|
(test-name '(list*of (-> boolean? boolean?) char?) (list*of (-> boolean? boolean?) char?))
|
||||||
|
|
||||||
|
|
||||||
(test-name '(vectorof boolean?) (vectorof boolean?))
|
(test-name '(vectorof boolean?) (vectorof boolean?))
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
(check-not-exn (λ () (test-contract-generation (listof some-crazy-predicate?))))
|
(check-not-exn (λ () (test-contract-generation (listof some-crazy-predicate?))))
|
||||||
(check-not-exn (λ () (test-contract-generation (non-empty-listof boolean?))))
|
(check-not-exn (λ () (test-contract-generation (non-empty-listof boolean?))))
|
||||||
(check-not-exn (λ () (test-contract-generation (list*of boolean?))))
|
(check-not-exn (λ () (test-contract-generation (list*of boolean?))))
|
||||||
|
(check-not-exn (λ () (test-contract-generation (list*of boolean? char?))))
|
||||||
(check-not-exn (λ () (test-contract-generation (list/c boolean? number?))))
|
(check-not-exn (λ () (test-contract-generation (list/c boolean? number?))))
|
||||||
(check-not-exn (λ () ((car (test-contract-generation (list/c (-> number? number?)))) 0)))
|
(check-not-exn (λ () ((car (test-contract-generation (list/c (-> number? number?)))) 0)))
|
||||||
|
|
||||||
|
|
|
@ -210,6 +210,14 @@
|
||||||
(ctest #f contract-stronger? (listof number?) (cons/c number? (cons/c number? (listof any/c))))
|
(ctest #f contract-stronger? (listof number?) (cons/c number? (cons/c number? (listof any/c))))
|
||||||
(ctest #t contract-stronger? (list*of (<=/c 2)) (list*of (<=/c 3)))
|
(ctest #t contract-stronger? (list*of (<=/c 2)) (list*of (<=/c 3)))
|
||||||
(ctest #f contract-stronger? (list*of (<=/c 3)) (list*of (<=/c 2)))
|
(ctest #f contract-stronger? (list*of (<=/c 3)) (list*of (<=/c 2)))
|
||||||
|
(ctest #t contract-stronger? (list*of (<=/c 2) char?) (list*of (<=/c 3) char?))
|
||||||
|
(ctest #f contract-stronger? (list*of (<=/c 3) char?) (list*of (<=/c 2) char?))
|
||||||
|
(ctest #t contract-stronger? (list*of char? (<=/c 2)) (list*of char? (<=/c 3)))
|
||||||
|
(ctest #f contract-stronger? (list*of char? (<=/c 3)) (list*of char? (<=/c 2)))
|
||||||
|
(ctest #t contract-stronger? (list*of char? null?) (listof char?))
|
||||||
|
(ctest #t contract-stronger? (listof char?) (list*of char? null?))
|
||||||
|
(ctest #f contract-stronger? (list*of char? any/c) (listof char?))
|
||||||
|
|
||||||
|
|
||||||
(ctest #f contract-stronger? (vectorof (<=/c 3)) (vectorof (<=/c 4)))
|
(ctest #f contract-stronger? (vectorof (<=/c 3)) (vectorof (<=/c 4)))
|
||||||
(ctest #f contract-stronger? (vectorof (<=/c 3)) (vectorof (<=/c 4)))
|
(ctest #f contract-stronger? (vectorof (<=/c 3)) (vectorof (<=/c 4)))
|
||||||
|
|
|
@ -524,29 +524,56 @@
|
||||||
(λ (x) (not (pred x))))))
|
(λ (x) (not (pred x))))))
|
||||||
|
|
||||||
(define (listof-generate ctc)
|
(define (listof-generate ctc)
|
||||||
(λ (fuel)
|
(cond
|
||||||
(define eg (contract-random-generate/choose (listof-ctc-elem-c ctc) fuel))
|
[(im-listof-ctc? ctc)
|
||||||
(if eg
|
(λ (fuel)
|
||||||
(λ ()
|
(define middle-eg (contract-random-generate/choose (listof-ctc-elem-c ctc) fuel))
|
||||||
(let loop ([so-far (cond
|
(define last-eg (contract-random-generate/choose (im-listof-ctc-last-c ctc) fuel))
|
||||||
[(pe-listof-ctc? ctc)
|
(cond
|
||||||
'()]
|
[(and last-eg middle-eg)
|
||||||
[(ne-listof-ctc? ctc)
|
(λ ()
|
||||||
(list (eg))]
|
(let loop ([so-far (last-eg)])
|
||||||
[else
|
(rand-choice
|
||||||
;; improper list
|
[1/5 so-far]
|
||||||
(eg)])])
|
[else (loop (cons (middle-eg) so-far))])))]
|
||||||
(rand-choice
|
[last-eg
|
||||||
[1/5 so-far]
|
(λ ()
|
||||||
[else (loop (cons (eg) so-far))])))
|
(last-eg))]
|
||||||
(if (pe-listof-ctc? ctc)
|
[else #f]))]
|
||||||
(λ () '())
|
[else
|
||||||
#f))))
|
(λ (fuel)
|
||||||
|
(define eg (contract-random-generate/choose (listof-ctc-elem-c ctc) fuel))
|
||||||
|
(if eg
|
||||||
|
(λ ()
|
||||||
|
(let loop ([so-far (cond
|
||||||
|
[(pe-listof-ctc? ctc)
|
||||||
|
'()]
|
||||||
|
[(ne-listof-ctc? ctc)
|
||||||
|
(list (eg))])])
|
||||||
|
(rand-choice
|
||||||
|
[1/5 so-far]
|
||||||
|
[else (loop (cons (eg) so-far))])))
|
||||||
|
(if (pe-listof-ctc? ctc)
|
||||||
|
(λ () '())
|
||||||
|
#f)))]))
|
||||||
|
|
||||||
(define (listof-exercise ctc)
|
(define (listof-exercise ctc)
|
||||||
(cond
|
(cond
|
||||||
[(pe-listof-ctc? ctc)
|
[(pe-listof-ctc? ctc)
|
||||||
(λ (fuel) (values void '()))]
|
(λ (fuel) (values void '()))]
|
||||||
|
[(im-listof-ctc? ctc)
|
||||||
|
(define last-ctc (im-listof-ctc-last-c ctc))
|
||||||
|
(λ (fuel)
|
||||||
|
(define env (contract-random-generate-get-current-environment))
|
||||||
|
(values
|
||||||
|
(λ (lst)
|
||||||
|
(contract-random-generate-stash
|
||||||
|
env last-ctc
|
||||||
|
(let loop ([lst lst])
|
||||||
|
(cond
|
||||||
|
[(pair? lst) (loop (cdr lst))]
|
||||||
|
[else lst]))))
|
||||||
|
(list last-ctc)))]
|
||||||
[else
|
[else
|
||||||
(define elem-ctc (listof-ctc-elem-c ctc))
|
(define elem-ctc (listof-ctc-elem-c ctc))
|
||||||
(λ (fuel)
|
(λ (fuel)
|
||||||
|
@ -555,10 +582,7 @@
|
||||||
(λ (lst)
|
(λ (lst)
|
||||||
(contract-random-generate-stash
|
(contract-random-generate-stash
|
||||||
env elem-ctc
|
env elem-ctc
|
||||||
(oneof
|
(oneof lst)))
|
||||||
(if (im-listof-ctc? ctc)
|
|
||||||
(improper-list->list lst)
|
|
||||||
lst))))
|
|
||||||
(list elem-ctc)))]))
|
(list elem-ctc)))]))
|
||||||
|
|
||||||
(define (improper-list->list l)
|
(define (improper-list->list l)
|
||||||
|
@ -571,11 +595,15 @@
|
||||||
(cond
|
(cond
|
||||||
[(listof-ctc? that)
|
[(listof-ctc? that)
|
||||||
(define that-elem (listof-ctc-elem-c that))
|
(define that-elem (listof-ctc-elem-c that))
|
||||||
(and (cond
|
(cond
|
||||||
[(pe-listof-ctc? this) (pe-listof-ctc? that)]
|
[(pe-listof-ctc? this) (and (pe-listof-ctc? that)
|
||||||
[(im-listof-ctc? this) (im-listof-ctc? that)]
|
(contract-struct-stronger? this-elem that-elem))]
|
||||||
[else #t])
|
[(im-listof-ctc? this)
|
||||||
(contract-struct-stronger? this-elem that-elem))]
|
(and (im-listof-ctc? that)
|
||||||
|
(contract-struct-stronger? this-elem that-elem)
|
||||||
|
(contract-struct-stronger? (im-listof-ctc-last-c this)
|
||||||
|
(im-listof-ctc-last-c that)))]
|
||||||
|
[else (contract-struct-stronger? this-elem that-elem)])]
|
||||||
[(the-cons/c? that)
|
[(the-cons/c? that)
|
||||||
(define hd-ctc (the-cons/c-hd-ctc that))
|
(define hd-ctc (the-cons/c-hd-ctc that))
|
||||||
(define tl-ctc (the-cons/c-tl-ctc that))
|
(define tl-ctc (the-cons/c-tl-ctc that))
|
||||||
|
@ -596,14 +624,19 @@
|
||||||
(define (non-empty-list? x) (and (pair? x) (list? x)))
|
(define (non-empty-list? x) (and (pair? x) (list? x)))
|
||||||
|
|
||||||
(define (list-name ctc)
|
(define (list-name ctc)
|
||||||
(build-compound-type-name (cond
|
(cond
|
||||||
[(pe-listof-ctc? ctc)
|
[(pe-listof-ctc? ctc)
|
||||||
'listof]
|
(build-compound-type-name 'listof (listof-ctc-elem-c ctc))]
|
||||||
[(ne-listof-ctc? ctc)
|
[(ne-listof-ctc? ctc)
|
||||||
'non-empty-listof]
|
(build-compound-type-name 'non-empty-listof (listof-ctc-elem-c ctc))]
|
||||||
[(im-listof-ctc? ctc)
|
[(im-listof-ctc? ctc)
|
||||||
'list*of])
|
(define elem-name (contract-name (listof-ctc-elem-c ctc)))
|
||||||
(listof-ctc-elem-c ctc)))
|
(define last-name (contract-name (im-listof-ctc-last-c ctc)))
|
||||||
|
(cond
|
||||||
|
[(equal? elem-name last-name)
|
||||||
|
`(list*of ,elem-name)]
|
||||||
|
[else
|
||||||
|
`(list*of ,elem-name ,last-name)])]))
|
||||||
|
|
||||||
(define (list-fo-check ctc)
|
(define (list-fo-check ctc)
|
||||||
(define elem-fo? (contract-first-order (listof-ctc-elem-c ctc)))
|
(define elem-fo? (contract-first-order (listof-ctc-elem-c ctc)))
|
||||||
|
@ -620,6 +653,7 @@
|
||||||
(for/and ([e (in-list v)])
|
(for/and ([e (in-list v)])
|
||||||
(elem-fo? e))))]
|
(elem-fo? e))))]
|
||||||
[(im-listof-ctc? ctc)
|
[(im-listof-ctc? ctc)
|
||||||
|
(define last-fo? (contract-first-order (im-listof-ctc-last-c ctc)))
|
||||||
(λ (v)
|
(λ (v)
|
||||||
(let loop ([v v])
|
(let loop ([v v])
|
||||||
(cond
|
(cond
|
||||||
|
@ -627,50 +661,59 @@
|
||||||
(and (elem-fo? (car v))
|
(and (elem-fo? (car v))
|
||||||
(loop (cdr v)))]
|
(loop (cdr v)))]
|
||||||
[else
|
[else
|
||||||
(elem-fo? v)])))]))
|
(last-fo? v)])))]))
|
||||||
|
|
||||||
(define (listof-late-neg-projection ctc)
|
(define (listof-late-neg-projection ctc)
|
||||||
(define elem-proj (get/build-late-neg-projection (listof-ctc-elem-c ctc)))
|
(define elem-proj (get/build-late-neg-projection (listof-ctc-elem-c ctc)))
|
||||||
(define pred? (if (pe-listof-ctc? ctc)
|
(define pred? (if (pe-listof-ctc? ctc)
|
||||||
list?
|
list?
|
||||||
non-empty-list?))
|
non-empty-list?))
|
||||||
|
(define last-proj (and (im-listof-ctc? ctc)
|
||||||
|
(get/build-late-neg-projection (im-listof-ctc-last-c ctc))))
|
||||||
(λ (blame)
|
(λ (blame)
|
||||||
(define elem-proj+blame (elem-proj (blame-add-listof-context blame)))
|
(define lo-blame (blame-add-listof-context blame))
|
||||||
|
(define elem-proj+blame (elem-proj lo-blame))
|
||||||
(cond
|
(cond
|
||||||
[(flat-listof-ctc? ctc)
|
[(flat-listof-ctc? ctc)
|
||||||
(if (im-listof-ctc? ctc)
|
(cond
|
||||||
(λ (val neg-party)
|
[(im-listof-ctc? ctc)
|
||||||
(let loop ([val val])
|
(define last-elem-proj+blame (last-proj lo-blame))
|
||||||
(cond
|
(λ (val neg-party)
|
||||||
[(pair? val)
|
(let loop ([val val])
|
||||||
(elem-proj+blame (car val) neg-party)
|
(cond
|
||||||
(loop (cdr val))]
|
[(pair? val)
|
||||||
[else
|
(elem-proj+blame (car val) neg-party)
|
||||||
(elem-proj+blame val neg-party)]))
|
(loop (cdr val))]
|
||||||
val)
|
[else
|
||||||
(λ (val neg-party)
|
(last-elem-proj+blame val neg-party)]))
|
||||||
(cond
|
val)]
|
||||||
[(pred? val)
|
[else
|
||||||
(for ([x (in-list val)])
|
(λ (val neg-party)
|
||||||
(elem-proj+blame x neg-party))
|
(cond
|
||||||
val]
|
[(pred? val)
|
||||||
[else
|
(for ([x (in-list val)])
|
||||||
(raise-listof-blame-error blame val (pe-listof-ctc? ctc) neg-party)])))]
|
(elem-proj+blame x neg-party))
|
||||||
|
val]
|
||||||
|
[else
|
||||||
|
(raise-listof-blame-error blame val (pe-listof-ctc? ctc) neg-party)]))])]
|
||||||
[else
|
[else
|
||||||
(if (im-listof-ctc? ctc)
|
(cond
|
||||||
(λ (val neg-party)
|
[(im-listof-ctc? ctc)
|
||||||
(let loop ([val val])
|
(define last-elem-proj+blame (last-proj lo-blame))
|
||||||
(cond
|
(λ (val neg-party)
|
||||||
[(pair? val)
|
(let loop ([val val])
|
||||||
(cons (elem-proj+blame (car val) neg-party)
|
(cond
|
||||||
(loop (cdr val)))]
|
[(pair? val)
|
||||||
[else
|
(cons (elem-proj+blame (car val) neg-party)
|
||||||
(elem-proj+blame val neg-party)])))
|
(loop (cdr val)))]
|
||||||
(λ (val neg-party)
|
[else
|
||||||
(if (pred? val)
|
(last-elem-proj+blame val neg-party)])))]
|
||||||
(for/list ([x (in-list val)])
|
[else
|
||||||
(elem-proj+blame x neg-party))
|
(λ (val neg-party)
|
||||||
(raise-listof-blame-error blame val (pe-listof-ctc? ctc) neg-party))))])))
|
(if (pred? val)
|
||||||
|
(for/list ([x (in-list val)])
|
||||||
|
(elem-proj+blame x neg-party))
|
||||||
|
(raise-listof-blame-error blame val (pe-listof-ctc? ctc) neg-party)))])])))
|
||||||
|
|
||||||
(define flat-prop
|
(define flat-prop
|
||||||
(build-flat-contract-property
|
(build-flat-contract-property
|
||||||
|
@ -735,7 +778,7 @@
|
||||||
#:property prop:contract full-prop)
|
#:property prop:contract full-prop)
|
||||||
|
|
||||||
;; improper lists
|
;; improper lists
|
||||||
(struct im-listof-ctc listof-ctc ())
|
(struct im-listof-ctc listof-ctc (last-c))
|
||||||
|
|
||||||
;; improper, flat
|
;; improper, flat
|
||||||
(struct imf-listof-ctc im-listof-ctc ()
|
(struct imf-listof-ctc im-listof-ctc ()
|
||||||
|
@ -777,12 +820,16 @@
|
||||||
[(flat-contract? c) (pef-listof-ctc c)]
|
[(flat-contract? c) (pef-listof-ctc c)]
|
||||||
[(chaperone-contract? c) (pec-listof-ctc c)]
|
[(chaperone-contract? c) (pec-listof-ctc c)]
|
||||||
[else (pei-listof-ctc c)]))
|
[else (pei-listof-ctc c)]))
|
||||||
(define/subexpression-pos-prop (list*of raw-c)
|
(define/subexpression-pos-prop (list*of raw-ele-c [raw-last-c raw-ele-c])
|
||||||
(define c (coerce-contract 'list*of raw-c))
|
(define ele-c (coerce-contract 'list*of raw-ele-c))
|
||||||
|
(define last-c (coerce-contract 'list*of raw-last-c))
|
||||||
(cond
|
(cond
|
||||||
[(flat-contract? c) (imf-listof-ctc c)]
|
[(and (generic-list/c? last-c)
|
||||||
[(chaperone-contract? c) (imc-listof-ctc c)]
|
(null? (generic-list/c-args last-c)))
|
||||||
[else (imi-listof-ctc c)]))
|
(listof ele-c)]
|
||||||
|
[(and (flat-contract? ele-c) (flat-contract? last-c)) (imf-listof-ctc ele-c last-c)]
|
||||||
|
[(and (chaperone-contract? ele-c) (chaperone-contract? last-c)) (imc-listof-ctc ele-c last-c)]
|
||||||
|
[else (imi-listof-ctc ele-c last-c)]))
|
||||||
|
|
||||||
|
|
||||||
(define (blame-add-car-context blame) (blame-add-context blame "the car of"))
|
(define (blame-add-car-context blame) (blame-add-context blame "the car of"))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user