;; Unify ;; Takes two FOL expressions and returns a list of substitutions. ;; FOL expressions can have: ;; not, and, or, var, forall, exists, and functions ;; (Predicates, Equality, and Functions are all treated identically) ;; ;; Returns the assignment (empty assignment means sentences are identical) ;; Returns the list ("Failed") on failiure. (defun unify (s1 s2 &optional (try2 nil)) (reverse ((lambda (assignment) ;; Cleanup: Check for failure. (if (member "Failed" assignment :test #'equal) (list "Failed") (do* ((a assignment (subst-fol a a)) ;; Make sure all assignments are in their final form. (b (subst-fol a a) (subst-fol a b))) ((equal a b) b)))) (if (equal s1 s2) nil (if (listp s1) (if (eq (car s1) 'var) ;; If s1 is a variable just set it to s2. (list (list (cadr s1) s2)) (if (listp s2) (if (= (length s1) (length s2)) ((lambda (a) (if (member "Failed" a :test #'equal) (unify-compound s2 s1) ;; Recalculate on failiure a)) (unify-compound s1 s2)) (if (not try2) (unify s2 s1 T) ;; Maybe s2 is a variable? (list "Failed"))))) (if (listp s2) (unify s2 s1) (list "Failed"))))))) ;; Helper function: ;; unify-compound unifies compound sentences/terms s1 and s2 ;; (both must be lists) (defun unify-compound (s1 s2) (if (and s1 s2) ((lambda (assignment) (append (unify-compound (subst-fol assignment (cdr s1)) (subst-fol assignment (cdr s2))) assignment)) (unify (car s1) (car s2))))) ;; Helper function: Applies a stubstituion based on an assignment to a sentence (defun subst-fol (assignment sentence) (if (and assignment sentence (listp sentence)) (if (eq (car sentence) 'var) ((lambda (x) (if x (cadar x) sentence)) (member (cadr sentence) assignment :test (lambda (a b) (eq a (car b))))) (cons (subst-fol assignment (car sentence)) (subst-fol assignment (cdr sentence)))) sentence ;; Nothing we can do here. ))