; ================================================== ; === programa: ENCADENAMIENTO REGRESIVO ; === probarlo asi: ; === * (back-chain '(robbie es leopardo)) ; === SI ; === * (back-chain '(suzie es albatros)) ; === SI ; === * (back-chain '(robbie es (? x))) ; === --> X = MAMIFERO ; === --> X = CARNIVORO ; === --> X = LEOPARDO ; === * (back-chain '((? animal) es (? x))) ; === --> ANIMAL = ROBBIE X = MAMIFERO ; === --> ANIMAL = SUZIE X = AVE ; === --> ANIMAL = ROBBIE X = CARNIVOR ; === --> ANIMAL = ROBBIE X = LEOPARDO ; === --> ANIMAL = SUZIE X = ALBATROS ; === autor: Jose Rafael Rodriguez Ochoa ; === fecha: enero / 1998 ; ================================================== ; ================================================== ; === comando: corresponde ; === funcion: match ; === fecha: enero / 1998 ; ================================================== (defun corresponde (p d &optional ligaduras) (cond ((elementos-p p d) (corresponde-atomos p d ligaduras)) ((variable-p p) (corresponde-variable p d ligaduras)) ((recursivos-p p d) (corresponde-partes p d ligaduras)) (t 'FAIL) ) ) ; ================================================== ; === comando: elementos-p ; === funcion: probar si ambos (p y d) son atomos ; === fecha: enero / 1998 ; ================================================== (defun elementos-p (p d) (and (atom p) (atom d)) ) ; ================================================== ; === comando: variable-p ; === funcion: probar si (p) es una lista y su ; === primer elemento es variable ; === fecha: enero / 1998 ; ================================================== (defun variable-p (p) (and (listp p) (eq '? (first p))) ) ; ================================================== ; === comando: recursivos-p ; === funcion: probar si (p y q) son listas ; === fecha: enero / 1998 ; ================================================== (defun recursivos-p (p d) (and (listp p) (listp d)) ) ; ================================================== ; === comando: corresponde-atomos ; === funcion: si (p y q) son iguales regresa ; === (ligaduras) sino FALLA ; === fecha: enero / 1998 ; ================================================== (defun corresponde-atomos (p d ligaduras) (if (eql p d) ligaduras 'FAIL) ) ; ================================================== ; === comando: corresponde-variable ; === funcion: verificar si se conoce la variable ; === de patron ; === de nuevo ; === si no, agrega nueva asociacion ; === fecha: enero / 1998 ; ================================================== (defun corresponde-variable (p d ligaduras) (let ((ligadura (encuentra-ligadura p ligaduras))) (if ligadura (corresponde (extrae-valor ligadura) d ligaduras) (agrega-ligadura p d ligaduras) ) ) ) ; ================================================== ; === comando: corresponde-partes ; === corresponden produciendo nuevas ligaduras ; === si no, FALLA ; === usando las ligaduras resultantes ; === fecha: enero / 1998 ; ================================================== (defun corresponde-partes (p d ligaduras) (let ((resultado (corresponde (first p) (first d) ligaduras))) (if (eq 'FAIL resultado) 'FAIL (corresponde (rest p) (rest d) resultado) ) ) ) ; ================================================== ; === comando: encuentra-ligadura ; === funcion: encontrar una ligadura ; === fecha: enero / 1998 ; ================================================== (defun encuentra-ligadura (expresion-variable-patron ligadura) (unless (eq '_ (extrae-variable expresion-variable-patron)) (assoc (extrae-variable expresion-variable-patron) ligadura) ) ) ; ================================================== ; === comando: agrega-ligadura ; === fecha: enero / 1998 ; ================================================== (defun agrega-ligadura (expresion-variable-patron dato ligaduras) (if (eq '_ (extrae-variable expresion-variable-patron)) ligaduras (cons (haz-ligadura (extrae-variable expresion-variable-patron) dato) ligaduras) ) ) ; ================================================== ; === comando: extrae-ligaduras ; === funcion: extraer una ligadura ; === fecha: enero / 1998 ; ================================================== (defun extrae-variable (exp-var-pat) (second exp-var-pat) ) ; ================================================== ; === comando: haz-ligadura ; === funcion: crear una ligadura con (var y dato) ; === fecha: enero / 1998 ; ================================================== (defun haz-ligadura (var dato) (list var dato) ) ; ================================================== ; === comando: recuerda-afirmacion ; === funcion: agregar nuevas afirmaciones al final ; === fecha: enero / 1998 ; ================================================== (defun recuerda-afirmacion (afirmacion) (recuerda-flujo afirmacion *afirmaciones*) ) ; ================================================== ; === comando: recuerda-regla ; === funcion: agregar nuevas reglas al final ; === fecha: enero / 1998 ; ================================================== (defun recuerda-regla (regla) (recuerda-flujo regla *reglas*) ) ; ================================================== ; === comando: recuerda-flujo ; === funcion: agregar nuevos flujos al final ; === fecha: enero / 1998 ; ================================================== (defmacro recuerda-flujo (objeto variable) `(unless (miembro-de-flujo ,objeto ,variable) (setf ,variable (agrega-a-flujo ,variable (construye-flujo ,objeto 'flujo-vacio))) ,objeto) ) ; ================================================== ; === comando: miembro-de-flujo ; === funcion: determinar si una cosa dada es un objeto en un flujo ; === fecha: enero / 1998 ; ================================================== (defun miembro-de-flujo (objeto flujo) (cond ((final-del-flujo-p flujo) nil) ((equal objeto (principio-del-flujo flujo)) t) (t (miembro-de-flujo objeto (resto-del-flujo flujo))) ) ) ; ================================================== ; === comando: agrega-a-flujo ; === funcion: agregar nuevos flujos al final ; === fecha: enero / 1998 ; ================================================== (defun agrega-a-flujo (flujo1 flujo2) (if (final-del-flujo-p flujo1) flujo2 (construye-flujo (principio-del-flujo flujo1) (agrega-a-flujo (resto-del-flujo flujo1) flujo2) ) ) ) ; ================================================== ; === comando: back-chain ; === en una respuesta atractiva. ; === fecha: enero / 1998 ; ================================================== (defun back-chain (&rest patrones) (let ((flujo-de-ligaduras (aplica-filtros patrones (construye-flujo nil 'flujo-vacio))) (variables (lista-variables patrones)) (respuestas-mostradas nil) ) (if (endp variables) (if (final-del-flujo-p flujo-de-ligaduras) 'no 'si) (do ((flujo-de-ligaduras flujo-de-ligaduras (resto-del-flujo flujo-de-ligaduras))) ((final-del-flujo-p flujo-de-ligaduras) 'no-mas) (let ((respuesta (haz-respuesta variables (principio-del-flujo flujo-de-ligaduras)))) (unless (member respuesta respuestas-mostradas :test #'equal) (muestra-respuestas respuestas) (setf respuestas-mostradas (cons respuesta respuestas-mostradas) ) ) ) ) ) ) ) ; ================================================== ; === comando: muestra-respuestas ; === funcion: imprimir resultados ; === fecha: enero / 1998 ; ================================================== (defun muestra-respuestas (respuestas) (format t "~&-->") (dolist (respuesta respuestas) (format t " ~a = ~a" (first respuesta) (second respuesta)) ) ) ; ================================================== ; === comando: aplica-filtros ; === funcion: desplegar los filtros ; === fecha: enero / 1998 ; ================================================== (defun aplica-filtros (patrones flujo-inicial-entrada) (if (endp patrones) (aplica-filtros (rest patrones) (filtra-flujo-de-ligaduras (first patrones) flujo-inicial-entrada) ) ) ) ; ================================================== ; === comando: filtra-flujo-de-ligaduras ; === de la regla. ; === fecha: enero / 1998 ; ================================================== (defun filtra-flujo-de-ligaduras (patron flujo) (concatena-flujo (transforma-flujo #'(lambda (ligaduras) (concatena-flujo (construye-flujo (corresponde-patron-con-afirmaciones patron ligaduras) (construye-flujo (corresponde-patron-con-reglas patron ligaduras) 'flujo-vacio ) ) ) ) flujo ) ) ) ; ================================================== ; === comando: lista-variables ; === funcion: producir variables ; === fecha: enero / 1998 ; ================================================== (defun lista-variables (arbol &optional nombres) (cond ((atom arbol) nombres) ((eq '? (first arbol)) (if (member (second arbol) nombres) nombres (append nombres (rest arbol)) ) ) (t (lista-variables (rest arbol) (lista-variables (first arbol) nombres))) ) ) ; ================================================== ; === comando: construye-flujo ; === funcion: inicializar un flujo ; === fecha: enero / 1998 ; ================================================== (defun construye-flujo (objeto flujo) (list objeto flujo) ) ; ================================================== ; === comando: final-del-flujo ; === funcion: comprobar si es el final del flujo ; === fecha: enero / 1998 ; ================================================== (defun final-del-flujo-p (flujo) (eq flujo 'flujo-vacio) ) ; ================================================== ; === comando: principio-del-flujo ; === funcion: extraer al principio del flujo ; === fecha: enero / 1998 ; ================================================== (defun principio-del-flujo (flujo) (first flujo) ) ; ================================================== ; === comando: resto-del-flujo ; === funcion: extraer el resto (segundo) del flujo ; === fecha: enero / 1998 ; ================================================== (defun resto-del-flujo (flujo) (second flujo) ) ; ================================================== ; === comando: concatena-flujo ; === funcion: crear un solo flujo de objetos a ; === partir de un flujo de flujos de objetos ; === fecha: enero / 1998 ; ================================================== (defun concatena-flujo (flujos) (if (final-del-flujo-p flujos) 'flujo-vacio (if (final-del-flujo-p (principio-del-flujo flujos)) (concatena-flujo (resto-del-flujo flujos)) (construye-flujo (principio-del-flujo (principio-del-flujo flujos)) (concatena-flujo (construye-flujo (resto-del-flujo (principio-del-flujo flujos)) (resto-del-flujo flujos)) ) ) ) ) ) ; ================================================== ; === comando: transforma-flujo ; === funcion: aplica un procedimiento a cada ; === objeto en un flujo produciendo ; === un nuevo flujo (mapcar) ; === fecha: enero / 1998 ; ================================================== (defun transforma-flujo (procedimiento flujo) (if (final-del-flujo-p flujo) 'flujo-vacio (construye-flujo (funcall procedimiento (principio-del-flujo flujo)) (transforma-flujo procedimiento (resto-del-flujo flujo)) ) ) ) ; ================================================== ; === comando: corresponde-patron-con-afirmaciones ; === funcion: operar sobre todas las afirmaciones ; === fecha: enero / 1998 ; ================================================== (defun corresponde-patron-con-afirmaciones (patron ligaduras) (concatena-flujo (transforma-flujo #'(lambda (afirmacion) (intenta-afirmacion patron afirmacion ligaduras)) *afirmaciones* ) ) ) ; ================================================== ; === comando: intenta-afirmacion ; === funcion: verificar el match ; === fecha: enero / 1998 ; ================================================== (defun intenta-afirmacion (patron afirmacion ligaduras) (let ((resultado (corresponde patron afirmacion ligaduras))) (if (eq 'falla resultado) 'flujo-vacio (construye-flujo resultado 'flujo-vacio) ) ) ) ; ================================================== ; === comando: corresponde-patron-con-reglas ; === funcion: parte del match (corresponde) ; === fecha: enero / 1998 ; ================================================== (defun corresponde-patron-con-reglas (patron ligaduras) (concatena-flujo (transforma-flujo #'(lambda (regla) (prueba-regla patron regla ligaduras)) *reglas* ) ) ) ; ================================================== ; === comando: consecuente-de-la-regla ; === funcion: obtener el consecuente ; === fecha: enero / 1998 ; ================================================== (defun consecuente-de-la-regla (regla) (first (last regla)) ) ; ================================================== ; === comando: nombre-de-la-regla ; === funcion: extraer el nombre de la regla ; === fecha: enero / 1998 ; ================================================== (defun nombre-de-la-regla (regla) (first regla) ) ; ================================================== ; === comando: antecedentes-de-la-regla ; === funcion: obtener el antecedente ; === fecha: enero / 1998 ; ================================================== (defun antecedentes-de-la-regla (regla) (butlast (rest regla)) ) ; ================================================== ; === comando: unifica-atomos ; === funcion: si son iguales (p1 y p2) => ligaduras ; === fecha: enero / 1998 ; ================================================== (defun unifica-atomos (p1 p2 ligaduras) (if (eql p1 p2) ligaduras 'falla) ) ; ================================================== ; === comando: unifica-partes ; === funcion: si son iguales (p1 y p2) => ligaduras ; === fecha: enero / 1998 ; ================================================== (defun unifica-partes (p1 p2 ligaduras) (let ((resultado (unifica (first p1) (first p2) ligaduras))) (if (eq 'falla resultado) 'falla (unifica (rest p1) (rest p2) resultado) ) ) ) ; ================================================== ; === comando: unifica-variable ; === funcion: unir ligaduras ; === fecha: enero / 1998 ; ================================================== (defun unifica-variable (p1 p2 ligaduras) (let ((ligadura (encuentra-ligadura p1 ligaduras))) (if ligadura (unifica (extrae-valor ligadura) p2 ligaduras) (if (contenidop p1 p2 ligaduras) 'falla (agrega-ligadura p1 p2 ligaduras) ) ) ) ) ; ================================================== ; === comando: contenidop ; === funcion: funciona si su primer argumento ; === su segundo ; === fecha: enero / 1998 ; ================================================== (defun contenidop (variable expresion ligaduras) (if (equal variable expresion) nil (contenido-o-igual-p variable expresion ligaduras) ) ) ; ================================================== ; === comando: contenido-o-igual-p ; === funcion: examinar de manera recursiva su ; === segundo argumento, reemplazando ; === cualquier variable que encuentre ; === con el valor de ella si la hay ; === fecha: enero / 1998 ; ================================================== (defun contenido-o-igual-p (variable expresion ligaduras) (cond ((equal variable expresion) t) ((atom expresion) nil) ((eq '? (first expresion)) (let ((ligadura (encuentra-ligadura expresion ligaduras))) (when ligadura (contenido-o-igual-p variable (extrae-valor ligadura) ligaduras)))) (t (or (contenido-o-igual-p variable (first expresion) ligaduras) (contenido-o-igual-p variable (rest expresion) ligaduras)) ) ) ) ; ================================================== ; === comando: unifica ; === funcion: corresponder 2 patrones ; === fecha: enero / 1998 ; ================================================== (defun unifica (p1 p2 &optional ligaduras) (cond ((elementos-p p1 p2)(unifica-atomos p1 p2 ligaduras)) ((variable-p p1)(unifica-variable p1 p2 ligaduras)) ((variable-p p2)(unifica-variable p2 p1 ligaduras)) ((recursivos-p p1 p2)(unifica-partes p1 p2 ligaduras)) (t 'falla) ) ) ; ================================================== ; === comando: prueba-regla ; === funcion: checar si coincide ; === fecha: enero / 1998 ; ================================================== (defun prueba-regla (patron regla ligaduras) (let* ((regla (haz-variables-unicas regla)) (resultado (unifica patron (consecuente-de-la-regla regla) ligaduras))) (if (eq 'falla resultado) 'flujo-vacio (aplica-filtros (antecedentes-de-la-regla regla) (construye-flujo resultado 'flujo-vacio) ) ) ) ) ; ================================================== ; === comando: extrae-valor ; === funcion: sacar un valor mas de ligadura ; === fecha: enero / 1998 ; ================================================== (defun extrae-valor (ligadura) (second ligadura) ) ; ================================================== ; === comando: haz-respuesta ; === funcion: construir una lista de asociacion ; === fecha: enero / 1998 ; ================================================== (defun haz-respuesta (variables ligaduras) (particulariza-variables (mapcar #'(lambda (variable) (list variable (list '? variable))) variables) ligaduras) ) ; ================================================== ; === comando: particulariza-variables ; === funcion: reemplazar expresiones de variable usando ; === una lista de ligaduras. ; === fecha: enero / 1998 ; ================================================== (defun particulariza-variables (patron lista-a) (cond ((atom patron) patron) ((eq '? (first patron))(extrae-valor (encuentra-ligadura patron lista-a))) (t (cons (particulariza-variables (first patron) lista-a) (particulariza-variables (rest patron) lista-a)) ) ) ) ; ================================================== ; === comando: haz-variables-unicas ; === funcion: auxiliar de prueba-regla ; === fecha: enero / 1998 ; ================================================== (defun haz-variables-unicas (regla) (let ((variables (lista-variables regla))) (dolist (variable variables regla) (setf regla (particulariza-variables regla (list (list variable (list '? (gentemp variable)))))))) ) ; ================================================== ; === BASE DE DATOS ORIENTADA AL MUNDO ANIMAL ; === CON REGLAS ; === fecha: enero / 1998 ; ================================================== (setf *afirmaciones* 'flujo-vacio) (recuerda-afirmacion '(robbie tiene manchas oscuras)) (recuerda-afirmacion '(robbie tiene color leonado)) (recuerda-afirmacion '(robbie come carne)) (recuerda-afirmacion '(robbie tiene pelo)) (recuerda-afirmacion '(suzie tiene plumas)) (recuerda-afirmacion '(suzie vuela bien)) (recuerda-afirmacion '(bozo es perro)) (recuerda-afirmacion '(deedee es caballo)) (recuerda-afirmacion '(deedee es padre de sugar)) (recuerda-afirmacion '(deedee es padre de brassy)) (setf *reglas* 'flujo-vacio) (recuerda-regla '(identifica1 ((? animal) tiene pelo) ((? animal) es mamifero))) (recuerda-regla '(identifica2 ((? animal) da leche) ((? animal) es mamifero))) (recuerda-regla '(identifica3 ((? animal) tiene plumas) ((? animal) es ave))) (recuerda-regla '(identifica4 ((? animal) vuela) ((? animal) pone huevos) ((? animal) es ave))) (recuerda-regla '(identifica5 ((? animal) come carne) ((? animal) es carnivoro))) (recuerda-regla '(identifica6 ((? animal) tiene dientes puntiagudos) ((? animal) tiene garras) ((? animal) tiene ojos al frente) ((? animal) es carnivoro))) (recuerda-regla '(identifica7 ((? animal) es mamifero) ((? animal) es ungulado))) (recuerda-regla '(identifica8 ((? animal) es mamifero) ((? animal) rumia) ((? animal) es ungulado))) (recuerda-regla '(identifica9 ((? animal) es mamifero) ((? animal) es carnivoro) ((? animal) tiene color leonado) ((? animal) tiene manchas oscuras) ((? animal) es leopardo))) (recuerda-regla '(identifica10 ((? animal) es mamifero) ((? animal) es carnivoro) ((? animal) tiene color leonado) ((? animal) tiene rayas negras) ((? animal) es tigre))) (recuerda-regla '(identifica11 ((? animal) es ungulado) ((? animal) tiene cuello largo) ((? animal) tiene piernas largas) ((? animal) tiene manchas oscuras) ((? animal) es jirafa))) (recuerda-regla '(identifica12 ((? animal) es ungulado) ((? animal) tiene rayas negras) ((? animal) es cebra))) (recuerda-regla '(identifica13 ((? animal) es ave) ((? animal) no vuela) ((? animal) tiene cuello largo) ((? animal) tiene piernas largas) ((? animal) es blanco y negro) ((? animal) es avestruz))) (recuerda-regla '(identifica14 ((? animal) es ave) ((? animal) no vuela) ((? animal) nada) ((? animal) es pinguino))) (recuerda-regla '(identifica15 ((? animal) es ave) ((? animal) vuela bien) ((? animal) es albatros))) (recuerda-regla '(identifica16 ((? animal) es (? especie)) ((? animal) es padre de (? cria)) ((? cria) es (? especie)))) ; ======================================================================= FIN