Tutorial de CLIPS (i)
Trabajando con CLIPS
Para arrancar CLIPS desde una shell de Linux teclea clips; en Windows or MacOS, haz doble
click en el icono de CLIPS. En ese momento aparecer el prompt CLIPS>. La forma ms usual
de interactuar con CLIPS es a travs de un interprete de comandos, con una notacin muy
similar a la del lenguaje LISP. As por ejemplo, para salir de CLIPS basta con teclar (exit).
Aqu tienes algunos comandos bsicos (siempre encerrados entre parntesis):
(exit) Sale de CLIPS
(clear) Elimina datos y programas de la memoria, tal como si salisemos y entrsemos en CLIPS.
(reset) Elimina la informacin dinmica de la memoria y resetea la agenda.
(run) Comienza la ejecucin de un programa CLIPS.
Estos comandos pueden ser ejecutados tambin desde la barra de mens, en caso que estemos ejecutando
CLIPS en un entorno grfico.
Hechos y Reglas
En un su modo ms sencillo, CLIPS opera manteniendo una lista de hechos (facts) y un conjunto de
reglas ( rules) con las que operar. Un hecho es una pieza de informacin tal como (colour green) o
(parent_of John Susan). Los hechos se crean aseverando su existencia mediante el comando
assert command. Un ejemplo, junto con la respuesta de CLIPS:
CLIPS>(assert (colour green))
<Fact-0>
El texto <Fact-0> is la respuesta de CLIPS e indica que se ha creado un nuevo hecho (fact number 0)
y ha sido aadido a la Memoria de Trabajo (MT). El comando (facts) listar todos los hechos
actuales almacenados en la MT:
CLIPS>(facts)
f-0 (colour green)
For a total of 1 fact.
Los hechos pueden ser retractados (eliminados) de la MT mediante el comando retract. Veamos un
ejemplo:
CLIPS>(assert (colour green))
<Fact-0>
CLIPS>(assert (colour red))
<Fact-1>
Para retraerse del primer hecho es necesario conocer el ndice de ese hecho, que es adjudicado por
CLIPS, como se vio anteriormente:
CLIPS>(retract 0)
CLIPS>(facts)
f-1 (colour red)
For a total of 1 fact.
Estos ndices no se reutilizan, esto es despues de borrar el hecho 0, ste no se le asignar a ningn hecho
venidero.
Los hechos por s mismo tienen una utilidad limitada. La aplicacin de reglas es necesaria para
desarrollar un programa capaz de realizar alguna funcin til. En general, una regla es expresado en la
forma SI <precondicin> ENTONCES<postcondicin>.Esta clase de regla es conocida como
produccin, y de ah que a CLIPS y sistemas similares se les llame sistemas de produccin. En CLIPS,
una regla tpica tiene el siguiente aspecto:
(defrule pato
(animal-es pato)
=>
(assert (sonido-es quack)))
Cada regla tiene tres partes. La primera parte, (defrule pato , simplemente le da un nombre nico
a esa regla. La segunda parte, (animal-es pato), es el patrn o LSH (el "SI...", left-hand side) de
la regla, y la ltima parte, (assert (sonido-es quack)), es la accin o RHS (el
"ENTONCES...", right-hand side). La regla del ejemplo puede parafrasearse como: "si hay un hecho
(animal-es pato) en la MT, entonces asevera otro hecho, (sonido-es quack), en la MT".
Prubalo. Limpia el sitema y teclea la regla tal cual. Tecleando (rules) te dar la lista de reglas
presente en la Memoria de Produccin (una tan solo en este ejemplo). En este momento no hay hecho
alguno, as que vamos a introducir uno, teclea (assert (animal-es pato)). Si compruebas el
contenido de la MT vers que slo hay un hecho. Para lanzar la regla, teclea (run). Aparentemente no
ocurre nada, pero si vuelves a comprobar el contenido de la MT, aparecer un nuevo hecho, (sonido-
es quack), que ha sido inferido/producido por la regla. Esta es la fuerza de la programacin basada
en reglas: la habilidad de hacer inferencias a partir de los datos, siendo posible usar el conocimiento
inferido para lanzar nuevas relgas. Aade una segunda regla:
(defrule es-esto-un-pato
(animal-tiene pies-palmeados)
(animal-tiene plumas)
=>
(assert (animal-es pato)))
Dado que esta regla tiene dos patrones, ambos deben satisfacerse para ser ejecutada la accin asociada.
Comprueba qu pasa en la MT si aseveramos los dos hechos que aparecen en el patrn de la regla. Si
aades tales hechos, (animal-tiene pies-palmeados), (animal-tiene plumas)y
luego ejecutas el programa ( (run) ), vers que aparecen cuatro reglas en la MT. En primer lugar, la regla
es-esto-un-pato se lanza, aseverando el hecho (animal-es pato). Este hecho entonces
lanza a su vez la regla pato, con lo que se asevera el hecho (sonido-es quack). Sistemas muy
poderosos pueden crearse mediante la adecuada construccin de reglas encadenadas entre ellas.
Combinacin de elementos condicionales con And, Or, y Not
Para que una regla este activada todos los elementos condicionales de la precondicin deben reconocer
hechos de la memoria de trabajo. Por lo tanto, hasta ahora todas la reglas vistas tienen un and implcito
entre los elementos condicionales. CLIPS ofrece la posibilidad de representar and y or explcitos, as
como la posibilidad de indicar mediante not que una regla ser activada si no existe ningn hecho
reconocido por un patrn.
La siguiente regla se activa en el caso de que no exista el hecho (animal-es pato):
(defrule nopato
(not (animal-es pato))
=>
(assert (sonido-es noquack))
(printout t "Esto no es un pato" crlf))
NOTA IMPORTANTE: Para que not sea efectivo siempre, es necesario haber ejecutado en algn
momento el reset. Tecleando (reset), entre otras cosas, se vaca la MT (las reglas estn en la
memoria de produccin, no se toca) y se asevera el hecho (initial-fact). Este hecho es el que se le
presupone a las reglas cuyo patrn est vaco. y se mantiene en la MT hasta que se ejecute (clear) o se
salga y entre de clips. En ocasiones, tal como el ejemplo anterior, el uso de not conlleva que a esa regla
se le aade el hecho (initial-fact) a su patrn, y es por ello que es necesario que en algn momento se
haya invocado (reset) para que este tipo de reglas funcione correctamente.
Es posible que la produccin de la regla est formada por tantas acciones como sea necesario. Por
ejemplo podramos modificar la regla pato para que adems de aseverar un hecho, muestre por pantalla
el hallazgo:
(defrule pato
(animal-es pato)
=>
(assert (sonido-es quack))
(printout t "Esto es un pato" crlf))
La siguiente vez que se teclee (run), si se asever previamente el hecho (animal-es pato), aparecer un
mensaje aseverando que hay un pato.
Algunos sencillos consejos de estilo para la creacin de reglas:
- Evitar el uso de OR. Un patrn que contiene un OR puede fcilmente sustiturse por dos reglas con
cada uno de los operandos que recibe el operador OR como patrn, y como accin, la misma accin de
la regla original.
- El "else" usual en las construcciones if...then puede simularse fcilmente creando una regla cuyo patrn
sea la negacin del patrn de la regla original.
- Nunca invocar a una regla desde la accin de otra regla, ni usar reglas anidadas. En vez de ello, se debe
descomponer la regla en diversas reglas ms sencillas que queden encadenadas mediante hechos
intermedios. Ya que esos hechos intermedios o sealadores no tiene ms funcin que simplificar las
reglas, deberan ser eliminados justo en la accin de aquellas reglas que le tienen como patrn.
Almacenamiento de reglas
Por convenio, los programas CLIPS tienen la extensin .CLP, si bien en estos archivos slo
se almacenan constructores (por el momento el nico constructor que conocemos es
defrule). Es posible cargar uno de tales archivos mediante (load "[Link]").
Tambin podemos siempre que queramos almacenar los constructores creados hasta ese
momento mediante (save "[Link]"). Por el momento, los hechos deben ser tecleados en
cada sesin.
Utilidades CLIPS
Las siguientes instrucciones te sern de utilidad:
(dribble-on <nombre-fichero>), (dribble-off) . Equivalente a la funcin dribble de lisp.
dribble-on registra las salidas del terminal y las entradas del teclado en el fichero especificado.
dribble-off cierra el fichero.
(agenda) Muestra las reglas instanciadas. Para cada instancia muestra la prioridad de la regla, el
nombre de la regla y los hechos reconocidos por la regla.
(facts) Muestra los hechos de la memoria de trabajo.
(watch <parmetro>) Es til para depurar programas. El parmetro puede ser un de los
siguientes smbolos: facts, rules, activations, statistics, compilations, focus, o all. Para la
prctica te interesar utilizar (watch facts) y (watch rules), que indica con la secuencia <==
cuando se elimina un hecho, y con la secuencia ==>, cuando se inserta. Para que deje de dar
esta informacin utiliza (unwatch facts).
o CLIPS> (assert (animal-es pato))
==> f-0 (animal-es pato)
<Fact-0>
CLIPS> (run)
FIRE 1 pato: f-0
==> f-1 (sonido-es quack)
Esto es un pato
(matches <nombre-de-regla>) . Matches recibe como argumento el nombre de una regla y
muestra los hechos reconocidos por cada patrn. Por ejemplo:
CLIPS>(matches Estado-Inicial)
Matches for Pattern 1
f-0
Activations
f-0
Cualquier lnea que comience con un punto y coma (;) no se interpreta. Son comentarios.
Tutorial de CLIPS: variables, y hechos complejos
Hechos persistentes
Usualmente, existen ciertos hechos que deseamos que se conserve entre ejecucin y ejecucin, despus
de limpiar la memoria de trabajo. Esto puede conseguirse mediante el constructor deffacts. Por
ejemplo, si quiero aseverar que en mi BC hay un perro, un pato y un loro, y esto quiero que conste cada
vez que haga un (reset)debo escribir:
(deffacts startup (animal dog) (animal duck) (animal haddock))
Una vez asertados -tras hacer un (reset)-estos son tres hechos ms de la WS. Pueden ser eliminados
de la WS, pero volvern a aparecer cuando se vuelva a ejecutar (reset). A continuacin, se listan
algunos hechos que, entre otros, se usarn en el resto de este tutorial:
(animal dog) (animal cat) (animal duck) (animal turtle) (warm-blooded
dog) (warm-blooded cat) (warm-blooded duck) (lays-eggs duck) (lays-
eggs turtle) (child-of dog puppy) (child-of cat kitten) (child-of
turtle hatchling)
Patrones ms flexibles
Hasta ahora, los patrones usados eran ms bien simples y restrictivos, ya que cada expresin lgica del
patrn slo poda ser satisfecha por un hecho. Frecuentemente interesa que una regla pueda ser lanzada
por diversos hechos que satisfazgan una determinada expresin. Para ello se pueden usar los comodines
o wildcards. A modo de ejemplo, el patrn de la siguiente regla ser lanzado por cualquier hecho que
refiera a un animal, sea el hecho que sea:
(defrule animal
(animal ?)
=>
(printout t "animal found" crlf))
As, si introducimos los animales de la anterior seccin (haciendo un reset si utilizamos obtenemos:
CLIPS>(run)
Animal found
Animal found
Animal found
Animal found
CLIPS>
ADVERTENCIA: Es posible usar la ? all donde haga falta y tantas veces como se necesite, pero puede
no ser legal poner ? al principio de un hecho. Por ejemplo (child-of ? ?)es legal , pero
(? ? hatchling) no lo es.
Uso de Variables
Para poder aprovechar todo el potentecial del uso de comodines, es necesario ligar estos a una variable.
La forma de ligarlos es simple: escribimos el nombre de la variable a continuacin del comodn. Prueba
este ejemplo:
(defrule list-animals
(animal ?name)
=>
(printout t ?name " found" crlf))
Si probamos ahora una ejecucin :
CLIPS>(run)
turtle found
duck found
cat found
dog found
CLIPS>
Conseguimos que se imprima cada uno de los cuatro hechos que casan con el patrn . Es posible utilizar
tantas variables como se requiera, o utlizarla en varios sitios dentro del mismo patrn, que es lo ms
usual. Un ejemplo:
(defrule mammal
(animal ?name)
(warm-blooded ?name)
(not (lays-eggs ?name))
=>
(assert (mammal ?name))
(printout t ?name " is a mammal" crlf))
Esta regla da el siguiente resultado:
CLIPS>(run)
cat is a mammal
dog is a mammal
CLIPS>
Ahora un ejemplo ms complejo. La siguiente regla hace uso de dos variables :
(defrule mammal2
(mammal ?name)
(child-of ?name ?young)
=>
(assert (mammal ?young))
(printout t ?young " is a mammal" crlf))
Esta regla dice que los hijos de mamferos son mamferos. Lo que muestra por pantalla:
CLIPS>(run)
kitten is a mammal
puppy is a mammal
CLIPS>
Variables para referirse a Hechos
Recuerda que todo hecho tiene un ndice, que es nico. Ese ndice es asignado por CLIPS y resulta muy
til almacenarlo en una variable con la finalidad de poder referenciar el hecho al que refiere ese ndice,
por ejemplo para eliminar ese hecho:
(defrule remove-mammals
?fact <- (mammal ?)
=>
(printout t "retracting " ?fact crlf)
(retract ?fact))
En el patrn de esta regla, la variable ?fact almacena cada mamfero contenido en la BC
(mammal ?) . Eso es justamente lo que el operador de asignacin (<-) hace. Si ejecutas esta regla
obtendrs algo similar a esto (los ndices pueden variar):
CLIPS>(run)
retracting <Fact-13>
retracting <Fact-14>
retracting <Fact-15>
retracting <Fact-16>
CLIPS>
Si ahora ejecutamos (facts) para listar los hechos alamacenados en el WS encontraremos que no hay
mamiferos.
Variables para almacenar expresiones
La sintaxis de CLIPS recuerda en gran medida a la de LISP, y como tal se usa notacin prefija, tanto con
operadores lgicos como aritmticos. Por ejemplo:
(defrule take-umbrella
(or (weather raining)
(weather snowing))
=>
(assert (umbrella required)))
Define un regla con un patrn que es una disyuncin de dos hechos (si bien recuerda que denota
un mejor estilo escribir dos reglas, una para cada operando). De forma anloga si quiero hacen
operaciones aritmticas:
CLIPS>(+ 5 7)
12
CLIPS>(- 5 7)
-2
CLIPS>(* 5 7)
35
CLIPS>(/ 5 7)
0.7142857142857143
CLIPS>
Prueba a re-escribir 10+4*19-35/12 en notacin propia de CLIPS y verifica que el resultado es 83.0833.
Solicitando informacin al usuario
CLIPSsolicita informacin por entrada estndard mediante la funcin (read) y readline) . Si
(read) es encontrado, lo leido por la entrada estndard es asignado al hecho que aparezca en esa
expresin. La diferencia con readline es que este ltimo asigna a la variable todo lo introducido hasta
pulsar el retorno de carro, mientras read slo lee el primer smbolo (generalmente, se corresponde con
los caracteres encontrados hasta dar con un espacio en blanco, o todo el texto si se introdujo
entrecomillado). Prueba a escribir (assert (user-input (read))) en en prompt de CLIPS. Si
despus comprobamos los hechos almacenados en la WS, habr un hecho llamado user-input con el
valor que hayamos introducido por teclado (si no hemos redirigido la entrada estndard a otro
dispositivo). Prueba esta regla:
(defrule what-is-child
(animal ?name)
(not (child-of ?name ?))
=>
(printout t "What do you call the child of a " ?name
"?")
(assert (child-of ?name (read))))
Si ejecutas esta regla, para cada animal cuyo cachorro no se conozca, se te solitiar el nombre de tal
cachorro y se crear un hecho a tal efecto. Este tipo de sentencias son muy tiles para realizar Sistemas
Expertos, en los cuales se requiere una interaccin con el usuario, cuyas respuestas guan la bsqueda a
travs de la BC. Otro ejemplo:
(defrule are-lights-working
(not (lights-working ?))
=>
(printout t "Are the car's lights working (yes or no)?")
(assert (lights-working (read))))
El resultado de esta regla aadir un hecho (lights-working yes) o bien (lights-working no), que a su
vez podr lanzar otras reglas que avancen en el dianstico segn estn las luces encendidas o no. De esta
forma se evita, por una parte, forzar al usuario a que de toda la informacin al principio, y por otra a que
de slo la informacin relevante, ni ms ni menos.
Definicin de hechos ms complejos
Hasta ahora todos los hechos declarados estaban formados por un slo atributo, pero esto no es lo usual.
Por ejemplo para representar la informacin de una persona:
(persona (nombre "Vitorino Gmez Campo")
(edad 32)
(estudios Empresariales Derecho)
(profesion abogado)
(estado-civil soltero))
Antes de crear un hecho as se debe definir una plantilla mediante deftemplate. Deftemplate permite
especificar si los atributos tendrn un nico valor mediante slot, o pueden tener 0 o ms valores
mediante multislot.
Adems se puede aadir informacin adicional sobre los atributos como tipo de los atributos o
restricciones sobre sus valores. La especificacin del tipo de atributos puede ser ?VARIABLE,
SYMBOL, STRING, LEXEME, INTEGER, FLOAT, o NUMBER. VARIABLE? indica que el atributo
puede contener cualquier tipo de dato; LEXEME que el dato puede ser SYMBOL o STRING; y
NUMBER que el dato puede ser INTEGER o FLOAT?.
Se puede restringir los valores permitidos en un atributo mediante allowed-symbols, allowed-strings,
allowed-lexemes, allowed-integers, allowed-floats, allowed-numbers, y allowed-values. Tambin es
posible especificar un rango numrico mediante los valores mnimo y mximo mediante (range
<mnimo> <mximo>), y la cardinalidad indicando el mnimo y mximo nmero de valores mediante
(cardinality <mnimo> <mximo>) (?VARIABLE indica que no hay mximo o mnimo).
Si no se especifica el valor por defecto, se asume (default ?DERIVE), que especifica que como valor del
atributo se derivar uno que cumpla con las restricciones impuestas. En el ejemplo de plantilla que se
expone a continuacin, si no se especifica otra cosa el atributo estado civil ser soltero (el primero de la
lista de valores permitidos).
Default tambin puede ir seguido de cualquier expresin cuyo valor ser utilizado como valor por
defecto; o seguido de ?NONE para indicar que no existe valor por defecto y que no se derivar ningn
valor.
(deftemplate persona "Plantilla para describir persona"
(slot nombre (type STRING))
(slot edad (type INTEGER)
(range 0 ?VARIABLE))
(multislot estudios (type SYMBOL))
(slot profesion (type SYMBOL))
(slot estado_civil (type SYMBOL)
(allowed-symbols soltero casado viudo divorciado)))
A lo hechos del tipo vistos al principio de este tutorial, que son simples, con un slo slot, se le
denominan hechos ordenados y como ya hemos visto no necesitan de plantilla para ser creados.
Manipulacin de hechos
El estado de la memoria de trabajo puede ser alterado aadiendo nuevos hechos, y eliminando o
modificando hechos de la lista. Como ya sabemos, (assert) permite aadir nuevos hechos y (retract)
eliminarlos. Pero tambin es posible modificar y copiar hechos. En concreto, contamos con las
siguientes funciones para manipular hechos:
(assert <hecho>+). Se pueden asertar uno o ms hechos. Por ejemplo, si queremos aadir un par
de hechos utilizando la plantilla definida para personas:
CLIPS>
(assert (persona (nombre "Vitorino Gmez Campo")
(edad 32)
(estudios Empresariales Derecho)
(profesion abogado))
(persona (nombre "Macarena Lpez del Monte")
(edad 35)
(estudios Ingeniero)
(profesion empresario)))
<fact-0>
CLIPS> (facts)
f-0 (persona (nombre "Vitorino Gmez Campo")
(edad 32) (estudios Empresariales Derecho)
(profesion abogado) (estado_civil soltero))
f-1 (persona (nombre "Macarena Lpez del Monte")
(edad 35) (estudios Ingeniero)
(profesion empresario) (estado_civil soltero))
For a total of 2 facts.
(retract <ndice>+). Por ejemplo, (retract 0) elimina el hecho f-0.
CLIPS> (retract 0)
CLIPS> (facts)
f-1 (persona (nombre "Macarena Lpez del Monte")
(edad 35) (estudios Ingeniero)
(profesion empresario) (estado_civil soltero))
For a total of 1 fact.
(modify <ndice> (<nombre-atributo> <valor>)+). Modify elimina el hecho modificado y aserta
un nuevo hecho con el valor del o los atributos actualizados. Por ejemplo, si queremos
actualizar el valor de la edad de Macarena a 36:
CLIPS> (modify 1 (edad 36))
<Fact-2>
CLIPS> (facts)
f-2 (persona (nombre "Macarena Lpez del Monte")
(edad 36) (estudios Ingeniero)
(profesion empresario) (estado_civil soltero))
For a total of 1 fact.
(duplicate <ndice> (<nombre-atributo> <valor>)+). Duplicate acta como modify aadiendo
un nuevo hecho actualizado, pero no elimina el hecho modificado.
CLIPS> (duplicate 2 (nombre "Aparicia Perez del Rio"))
<Fact-3>
CLIPS> (facts)
f-2 (persona (nombre "Macarena Lpez del Monte")
(edad 36) (estudios Ingeniero)
(profesion empresario) (estado_civil soltero))
f-3 (persona (nombre "Aparicia Perez del Rio")
(edad 36) (estudios Ingeniero)
(profesion empresario) (estado_civil soltero))
For a total of 2 facts.
Reconocimiento de patrones usando hechos complejos
Hasta ahora hemos visto patrones muy simples. Como en otros lenguajes, CLIPS tiene variables para
almacenar valores. Por convenio, todo identificador de una variable es precedido por el carcter ?, como
por ejemplo ?color, ?nombre, ?valor.
Un primer uso de las variables es ligar una variable a un valor en la parte izquierda de una regla y usar el
valor posteriormente en la parte derecha. Por ejemplo:
CLIPS> (clear)
CLIPS> (deftemplate personaje
(slot nombre)
(slot ojos)
(slot pelo))
CLIPS>
(defrule busca-ojos-azules
(personaje (nombre ?nombre) (ojos azules))
=>
(printout t ?nombre " tiene los ojos azules." crlf))
CLIPS>
(deffacts gente
(personaje (nombre Juan) (ojos azules) (pelo castagno))
(personaje (nombre Luis) (ojos verdes) (pelo rojo))
(personaje (nombre Pedro) (ojos azules) (pelo rubio))
(personaje (nombre Maria) (ojos castagnos) (pelo negro)))
CLIPS> (reset)
CLIPS> (run)
Pedro tiene los ojos azules.
Juan tiene los ojos azules.
Pedro y Juan tienen los ojos azules, por lo que la regla busca-ojos-azules es instanciada dos veces.
El segundo uso de las variables consiste en utilizar la misma variable en mltiples lugares en la parte
izquierda de una regla. La primera aparicin de la variable liga un valor a dicha variable, y este valor es
retenido para el resto de apariciones en la regla. De esta forma podemos definir relaciones entre los
patrones de la parte izquierda de una regla, y definir restricciones adicionales.
Siguiendo con el ejemplo anterior, podemos asertar un hecho que indique que color de ojos buscar:
CLIPS> (undefrule *)
CLIPS>(deftemplate busca (slot ojos))
CLIPS>
(defrule busca-ojos
(busca (ojos ?color-ojos))
(personaje (nombre ?nombre) (ojos azules))
=>
(printout t ?nombre " tiene los ojos "
?color-ojos "." crlf))
CLIPS> (reset)
CLIPS> (assert (busca (ojos azules)))
<Fact-5>
CLIPS> (run)
Pedro tiene los ojos azul.
Juan tiene los ojos azul.
CLIPS permite especificar patrones ms sofisticados, as como funciones para manipular hechos en las
reglas. A continuacin algunos ejemplos
Ejemplo 1: Ligar un hecho a una variable
CLIPS> (clear)
CLIPS> (deftemplate persona (slot nombre) (slot direccion))
CLIPS> (deftemplate cambio (slot nombre) (slot direccion))
CLIPS> (defrule procesa-informacion-cambios
?h1 <- (cambio (nombre ?nombre) (direccion ?direccion))
?h2 <- (persona (nombre ?nombre))
=>
(retract ?h1)
(modify ?h2 (direccion ?direccion)))
CLIPS>
(deffacts ejemplo
(persona (nombre "Pato Donald") (direccion "Disneylandia"))
(cambio (nombre"Pato Donald") (direccion "Port Aventura")))
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-3 (persona(nombre "Pato Donald")(direccion "Port Aventura"))
For a total of 2 facts.
Ejemplo 2: Comodines
CLIPS> (clear)
CLIPS>
(deftemplate persona (multislot nombre) (slot dni))
CLIPS>
(deffacts ejemplo
(persona (nombre Jose L. Perez) (dni 22454322))
(persona (nombre Juan Gomez) (dni 23443325)))
CLIPS>
(defrule imprime-dni
(persona (nombre ? ? ?Apellido) (dni ?dni))
=>
(printout t ?dni " " ?Apellido crlf))
CLIPS> (reset)
CLIPS> (run)
22454322 Perez
La regla imprime-dni imprime los dni de las personas que tienen nombre compuesto y apellido, es decir
aquellas que tengan exactamente tres elementos en el atributo nombre. Cuandose quiere un comodn que
reconozca cero o ms valores de un atributo multi-valor, se puede utilizar "$?". Por ejemplo, la siguiente
regla imprimir los dni de todas las personas con apellido, tengan o no nombre, o sea nombre sencillo o
compuesto por dos o ms.
CLIPS>
(defrule imprime-dni
(persona (nombre $?nombre ?Apellido) (dni ?dni))
=>
(printout t ?dni " " ?nombre " " ?Apellido crlf))
CLIPS> (reset)
CLIPS> (run)
23443325 (Juan) Gomez
22454322 (Jose L.) Perez
Ejemplo 3: Restricciones
Podemos representar patrones que reconozcan hechos que no tengan un determinado valor en un
atributo, o que tengan alguno de los valores que se especifican. Los operadores operador ~, | y &
cumplen este propsito. Por ejemplo
(persona (nombre ?nombre) (pelo ~rubio))
reconocer a toda persona con pelo que no sea rubio, y
(persona (nombre ?nombre) (pelo castagno | pelirrojo))
reconocer a toda persona con el pelo castao o pelirrojo.
El operador & se utiliza en realidad en combinacin con los anteriores para ligar valor a una variable.
Por ejemplo
(defrule pelo-castagno-o-rubio
(persona (nombre ?nombre) (pelo ?color&rubio|castagno))
=>
(printout t ?nombre " tiene el pelo " ?color crlf))
Tambin es posible expresar predicados sobre el valor de un atributo directamente en el patrn. Por
ejemplo:
(defrule mayor-de-edad
(persona (nombre $?nombre) (edad ?edad&:(> ?edad 18))
=>
(printout t ?nombre " es mayor de edad." crlf))
Para indicar que el valor de un atributo debe ser igual al resultado de la evaluacin de una funcin se
indica mediante el operador =. Por ejemplo, para reconocer las personas con 2 aos mas que la mayora
de edad se puede expresar mediante el patrn:
(persona (edad =(+ 18 2)))
Funcin test
Un elemento condicional puede evaluar una expresin, en lugar de representar un patrn que debe ser
reconocido. Por ejemplo, para comprobar que la variable ?edad es mayor que 18 se puede representar
mediante (test (> ?edad 18)).
Funcin bind
Si queremos ligar un valor a una variable para utilizarlo en varios sitios sin tener que recalcular el valor
podemos hacerlo con la funcin bind. Por ejemplo, supn que hoy es el cumpleaos de Paco:
(defrule cumpleagnos
?indice<-(persona (nombre Paco) (edad ?agnos))
=>
(bind ?edad (+ 1 ?agnos))
(printout t Jose cumple ?edad aos crlf)
(modify ?indice (edad ?edad))
)
Funciones
Aunque cae fuera de los objetivos de este pequeo tutorial, CLIPS es un lenguaje de programacin
completo, con estructuras de control y extensiones orientadas a objetos. A modo de ejemplo, se incluyen
dos funciones que permiten una captura por teclado controlada:
(deffunction ask-question (?question $?allowed-values)
(printout t ?question)
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer)))
(while (not (member ?answer ?allowed-values)) do
(printout t ?question)
(bind ?answer (read))
(if (lexemep ?answer)
then (bind ?answer (lowcase ?answer))))
?answer)
(deffunction yes-or-no-p (?question)
(bind ?response (ask-question ?question yes no y n))
(if (or (eq ?response yes) (eq ?response y))
then TRUE
else FALSE))
La forma de usar funciones definidas por usuario no difiere a como se usara cualquier otra funcin:
(bind ?response (ask-question ("Es un animal de sangre FRIA o
CALIENTE?" (fria caliente)))
La forma correcta de expresar 10+4*19-35/12 en CLISP notacin infija es (+ 10 (- (* 4 19) (/
35 12))).