Redex: corrections for disequations in generator

- handle parameters correctly when simplifying disequations
- rework term generation/disequation checking for parameters
- fix define-extended-metafunction w/r/t the above
This commit is contained in:
Burke Fetscher 2013-03-22 15:26:40 -05:00
parent 40fc96cacf
commit ddf4945125
6 changed files with 229 additions and 99 deletions

View File

@ -1,16 +1,19 @@
#lang racket/base
(require
(require racket/match
racket/set
(only-in "rg.rkt"
[compile rg:compile])
(only-in "reduction-semantics.rkt"
do-test-match)
"pat-unify.rkt"
(for-syntax racket/base)
racket/match)
(for-syntax racket/base))
(provide pat->term
check-dq)
check-dq
dq)
;; term generation
@ -72,31 +75,31 @@
(define (check-dqs dqs term-e lang eqs)
(for/and ([dq dqs])
(define te (hash-copy term-e))
(define rhs (list-ref dq 0))
(define lhs (list-ref dq 1))
(check-dq rhs lhs te lang eqs)))
(define sym-index 0)
(check-dq dq te lang eqs)))
(struct not-ground ())
(define (check-dq rhs lhs term-e lang eqs)
(set! sym-index 0)
(define rhs-term (pat->term/term-e rhs term-e eqs lang))
(define lhs-term (pat->term/term-e lhs term-e eqs lang))
(not (equal? rhs-term lhs-term)))
(define (check-dq the-dq term-e lang eqs)
(match-define (dq ps `(,lhs ,rhs)) the-dq)
(define rhs-term (pat->term/term-e ps rhs term-e eqs lang))
(define lhs-term (pat->term/term-e ps lhs term-e eqs lang))
(not (compare-partial-terms rhs-term lhs-term)))
(define (pat->term/term-e t term-e actual-e lang)
(define (pat->term/term-e ps t term-e actual-e lang)
(call/ec
(λ (fail)
(let recur ([p t])
(match p
[`(name ,var ,(bound))
(if (hash-has-key? term-e (lvar var))
(recur (hash-ref term-e (lvar var)))
(cond
[(member var ps)
`(name ,var ,(bound))]
[(hash-has-key? term-e (lvar var))
(recur (hash-ref term-e (lvar var)))]
[else
(let ([new-val (recur (hash-ref actual-e (lvar var)))])
(hash-set! term-e (lvar var) new-val)
new-val))]
new-val)])]
[`(cstr (,nts ...) ,pat)
(recur pat)]
[`(list ,ps ...)
@ -109,6 +112,37 @@
(let-values ([(p bs) (gen-term p lang 2)])
p)])))))
(define (compare-partial-terms l r)
(define param-vals (hash))
(define (update-param-vals p v)
(set! param-vals
(hash-set param-vals p
(set-add (hash-ref param-vals p (λ () (set))) v))))
(and
(let recur ([l l]
[r r])
(match* (l r)
[(`(name ,lv ,(bound)) `(name ,rv ,(bound)))
(update-param-vals lv r)
(update-param-vals rv l)
#t]
[(`(name ,lv ,(bound)) _)
(update-param-vals lv r)
#t]
[(_ `(name ,rv ,(bound)))
(update-param-vals rv l)
#t]
[(`(,l-ts ...) `(,r-ts ...))
(and (= (length l-ts) (length r-ts))
(for/and ([lt l-ts]
[rt r-ts])
(recur lt rt)))]
[(_ _)
(equal? l r)]))
;; TODO: handle case where param appears twice against different stuff
(for/and ([vs (in-list (hash-values param-vals))])
((set-count vs) . < . 2))))
(define (gen-term pat lang size [num-atts 1] [retries 100])
(((rg:compile lang 'what) pat) size num-atts retries))
@ -128,3 +162,4 @@
(lookup new-id env)]
[else
(values (lvar id) res)]))

View File

@ -1382,7 +1382,7 @@
(if in-judgment-form?
(let-values ([(term-rws mf-cs) (rewrite-terms (list #'rest) ns)])
(values (append mf-cs ps-rw)
(cons #`(dqn #f '#,(car term-rws)) eqs)
(cons #`(dqn '() #f '#,(car term-rws)) eqs)
ns))
(values ps-rw eqs ns))]
[(prem-name . prem-body)

View File

@ -23,10 +23,10 @@
pat*-clause-p?s
bind-names
remove-empty-dqs
unif-fail
(struct-out unif-fail)
dq)
;(require racket/trace)
;;
;; atom := `any | `number | `string | `integer | `boolean | `real | `variable | `variable-not-otherwise-mentioned
;; var := symbol?
@ -213,16 +213,49 @@
(filter (λ (dq) (not (equal? base-dq dq)))
dqs))
(define (extend-dq eqs ineq0)
(define (extend-dq new-eqs ineq0 eqs)
(for/fold ([ineq ineq0])
([(k v) (in-hash eqs)])
([(k v) (in-hash new-eqs)])
(match ineq
[`((list ,vars ...) (list ,terms ...))
(match* (k v)
[((lvar id-l) (lvar id-r))
`((list ,@vars (name ,id-l ,(bound))) (list ,@terms (name ,id-r ,(bound))))]
`((list ,@vars (name ,id-l ,(bound)))
(list ,@terms ,(resolve-no-nts/var v eqs)))]
[((lvar id-l) pat*-r)
`((list ,@vars (name ,id-l ,(bound))) (list ,@terms ,pat*-r))])])))
`((list ,@vars (name ,id-l ,(bound)))
(list ,@terms ,(resolve-no-nts/pat v eqs)))])])))
(define (resolve-no-nts/var lv eqs)
(define-values (rep pat) (lookup (lvar-id lv) eqs))
(if (not (groundable? pat))
`(name ,(lvar-id rep) ,(bound))
(resolve-no-nts/pat pat eqs)))
(define (resolve-no-nts/pat pat eqs)
(let recur ([p pat])
(match p
[`(name ,id ,(bound))
(resolve-no-nts/var (lvar id) eqs)]
[`(list ,ps ...)
`(list ,@(for/list ([p ps]) (recur p)))]
[`(cstr (,cs ...) p)
(recur p)]
[else
(unless (groundable? p)
(error 'resolve/termable-pat
"non-termable pat at internal pattern position: ~s" p))
p])))
(define (groundable? p)
(match p
[`(nt ,_) #f]
[(? predef-pat? _) #f]
[`(cstr ,_ ,p)
(groundable? p)]
[else #t]))
(define (hash/mut->imm h0)
(for/fold ([h (hash)])
@ -265,7 +298,7 @@
[(empty? (hash-keys (new-eqs))) #f]
[else
(define-values (new-ps new-dq)
(param-elim params (extend-dq (new-eqs) base-dq)))
(param-elim params (extend-dq (new-eqs) base-dq eqs)))
(match new-dq
[`((list) (list))
#f]
@ -641,9 +674,3 @@
[else
(values (lvar id) res)]))
;(trace disunify*)

View File

@ -1300,7 +1300,7 @@
(syntax->list #'(lhs-names ...))
(syntax->list #'(lhs-namess/ellipses ...))
(syntax->list (syntax (rhs/wheres ...))))]
[((gen-clause lhs-pat) ...)
[((gen-clause lhs-pat lhs-ps/pat*) ...)
(make-mf-clauses (syntax->list #'(lhs ...))
(syntax->list #'(rhs ...))
(syntax->list #'((stuff ...) ...))
@ -1322,7 +1322,9 @@
#,(if prev-metafunction
#`(metafunc-proc-cases #,(term-fn-get-id (syntax-local-value prev-metafunction)))
#'null)]
[new-lhs-pats '(lhs-pat ...)])
[new-lhs-pats '(lhs-pat ...)]
[new-lhs-ps/pats '(lhs-ps/pat* ...)])
(build-metafunction
lang
cases
@ -1348,7 +1350,7 @@
#`(extend-mf-clauses #,(term-fn-get-id (syntax-local-value prev-metafunction))
(λ ()
#,(check-pats #'(list gen-clause ...)))
new-lhs-pats)]
new-lhs-ps/pats)]
[else
#`(memoize0
(λ ()
@ -1367,14 +1369,16 @@
(define (extend-lhs-pats old-m new-pats)
(append new-pats (metafunc-proc-lhs-pats old-m)))
(define (extend-mf-clauses old-mf new-clauses new-lhs-pats)
(define (extend-mf-clauses old-mf new-clauses new-lhs-ps/pats)
(memoize0
(λ ()
(define old-clauses
(for/list ([old-clauses (in-list ((metafunc-proc-gen-clauses old-mf)))]
[old-lhs-pat (in-list (metafunc-proc-lhs-pats old-mf))])
(define new-dqs (for/list ([new-lhs-pat (in-list new-lhs-pats)])
(dqn old-lhs-pat new-lhs-pat)))
(define new-dqs (for/list ([new-lhs-ps/pat (in-list new-lhs-ps/pats)])
(dqn (first new-lhs-ps/pat)
old-lhs-pat
(second new-lhs-ps/pat))))
(struct-copy clause old-clauses
[eq/dqs
(append
@ -1393,30 +1397,30 @@
ans)))
(define-for-syntax (make-mf-clauses lhss rhss extrass nts err-name name lang)
(define-values (rev-clauses _)
(for/fold ([clauses '()]
[prev-lhs-pats '()]) ([lhs (in-list lhss)]
[rhs (in-list rhss)]
[extras (in-list extrass)])
(with-syntax ([(lhs-pat (names ...) (names/ellipses ...)) (rewrite-side-conditions/check-errs nts err-name #t lhs)])
(define-values (rev-clauses _1 _2)
(for/fold ([clauses '()] [prev-lhs-pats '()] [prev-lhs-pats* '()])
([lhs (in-list lhss)] [rhs (in-list rhss)] [extras (in-list extrass)])
(with-syntax* ([(lhs-pat (names ...) (names/ellipses ...)) (rewrite-side-conditions/check-errs nts err-name #t lhs)]
[((lhs-pat-ps* ...) lhs-pat*) (fix-and-extract-dq-vars #'lhs-pat)])
(define-values (ps-rw extra-eqdqs p-names)
(rewrite-prems #f (syntax->list extras) nts (syntax->datum #'(names ...)) 'define-metafunction))
(define-values (rhs-pats mf-clausess) (rewrite-terms (list rhs) p-names))
(define clause-stx
(with-syntax ([(prem-rw ...) ps-rw]
[(eqs ...) extra-eqdqs]
[(((lhs-pat-ps ...) prev-lhs-pat) ...)
(map fix-and-extract-dq-vars prev-lhs-pats)]
[(((prev-lhs-pat-ps ...) prev-lhs-pat) ...) prev-lhs-pats*]
[(mf-clauses ...) mf-clausess]
[(rhs-pat) rhs-pats])
#`((clause '(list lhs-pat rhs-pat)
(list eqs ... (dqn '(lhs-pat-ps ...) 'prev-lhs-pat 'lhs-pat) ...)
(list eqs ... (dqn '(prev-lhs-pat-ps ...) 'prev-lhs-pat 'lhs-pat) ...)
(list prem-rw ... mf-clauses ...)
#,lang
'#,name)
lhs-pat)))
lhs-pat
((lhs-pat-ps* ...) lhs-pat*))))
(values (cons clause-stx clauses)
(cons #'lhs-pat prev-lhs-pats)))))
(cons #'lhs-pat prev-lhs-pats)
(cons #'((lhs-pat-ps* ...) lhs-pat*) prev-lhs-pats*)))))
(reverse rev-clauses))
(define-for-syntax (fix-and-extract-dq-vars pat)
@ -1426,12 +1430,11 @@
[(name vname p)
(with-syntax ([((vs ...) new-p) (recur #'p)]
[new-vn (datum->syntax #'vname
(let* ([vn (syntax-e #'vname)]
[vn-sym (format "~s_" vn)])
(let ([vn (syntax-e #'vname)])
(hash-ref new-ids vn
(λ ()
(define new
(syntax-e (generate-temporary vn-sym)))
(syntax-e (generate-temporary (format "~s_" vn))))
(set! new-ids (hash-set new-ids vn new))
new)))
#'vname)])

View File

@ -8,35 +8,44 @@
bound
lvar))
(define-syntax-rule (is-not-false e)
(test-equal (not e) #f))
(define-syntax-rule (is-false e)
(test-equal e #f))
(let ()
(define-language L0)
(test-equal (check-dq `a `a (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `a `a)) (make-hash) L0 (hash))
#f)
(test-equal (check-dq `a `b (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `a `b)) (make-hash) L0 (hash))
#t)
(test-equal (check-dq `(list a) `(list a) (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `(list a) `(list a))) (make-hash) L0 (hash))
#f)
(test-equal (check-dq `(list a) `(list b) (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `(list a) `(list b))) (make-hash) L0 (hash))
#t)
(test-equal (check-dq `(list number) `(list variable) (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `(list number) `(list variable))) (make-hash) L0 (hash))
#t)
(test-equal (check-dq `(list a) `(list number) (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `(list a) `(list number))) (make-hash) L0 (hash))
#t)
(test-equal (check-dq `(list 2) `(list variable-not-otherwise-mentioned) (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `(list 2) `(list variable-not-otherwise-mentioned))) (make-hash) L0 (hash))
#t)
(test-equal (check-dq `(list a b) `(list a number) (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `(list a b) `(list a number))) (make-hash) L0 (hash))
#t)
(test-equal (check-dq `(list a b) `(list a b) (make-hash) L0 (hash))
(test-equal (check-dq (dq '() (list `(list a b) `(list a b))) (make-hash) L0 (hash))
#f)
(test-equal (check-dq `(list (name a ,(bound)))
`(list (name a ,(bound)))
(test-equal (check-dq (dq '()
(list `(list (name a ,(bound)))
`(list (name a ,(bound)))))
(make-hash)
L0
(hash (lvar 'a) 'number))
#f)
(test-equal (check-dq `(name a ,(bound))
`(name b ,(bound))
(test-equal (check-dq (dq '()
(list `(name a ,(bound))
`(name b ,(bound))))
(make-hash (list (cons (lvar 'a) '(1 2 3))
(cons (lvar 'b) '(1 2 3))))
L0
@ -151,26 +160,6 @@
#t)
)
(let ()
(define-language STLC
(τ int
(τ τ))
(Γ ([x τ] Γ)
)
(x variable-not-otherwise-mentioned))
(define-metafunction STLC
[(lookup x ([x τ] Γ))
τ]
[(lookup x ([x_1 τ] Γ))
(lookup x Γ)])
(test-equal (generate-term STLC
#:satisfying
(lookup x ([x int] ([x (int int)] ))) = (int int)
6)
#f))
(let ()
(define-language simple
@ -281,6 +270,12 @@
(typ-if Γ e_2 τ)
(typ-if Γ e_3 τ)])
(test-equal (generate-term STLC
#:satisfying
(lookup x ([x int] ([x (int int)] ))) = (int int)
6)
#f)
(test-equal (judgment-holds (typeof ([x_1 int] ([x_1 (int int)] )) (x_1 5) int))
#f)
(test-equal (judgment-holds (typeof ([x_2 int] ([x_1 (int int)] )) (x_1 5) int))
@ -404,6 +399,19 @@
(test-equal (generate-term L #:satisfying (is-a/b? c) = any +inf.0)
'((is-a/b? c) = F))
(test-equal (generate-term L #:satisfying (is-a? a) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a? b) = T +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a? c) = T +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b? a) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b? b) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b? c) = T +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? a) = any +inf.0)
'((is-a/b/c/d/e? a) = T))
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? b) = any +inf.0)
@ -415,7 +423,20 @@
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? e) = any +inf.0)
'((is-a/b/c/d/e? e) = T))
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? f) = any +inf.0)
'((is-a/b/c/d/e? f) = F)))
'((is-a/b/c/d/e? f) = F))
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? a) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? b) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? c) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? d) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? e) = F +inf.0)
#f)
(test-equal (generate-term L #:satisfying (is-a/b/c/d/e? f) = T +inf.0)
#f))
;; errors for unsupprted pats
(let ()
@ -608,11 +629,6 @@
(let ()
(define-syntax-rule (is-not-false e)
(test-equal (not e) #f))
(define-syntax-rule (is-false e)
(test-equal e #f))
(define-language L0)
@ -659,3 +675,39 @@
(is-false (generate-term L0 #:satisfying (J ((1) (#f))) 5))
(is-false (generate-term L0 #:satisfying (J ((#f) (2))) 5))
(is-not-false (generate-term L0 #:satisfying (J ((#t) (2))) 5)))
(let ()
(define-language L0)
(define-metafunction L0
[(f (any_1 any_2))
2]
[(f any_1)
1])
(define-judgment-form L0
#:mode (J I I)
[(J (any_1 any_2) 2)]
[(J any_1 1)])
(test-equal (generate-term L0
#:satisfying
(f (any_1 any_2)) = 1
+inf.0)
#f)
(test-equal (not
(generate-term L0
#:satisfying
(f (any_1 any_2)) = 2
+inf.0))
#f)
(is-not-false
(for/and ([_ 50])
(match (generate-term L0
#:satisfying
(f any) = 1
5)
[`((f (,a ,b)) = 1) #f]
[else #t]))))

View File

@ -1091,6 +1091,19 @@
(,(lvar 'd) . (nt Q)))
'() #f)
;; resolve fully
;; (necessary for parameter elimination to be correct)
(check-not-false
(env-equal?
(disunify
'(a)
'(list (name a any) (name a any))
'(list (name b any) 2)
(env '#hash() '())
#f)
(env (hash (lvar 'a) 'any (lvar 'b) 'any)
(list (dq '() `((list (name b ,(bound))) (list 2)))))))
(let ([untested