racket/collects/racklog/unify.rkt
2012-08-27 15:13:18 -06:00

554 lines
17 KiB
Racket

#lang racket/base
(require (for-syntax racket/base)
racket/list
racket/match
racket/function
racket/vector
racket/set)
(provide (all-defined-out))
; same hash
(define (make-immutable-hash*) (make-immutable-hash empty))
(define (make-immutable-hasheqv*) (make-immutable-hasheqv empty))
(define (make-immutable-hasheq*) (make-immutable-hasheq empty))
(define (same-hash-make ht)
(match ht
[(? immutable?)
(match ht
[(? hash-equal?) make-immutable-hash*]
[(? hash-eqv?) make-immutable-hasheqv*]
[(? hash-eq?) make-immutable-hasheq*])]
[(? hash-weak?)
(match ht
[(? hash-equal?) make-weak-hash]
[(? hash-eqv?) make-weak-hasheqv]
[(? hash-eq?) make-weak-hasheq])]
[_
(match ht
[(? hash-equal?) make-hash]
[(? hash-eqv?) make-hasheqv]
[(? hash-eq?) make-hasheq])]))
(define (same-hash-kind? x y)
(eq? (same-hash-make x) (same-hash-make y)))
(define (same-hash-map f ht)
(define new-ht ((same-hash-make ht)))
(if (immutable? ht)
(for/fold ([new-ht new-ht])
([(k v) (in-hash ht)])
(hash-set new-ht k (f v)))
(begin
(for ([(k v) (in-hash ht)])
(hash-set! new-ht k (f v)))
new-ht)))
; compound structs
(require unstable/sequence)
(define (in-compound-struct s)
(define-values (stype _) (struct-info s))
(define-values (name init-field-cnt auto-field-cnt accessor-proc mutator-proc immutable-k-list super-type skipped?) (struct-type-info stype))
(define total-field-cnt (+ init-field-cnt)
#;(compound-struct-type-field-cnt stype))
(sequence-lift (curry accessor-proc s) (in-range total-field-cnt)))
(define (compound-struct-map f s)
(define-values (stype _) (struct-info s))
(define make (struct-type-make-constructor stype))
(apply make
(for/list ([e (in-compound-struct s)])
(f e))))
(define (compound-struct-ormap f s)
(for/or ([e (in-compound-struct s)])
(f e)))
(define (compound-struct-andmap f s)
(for/and ([e (in-compound-struct s)])
(f e)))
(define (compound-struct-same? x y)
(define-values (xtype _) (struct-info x))
((struct-type-make-predicate xtype) y))
(define (compound-struct-cmp x y =)
(and (compound-struct-same? x y)
(for/and ([ex (in-compound-struct x)]
[ey (in-compound-struct y)])
(= ex ey))))
(define-struct logic-var (val) #:mutable)
(define *unbound* '_)
;;unbound refs point to themselves
(define (make-ref [val *unbound*])
(make-logic-var val))
(define _ make-ref)
(define (unbound-logic-var? r)
(and (logic-var? r) (eq? (logic-var-val r) *unbound*)))
(define (unbind-ref! r)
(set-logic-var-val! r *unbound*))
(define-struct frozen (val))
(define (freeze-ref r)
(make-ref (make-frozen r)))
(define (thaw-frozen-ref r)
(frozen-val (logic-var-val r)))
(define (frozen-logic-var? r)
(frozen? (logic-var-val r)))
(define-syntax (uni-match stx)
(syntax-case
stx (? logic-var? cons mcons box vector? hash? compound-struct? atom? else)
[(_ v
[(? logic-var? lv) logic-var-expr ...]
[(cons cl cr) cons-expr ...]
[(mcons mcl mcr) mcons-expr ...]
[(box bv) box-expr ...]
[(? vector? vec) vector-expr ...]
[(? hash? hash) hash-expr ...]
[(? compound-struct? cs) cs-expr ...]
[(? atom? x) atom-expr ...])
(syntax/loc stx
(match v
[(? logic-var? lv) logic-var-expr ...]
[(cons cl cr) cons-expr ...]
[(mcons mcl mcr) mcons-expr ...]
[(box bv) box-expr ...]
[(? vector? vec) vector-expr ...]
[(? hash? hash) hash-expr ...]
[(? compound-struct? cs) cs-expr ...]
[(? atom? x) atom-expr ...]))]
[(_ v
[(? logic-var? lv) logic-var-expr ...]
[(cons cl cr) cons-expr ...]
[(mcons mcl mcr) mcons-expr ...]
[(box bv) box-expr ...]
[(? vector? vec) vector-expr ...]
[(? hash? hash) hash-expr ...]
[(? compound-struct? cs) cs-expr ...]
[(? atom? x) atom-expr ...]
[else else-expr ...])
(syntax/loc stx
(match v
[(? logic-var? lv) logic-var-expr ...]
[(cons cl cr) cons-expr ...]
[(mcons mcl mcr) mcons-expr ...]
[(box bv) box-expr ...]
[(? vector? vec) vector-expr ...]
[(? hash? hash) hash-expr ...]
[(? compound-struct? cs) cs-expr ...]
[(? atom? x) atom-expr ...]
[else else-expr ...]))]))
(define (logic-var-val* v)
(uni-match
v
[(? logic-var? s)
(if (frozen-logic-var? s) s
(logic-var-val* (logic-var-val s)))]
[(cons l r)
(cons (logic-var-val* l) (logic-var-val* r))]
[(mcons l r)
(mcons (logic-var-val* l) (logic-var-val* r))]
[(box v) (box (logic-var-val* v))]
[(? vector? v)
(vector-map logic-var-val* v)]
[(? hash? v) (same-hash-map logic-var-val* v)]
[(? compound-struct? v) (compound-struct-map logic-var-val* v)]
[(? atom? s) s]))
(define use-occurs-check? (make-parameter #f))
(define (occurs-in? var term)
(and (use-occurs-check?)
(let loop ([term term])
(or (eqv? var term)
(uni-match
term
[(? logic-var? term)
(cond [(unbound-logic-var? term) #f]
[(frozen-logic-var? term) #f]
[else (loop (logic-var-val term))])]
[(cons l r)
(or (loop l) (loop r))]
[(mcons l r)
(or (loop l) (loop r))]
[(box v) (loop v)]
[(? vector? v)
(for/or ([e (in-vector v)]) (loop e))]
[(? hash? ht)
(for/or ([(k v) (in-hash ht)]) (or (loop k) (loop v)))]
[(? compound-struct? cs) (compound-struct-ormap loop cs)]
[(? atom? x) #f])))))
(define (constant? x)
(uni-match
x
[(? logic-var? x)
(cond [(unbound-logic-var? x) #f]
[(frozen-logic-var? x) #t]
[else (constant? (logic-var-val x))])]
[(cons l r) #f]
[(mcons l r) #f]
[(box v) #f]
[(? vector? v) #f]
[(? hash? v) #f]
[(? compound-struct? v) #f]
[(? atom? x) #t]))
(define (is-compound? x)
(uni-match
x
[(? logic-var? x)
(cond [(unbound-logic-var? x) #f]
[(frozen-logic-var? x) #f]
[else (is-compound? (logic-var-val x))])]
[(cons l r) #t]
[(mcons l r) #t]
[(box v) #t]
[(? vector? v) #t]
[(? hash? v) #t]
[(? compound-struct? v) #t]
[(? atom? x) #f]))
(define (var? x)
(uni-match
x
[(? logic-var? x)
(cond [(unbound-logic-var? x) #t]
[(frozen-logic-var? x) #f]
[else (var? (logic-var-val x))])]
[(cons l r) (or (var? l) (var? r))]
[(mcons l r) (or (var? l) (var? r))]
[(box v) (var? v)]
[(? vector? v)
(for/or ([e (in-vector v)]) (var? e))]
[(? hash? ht)
(for/or ([(k v) (in-hash ht)]) (var? v))]
[(? compound-struct? cs) (compound-struct-ormap var? cs)]
[(? atom? x) #f]))
(define (freeze v)
(define dict (make-hasheq))
(define (loop s)
(uni-match
s
[(? logic-var? s)
(if (or (unbound-logic-var? s) (frozen-logic-var? s))
(hash-ref! dict s
(lambda ()
(freeze-ref s)))
(loop (logic-var-val s)))]
[(cons l r)
(cons (loop l) (loop r))]
[(mcons l r)
(mcons (loop l) (loop r))]
[(box v) (box (loop v))]
[(? vector? v)
(vector-map loop v)]
[(? hash? v)
(same-hash-map loop v)]
[(? compound-struct? cs) (compound-struct-map loop cs)]
[(? atom? s) s]))
(loop v))
(define (melt f)
(uni-match
f
[(? logic-var? f)
(cond [(unbound-logic-var? f) f]
[(frozen-logic-var? f) (thaw-frozen-ref f)]
[else (melt (logic-var-val f))])]
[(cons l r)
(cons (melt l) (melt r))]
[(mcons l r)
(mcons (melt l) (melt r))]
[(box v) (box (melt v))]
[(? vector? v)
(vector-map melt v)]
[(? hash? v)
(same-hash-map melt v)]
[(? compound-struct? cs) (compound-struct-map melt cs)]
[(? atom? s) s]))
(define (melt-new f)
(define dict (make-hasheq))
(define (loop s)
(uni-match
s
[(? logic-var? f)
(cond [(unbound-logic-var? f) f]
[(frozen-logic-var? f)
(hash-ref! dict f _)]
[else (loop (logic-var-val f))])]
[(cons l r)
(cons (loop l) (loop r))]
[(mcons l r)
(mcons (loop l) (loop r))]
[(box v) (box (loop v))]
[(? vector? v)
(vector-map loop v)]
[(? hash? v)
(same-hash-map loop v)]
[(? compound-struct? cs)
(compound-struct-map loop cs)]
[(? atom? s) s]))
(loop f))
(define (copy s)
(melt-new (freeze s)))
(define (ident? x y)
(uni-match
x
[(? logic-var? x)
(cond [(unbound-logic-var? x)
(cond [(logic-var? y)
(cond [(unbound-logic-var? y) (eq? x y)]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[else #f])]
[(frozen-logic-var? x)
(cond [(logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) (eq? x y)]
[else (ident? x (logic-var-val y))])]
[else #f])]
[else (ident? (logic-var-val x) y)])]
[(cons xl xr)
(uni-match
y
[(? logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[(cons yl yr)
(and (ident? xl yl) (ident? xr yr))]
[(mcons yl yr) #f]
[(box v) #f]
[(? vector? y) #f]
[(? hash? y) #f]
[(? compound-struct? y) #f]
[(? atom? y) #f])]
[(mcons xl xr)
(uni-match
y
[(? logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[(cons yl yr) #f]
[(mcons yl yr)
(and (ident? xl yl) (ident? xr yr))]
[(box v) #f]
[(? vector? y) #f]
[(? hash? y) #f]
[(? compound-struct? y) #f]
[(? atom? y) #f])]
[(box xv)
(uni-match
y
[(? logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[(cons yl yr) #f]
[(mcons yl yr) #f]
[(box yv) (ident? xv yv)]
[(? vector? y) #f]
[(? hash? y) #f]
[(? compound-struct? y) #f]
[(? atom? y) #f])]
[(? vector? x)
(uni-match
y
[(? logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[(cons yl yr) #f]
[(mcons yl yr) #f]
[(box v) #f]
[(? vector? y)
(if (= (vector-length x)
(vector-length y))
(for/and ([xe (in-vector x)]
[ye (in-vector y)])
(ident? xe ye))
#f)]
[(? hash? y) #f]
[(? compound-struct? y) #f]
[(? atom? y) #f])]
[(? hash? x)
(uni-match
y
[(? logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[(cons yl yr) #f]
[(mcons yl yr) #f]
[(box v) #f]
[(? vector? y) #f]
[(? hash? y)
(and (same-hash-kind? x y)
(= (hash-count x) (hash-count y))
(for/and ([(xk xv) (in-hash x)])
; XXX not using ident? for key comparison
(and (hash-has-key? y xk)
(ident? xv (hash-ref y xk)))))]
[(? compound-struct? y) #f]
[(? atom? y) #f])]
[(? compound-struct? x)
(uni-match
y
[(? logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[(cons yl yr) #f]
[(mcons yl yr) #f]
[(box v) #f]
[(? vector? y) #f]
[(? hash? y) #f]
[(? compound-struct? y)
(compound-struct-cmp x y ident?)]
[(? atom? y) #f])]
[(? atom? x)
(uni-match
y
[(? logic-var? y)
(cond [(unbound-logic-var? y) #f]
[(frozen-logic-var? y) #f]
[else (ident? x (logic-var-val y))])]
[(cons yl yr) #f]
[(mcons yl yr) #f]
[(box v) #f]
[(? vector? y) #f]
[(? hash? y) #f]
[(? compound-struct? y) #f]
[(? atom? y) (eqv? x y)])]))
(define (unify t1 t2)
(define iu (inner-unify t1 t2))
(λ (fk)
(define-values (cleanup k)
(iu fk))
k))
(define (inner-unify t1 t2)
(lambda (fk)
(define (cleanup s)
(for-each unbind-ref! s))
(define (cleanup-n-fail s)
(cleanup s)
(fk 'fail))
(define (unify1 t1 t2 s)
(cond [(eqv? t1 t2) s]
[(logic-var? t1)
(cond [(unbound-logic-var? t1)
(cond [(occurs-in? t1 t2)
(cleanup-n-fail s)]
[else
(set-logic-var-val! t1 t2)
(list* t1 s)])]
[(frozen-logic-var? t1)
(cond [(logic-var? t2)
(cond [(unbound-logic-var? t2)
(unify1 t2 t1 s)]
[(frozen-logic-var? t2)
(cleanup-n-fail s)]
[else
(unify1 t1 (logic-var-val t2) s)])]
[else (cleanup-n-fail s)])]
[else
(unify1 (logic-var-val t1) t2 s)])]
[(logic-var? t2) (unify1 t2 t1 s)]
[(and (pair? t1) (pair? t2))
(unify1 (cdr t1) (cdr t2)
(unify1 (car t1) (car t2) s))]
[(and (mpair? t1) (mpair? t2))
(unify1 (mcdr t1) (mcdr t2)
(unify1 (mcar t1) (mcar t2) s))]
[(and (box? t1) (box? t2))
(unify1 (unbox t1) (unbox t2) s)]
[(and (vector? t1) (vector? t2))
(if (= (vector-length t1)
(vector-length t2))
(for/fold ([s s])
([v1 (in-vector t1)]
[v2 (in-vector t2)])
(unify1 v1 v2 s))
(cleanup-n-fail s))]
[(and (hash? t1) (hash? t2))
(if (and (same-hash-kind? t1 t2)
(= (hash-count t1) (hash-count t2)))
(for/fold ([s s])
([(xk xv) (in-hash t1)])
(if (hash-has-key? t2 xk)
(unify1 xv (hash-ref t2 xk) s)
(cleanup-n-fail s)))
(cleanup-n-fail s))]
[(and (compound-struct? t1) (compound-struct? t2))
(if (compound-struct-same? t1 t2)
(for/fold ([s s])
([e1 (in-compound-struct t1)]
[e2 (in-compound-struct t2)])
(unify1 e1 e2 s))
(cleanup-n-fail s))]
[(and (atom? t1) (atom? t2))
(if (equal? t1 t2) s
(cleanup-n-fail s))]
[else
(cleanup-n-fail s)]))
(define s (unify1 t1 t2 empty))
(values
(λ () (cleanup s))
(lambda (d)
(cleanup-n-fail s)))))
(define-syntax-rule (or* x f ...)
(or (f x) ...))
(define (atomic-struct? v)
(not (compound-struct? v)))
(define (compound-struct? v)
(let-values ([(stype skipped?) (struct-info v)])
(and stype (not skipped?))))
(define (atom? x)
(or* x boolean? number? string? bytes? char? symbol?
regexp? pregexp? byte-regexp? byte-pregexp?
keyword? null? procedure? void? set?
atomic-struct?))
(define (compound? x)
(or* x pair? vector? mpair? box? hash? compound-struct?))
(define (answer-value? x)
(uni-match
x
[(? logic-var? x) #f]
[(cons l r) (and (answer-value? l) (answer-value? r))]
[(mcons l r) (and (answer-value? l) (answer-value? r))]
[(box v) (answer-value? v)]
[(? vector? v) (for/and ([e (in-vector v)]) (answer-value? e))]
[(? hash? ht) (for/and ([(k v) (in-hash ht)]) (and (answer-value? k) (answer-value? v)))]
[(? compound-struct? cs) (compound-struct-andmap answer-value? cs)]
[(? atom? x) #t]
[else #f]))
(define answer?
(match-lambda
[#f #t]
[(list (cons (? symbol?) (? answer-value?)) ...) #t]
[_ #f]))
(define (unifiable? x)
(uni-match
x
[(? logic-var? x) #t]
[(cons l r) (and (unifiable? l) (unifiable? r))]
[(mcons l r) (and (unifiable? l) (unifiable? r))]
[(box v) (unifiable? v)]
[(? vector? v) (for/and ([e (in-vector v)]) (unifiable? e))]
[(? hash? ht) (for/and ([(k v) (in-hash ht)]) (and #;(answer-value? k) ; No constraint, but won't be used XXX
(unifiable? v)))]
[(? compound-struct? cs) (compound-struct-andmap unifiable? cs)]
[(? atom? x) #t]
[else #f]))