Adding dynamic/c and coerce/c
This commit is contained in:
parent
7ebdd3c7f1
commit
d6d9f3ef8c
|
@ -1,6 +1,18 @@
|
|||
#lang racket
|
||||
(require rackunit rackunit/text-ui unstable/contract "helpers.rkt" tests/eli-tester)
|
||||
|
||||
(require rackunit rackunit/text-ui unstable/contract "helpers.rkt")
|
||||
(test
|
||||
(let ()
|
||||
(define p (make-parameter any/c))
|
||||
(define c (dynamic/c string? p number?))
|
||||
|
||||
(parameterize ([p (coerce/c string->number)])
|
||||
(test
|
||||
(contract c "123" 'pos 'neg) => 123
|
||||
(contract c "123a" 'pos 'neg) =error> "Coercion failed"))
|
||||
|
||||
(test
|
||||
(contract c "123" 'pos 'neg) =error> "broke")))
|
||||
|
||||
(run-tests
|
||||
(test-suite "contract.ss"
|
||||
|
|
|
@ -1,6 +1,38 @@
|
|||
#lang racket/base
|
||||
(require racket/contract racket/dict racket/match)
|
||||
|
||||
(define (dynamic/c pre parameter post)
|
||||
(define pre-ctc (coerce-contract 'pre pre))
|
||||
(define post-ctc (coerce-contract 'post post))
|
||||
(make-contract
|
||||
#:name (build-compound-type-name 'dynamic pre-ctc parameter post-ctc)
|
||||
#:projection
|
||||
(λ (b)
|
||||
(define pre-proj ((contract-projection pre-ctc) b))
|
||||
(define post-proj ((contract-projection post-ctc) b))
|
||||
(λ (x)
|
||||
(define dyn-proj
|
||||
((contract-projection (coerce-contract 'dynamic (parameter))) b))
|
||||
(post-proj
|
||||
(dyn-proj
|
||||
(pre-proj
|
||||
x)))))))
|
||||
|
||||
(define (coerce/c i->o)
|
||||
(make-contract
|
||||
#:name (build-compound-type-name 'coerce i->o)
|
||||
#:projection
|
||||
(λ (b)
|
||||
(λ (x)
|
||||
(or (i->o x)
|
||||
(raise-blame-error b x "Coercion failed"))))))
|
||||
|
||||
(provide/contract
|
||||
[dynamic/c (-> contract? (parameter/c contract?) contract?
|
||||
contract?)]
|
||||
[coerce/c (-> (-> any/c any/c)
|
||||
contract?)])
|
||||
|
||||
(define path-element?
|
||||
(or/c path-string? (symbols 'up 'same)))
|
||||
;; Eli: We already have a notion of "path element" which is different
|
||||
|
|
|
@ -222,3 +222,27 @@ immutable dictionaries (which may be passed through a constructor that involves
|
|||
efficient than the original dictionaries.
|
||||
|
||||
}
|
||||
|
||||
@addition[@author+email["Jay McCarthy" "jay@racket-lang.org"]]
|
||||
|
||||
@defproc[(dynamic/c [pre contract?] [dynamic (parameter/c contract?)] [post contract?])
|
||||
contract?]{
|
||||
Returns a contract that applies the @racket[pre] contract, then the contract dynamically bound to the @racket[dynamic] parameter, then the @racket[post] contract.
|
||||
}
|
||||
|
||||
@defproc[(coerce/c [coerce (-> any/c any/c)])
|
||||
contract?]{
|
||||
Returns a contract that applies @racket[coerce] to all values and blames the positive party if @racket[coerce] returns false. This is a light-weight way to create a contract from a simple projection.
|
||||
}
|
||||
|
||||
@defexamples[
|
||||
#:eval (eval/require 'racket/contract 'unstable/contract)
|
||||
|
||||
(define p (make-parameter any/c))
|
||||
(define c (dynamic/c string? p number?))
|
||||
|
||||
(contract c "123" 'pos 'neg)
|
||||
|
||||
(p (coerce/c string->number))
|
||||
(contract c "123" 'pos 'neg)
|
||||
(contract c "123a" 'pos 'neg)]
|
||||
|
|
Loading…
Reference in New Issue
Block a user