git @ Cat's Eye Technologies Treacle / master src / unifier.scm
master

Tree @master (Download .tar.gz)

unifier.scm @masterraw · history · blame

;
; Support for matching of patterns containing contexts (holes)
; Chris Pressey, March 2008
;

; Copyright (c)2008 Cat's Eye Technologies.  All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
;
; 1. Redistributions of source code must retain the above copyright
;    notices, this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
;    notices, this list of conditions, and the following disclaimer in
;    the documentation and/or other materials provided with the
;    distribution.
; 3. Neither the names of the copyright holders nor the names of their
;    contributors may be used to endorse or promote products derived
;    from this software without specific prior written permission. 
;
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
; FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
; POSSIBILITY OF SUCH DAMAGE.

;
; A traditional unifier is a set of (variable name, value) pairs indicating
; what value is bound to each variable name.  In our case, unifiers contain
; (name, term index) pairs which bind named to indices into the subject term.
; In a sense, conventional unifiers are unifiers "by value" while Treacle's
; are unifiers "by reference".
;
; Note also that in these unifiers, the same name can be bound to *multiple*
; positions within the subject, since the name may occur in any number of
; positions in the pattern, and will match as long as those subterms are
; equivalent.
;

;
; Create and return a new, empty unifier.
;
(define mk-empty-unifier
  (lambda ()
    '()))

;
; Extend the given unifier to one where the given name is associated with
; the given term index in the given subject term.  If such an extension is
; not possible (i.e. the name is already bound to an inequivalent term at
; a different index in the subject,) then #f is returned.
;
(define bind-name
  (lambda (subject index name unifier)
    (if (scour-unifier? subject index name unifier)
      (cons (cons name index) unifier)
      #f)))

;
; Helper function for bind-name.  Returns #t if it's OK to extend the
; unifier with the given name->index association, #f otherwise
;
(define scour-unifier?
  (lambda (subject index name unifier)
    (cond
      ((null? unifier)
        #t)
      (else
        (let* ((pair        (car unifier))
               (bound-name  (car pair))
               (bound-index (cdr pair)))
          (cond
            ((not (eq? name bound-name))
              (scour-unifier? subject index name (cdr unifier)))
            ((eqv? index bound-index) ; already bound to same place: ok
              (scour-unifier? subject index name (cdr unifier)))
            ((eqv? (term-index-fetch subject index) ; already bound to equiv
                   (term-index-fetch subject (cdr pair))) ; term: alright
              (scour-unifier? subject index name (cdr unifier)))
            (else                ; already bound to something else: not good
              #f)))))))

;
; Given a subject, a replacement, and a unifier, return a term which is like
; the replacement except where where each of the placeholders in the replacement
; has been replaced by the associated term referenced in the unifier.
;
(define expand-vars
  (lambda (subject replacement unifier generation-id)
    (cond ((is-named? replacement)      ; variable - replace if in unifier
            (let* ((pair (assq (get-name replacement) unifier)))
              (cond ((pair? pair)
                      (term-index-fetch subject (cdr pair)))
                    (else
                      replacement))))
          ((is-newref? replacement)
            (string->symbol (string-append "unique-ref-" (number->string generation-id))))
          ((list? replacement)          ; list - recurse
            (map (lambda (subpattern)
                   (expand-vars subject subpattern unifier generation-id))
                 replacement))
          (else                         ; ground term - leave it alone.
            replacement))))