added contracts to define-relation.

(also removed old, wrong tl-pat stuff from the docs)
This commit is contained in:
Robby Findler 2010-11-04 16:38:36 -05:00
parent 4c081c127a
commit 8bf096b1e3
3 changed files with 97 additions and 33 deletions

View File

@ -1438,23 +1438,55 @@
[else
(syntax-case rest ()
[(id colon more ...)
(begin
(unless (eq? ': (syntax-e #'colon))
(raise-syntax-error syn-error-name "expected a colon to follow the meta-function's name" stx #'colon))
(let loop ([more (syntax->list #'(more ...))]
[dom-pats '()])
(cond
[(null? more)
(raise-syntax-error syn-error-name "expected an ->" stx)]
[(eq? (syntax-e (car more)) '->)
(when (null? (cdr more))
(raise-syntax-error syn-error-name "expected a range contract to follow the arrow" stx (car more)))
(let ([doms (reverse dom-pats)]
[codomain (cadr more)]
[clauses (check-clauses stx syn-error-name (cddr more) relation?)])
(values #'id doms codomain clauses))]
[else
(loop (cdr more) (cons (car more) dom-pats))])))]
(identifier? #'id)
(cond
[relation?
(unless (memq (syntax-e #'colon) '( ))
(raise-syntax-error syn-error-name
"expected ⊂ or ⊆ to follow the relation's name"
stx #'colon))
(let ([more (syntax->list #'(more ...))])
(when (null? more)
(raise-syntax-error syn-error-name
(format "expected a sequence of patterns separated by x or × to follow ~a"
(syntax-e #'colon))
stx))
(let loop ([more (cdr more)]
[arg-pats (list (car more))])
(cond
[(null? more)
(raise-syntax-error syn-error-name
"expected clause definitions to follow domain contract"
stx)]
[(memq (syntax-e (car more)) '(x ×))
(when (null? (cdr more))
(raise-syntax-error syn-error-name
(format "expected a pattern to follow ~a" (syntax-e (car more)))
stx))
(loop (cddr more)
(cons (cadr more) arg-pats))]
[else
(values #'id
(reverse arg-pats)
#'any
(check-clauses stx syn-error-name more relation?))])))]
[else
(unless (eq? ': (syntax-e #'colon))
(raise-syntax-error syn-error-name "expected a colon to follow the meta-function's name" stx #'colon))
(let loop ([more (syntax->list #'(more ...))]
[dom-pats '()])
(cond
[(null? more)
(raise-syntax-error syn-error-name "expected an ->" stx)]
[(eq? (syntax-e (car more)) '->)
(when (null? (cdr more))
(raise-syntax-error syn-error-name "expected a range contract to follow the arrow" stx (car more)))
(let ([doms (reverse dom-pats)]
[codomain (cadr more)]
[clauses (check-clauses stx syn-error-name (cddr more) relation?)])
(values #'id doms codomain clauses))]
[else
(loop (cdr more) (cons (car more) dom-pats))]))])]
[_
(raise-syntax-error
syn-error-name
@ -1492,7 +1524,7 @@
(λ (x)
(syntax-case x ()
[(stuff ...) (void)]
[x (raise-syntax-error syn-error-name "expected a metafunction clause" stx #'x)]))
[x (raise-syntax-error syn-error-name "expected a clause" stx #'x)]))
(syntax->list #'(x ...)))
(raise-syntax-error syn-error-name "error checking failed.2" stx))]))

View File

@ -682,15 +682,13 @@ all non-GUI portions of Redex) and also exported by
[extras rule-name
(fresh fresh-clause ...)
(side-condition racket-expression)
(where tl-pat @#,tttterm)
(where pat @#,tttterm)
(side-condition/hidden racket-expression)
(where/hidden tl-pat @#,tttterm)]
(where/hidden pat @#,tttterm)]
[rule-name identifier
string
(computed-name racket-expression)]
[fresh-clause var ((var1 ...) (var2 ...))]
[tl-pat identifier (tl-pat-ele ...)]
[tl-pat-ele tl-pat (code:line tl-pat ... (code:comment "a literal ellipsis"))])]{
[fresh-clause var ((var1 ...) (var2 ...))])]{
Defines a reduction relation casewise, one case for each of the
clauses beginning with @racket[-->] (or with @racket[arrow], if
@ -930,17 +928,15 @@ all non-GUI portions of Redex) and also exported by
@defform/subs[#:literals (: -> where side-condition side-condition/hidden where/hidden)
(define-metafunction language
contract
metafunction-contract
[(name @#,ttpattern ...) @#,tttterm extras ...]
...)
([contract (code:line)
(code:line id : @#,ttpattern ... -> @#,ttpattern)]
([metafunction-contract (code:line)
(code:line id : @#,ttpattern ... -> @#,ttpattern)]
[extras (side-condition racket-expression)
(side-condition/hidden racket-expression)
(where tl-pat @#,tttterm)
(where/hidden tl-pat @#,tttterm)]
[tl-pat identifier (tl-pat-ele ...)]
[tl-pat-ele tl-pat (code:line tl-pat ... (code:comment "a literal ellipsis"))])]{
(where pat @#,tttterm)
(where/hidden pat @#,tttterm)])]{
The @racket[define-metafunction] form builds a function on
sexpressions according to the pattern and right-hand-side
@ -1013,7 +1009,7 @@ match.
}
@defform[(define-metafunction/extension f language
contract
metafunction-contract
[(g @#,ttpattern ...) @#,tttterm extras ...]
...)]{
@ -1047,8 +1043,9 @@ and @racket[#f] otherwise.
@defform/subs[#:literals ()
(define-relation language
[(name @#,ttpattern ...) @#,tttterm ...] ...)
([tl-pat identifier (tl-pat-ele ...)]
[tl-pat-ele tl-pat (code:line tl-pat ... (code:comment "a literal ellipsis"))])]{
([relation-contract (code:line)
(code:line id ⊂ pat x ... x pat)
(code:line id ⊆ pat × ... × pat)])]{
The @racket[define-relation] form builds a relation on
sexpressions according to the pattern and right-hand-side
@ -1067,6 +1064,11 @@ the result is @racket[#f]. If there are multiple expressions on
the right-hand side of a relation, then all of them must be satisfied
in order for that clause of the relation to be satisfied.
The contract specification for a relation restricts the patterns that can
be used as input to a relation. For each argument to the relation, there
should be a single pattern, using @racket[x] or @racket[×] to separate
the argument contracts.
Note that relations are assumed to always return the same results for
the same inputs, and their results are cached, unless
@racket[caching-enable?] is set to @racket[#f]. Accordingly, if a

View File

@ -899,6 +899,36 @@
(test (term (<: 1 2 2)) #f)
(test (term (<: 1 1 1)) #t))
(let ()
(define-relation empty-language
d any × any
[(d (any) (any)) (d any any)]
[(d () ())])
(test (term (d ((())) ((())))) #t)
(test (term (d ((())) ())) #f))
(let ()
(define-relation empty-language
d any x any
[(d (any) (any)) (d any any)]
[(d () ())])
(test (term (d ((())) ((())))) #t)
(test (term (d ((())) ())) #f))
(let ()
(define-relation empty-language
d (any)
[(d (1))])
(test (term (d (1))) #t)
(test (term (d (2))) #f)
(test (with-handlers ((exn:fail? (λ (x) 'passed)))
(term (d 1))
'failed)
'passed))
; ;; ; ;; ;
; ; ; ; ;