1 ;;;; -*- Mode: Lisp -*- 2 3 ;;;; substitutions.lisp -- 4 ;;;; General CL structures unifier. 5 ;;;; Substitution definitions. Mostly a rehash of the usual SICP stuff. 6 7 ;;;; See file COPYING for copyright licensing information. 8 9 (in-package "CL.EXT.DACF.UNIFICATION") ; DACF = Data And Control Flow. 10 11 ;;;--------------------------------------------------------------------------- 12 ;;; Bindings. 13 14 (deftype binding () 'cons) 15 16 (deftype bindings () 'list) ; An A-LIST. 17 18 (defun make-binding (variable value) 19 (cons variable value)) 20 21 (defun extend-bindings (variable value bindings) 22 (acons variable value bindings)) 23 24 25 (defun binding-variable (b) 26 (declare (type binding b)) 27 (car b)) 28 29 (defun (setf binding-variable) (v b) 30 (declare (type binding b)) 31 (setf (car b) v)) 32 33 34 (defun binding-value (b) 35 (declare (type binding b)) 36 (cdr b)) 37 38 39 (defun (setf binding-value) (v b) 40 (declare (type binding b)) 41 (setf (cdr b) v)) 42 43 44 (defun bindings-values (bindings) (mapcar #'cdr bindings)) 45 46 (defun bindings-keys (bindings) (mapcar #'car bindings)) 47 48 49 50 (define-condition unification-variable-unbound (unbound-variable) 51 () 52 ) 53 54 (define-condition unification-failure (simple-error) 55 ()) 56 57 58 ;;;--------------------------------------------------------------------------- 59 ;;; Frames. 60 61 (defstruct (frame (:constructor make-frame (&optional bindings))) 62 (bindings () :type bindings)) 63 64 (defun empty-frame-p (f) 65 (declare (type frame f)) 66 (null (frame-bindings f))) 67 68 69 (defun find-variable-binding-in-frame (v f) 70 (declare (type frame f)) 71 (assoc v (frame-bindings f))) 72 73 74 (defun find-variable-value-in-frame (v f) 75 (declare (type frame f)) 76 (let ((b (find-variable-binding-in-frame v f))) 77 (declare (type (or null binding) b)) 78 (if b 79 (values (cdr b) t) 80 (values nil nil)))) 81 82 (defun frame-variables (frame) 83 (mapcar 'binding-variable (frame-bindings frame))) 84 85 86 (defun frame-values (frame) 87 (mapcar 'binding-value (frame-bindings frame))) 88 89 90 ;;;--------------------------------------------------------------------------- 91 ;;; Environments. 92 93 (defstruct (environment (:print-object print-environment) 94 (:copier nil)) 95 (frames () :type list)) 96 97 (defun print-environment (env stream) 98 (if *print-readably* 99 (format stream "#S(ENVIRONMENT FRAMES ~S)" 100 (environment-frames env)) 101 (print-unreadable-object (env stream :type nil :identity t) 102 (format stream "~:[~;EMPTY ~]UNIFY ENVIRONMENT: ~D frame~:P" 103 (empty-environment-p env) 104 (list-length (environment-frames env)))))) 105 106 (deftype substitution () 'environment) 107 108 (defun substitution-p (x) (environment-p x)) 109 110 (defun first-frame (env) 111 (first (environment-frames env))) 112 113 114 (defun make-empty-environment () 115 (make-environment :frames (list (make-frame)))) 116 117 (defun copy-environment (env) 118 (declare (type environment env)) 119 (make-environment :frames (copy-list (environment-frames env)))) 120 121 (defun make-shared-environment (env &optional (pushp nil)) 122 (declare (type environment env)) 123 (make-environment :frames (if pushp 124 (cons (make-frame) (environment-frames env)) 125 (environment-frames env)))) 126 127 (defun push-frame (env) 128 (declare (type environment env)) 129 (push (make-frame) (environment-frames env))) 130 131 (defun pop-frame (env) 132 (declare (type environment env)) 133 (pop (environment-frames env))) 134 135 136 (defun make-expanded-environment (base-env) 137 (make-environment :frames (cons (make-frame) (environment-frames base-env)))) 138 139 (defun empty-environment-p (env) 140 (declare (type environment env)) 141 (let ((env-frames (environment-frames env))) 142 (declare (type list env-frames)) 143 (and (= 1 (list-length env-frames)) 144 (empty-frame-p (first env-frames))))) 145 146 (defparameter *null-environment* (make-empty-environment)) 147 148 149 (defun find-variable-value (variable &optional (env *null-environment*) errorp) 150 (declare (type environment env)) 151 (labels ((find-var-value (frames) 152 (cond (frames 153 (multiple-value-bind (val foundp) 154 (find-variable-value-in-frame variable (first frames)) 155 (if foundp 156 (values val t) 157 (find-var-value (rest frames))))) 158 (errorp 159 (error 'unification-variable-unbound :variable variable)) 160 (t (values nil nil)))) 161 ) 162 (find-var-value (environment-frames env)))) 163 164 165 166 (defun extend-environment (var pat &optional (env (make-empty-environment))) 167 (let ((first-frame (first-frame env))) 168 (setf (frame-bindings first-frame) 169 (extend-bindings var pat (frame-bindings first-frame))) 170 env)) 171 172 173 (defun fill-environment (vars pats &optional (env (make-empty-environment))) 174 (map nil (lambda (v p) (extend-environment v p env)) vars pats) 175 env) 176 177 178 (defun fill-environment* (vars-pats &optional (env (make-empty-environment))) 179 (loop for (v . p) in vars-pats do (extend-environment v p env)) 180 env) 181 182 183 (declaim (inline v?)) 184 (declaim (ftype (function (symbol &optional environment boolean) 185 (values t boolean)) 186 find-variable-value) 187 (ftype (function (symbol environment &optional boolean) 188 (values t boolean)) 189 v?)) 190 191 (defun v? (s env &optional (plain-symbol-p nil)) 192 (find-variable-value (if plain-symbol-p 193 (make-var-name s) 194 s) 195 env)) 196 197 198 (defun environment-variables (env) 199 (mapcan #'frame-variables (environment-frames env))) 200 201 (defun environment-values (env) 202 (mapcan #'frame-values (environment-frames env))) 203 204 205 ;;;--------------------------------------------------------------------------- 206 ;;; Simple debugging. 207 208 (defun dump-frame (f &optional (out *standard-output*)) 209 (declare (type frame f)) 210 (loop for (var . value) in (frame-bindings f) 211 do (format out "~&~A~VT= ~A~%" var 8 value)) 212 ) 213 214 (defun dump-environment (env &optional (out *standard-output*)) 215 (declare (type environment env)) 216 (if (empty-environment-p env) 217 (format out ">>> Empty unify environment ~S.~%" env) 218 (loop initially (format out ">>> Dumping unify environment ~S.~%" env) 219 for fr in (environment-frames env) 220 for fr-n downfrom (list-length (environment-frames env)) 221 do (format out ">>> Frame ~D:~%" fr-n) 222 do (dump-frame fr out) 223 do (terpri out) 224 ))) 225 226 ;;;; end of file -- substitutions.lisp --