Translate

sábado, 12 de marzo de 2022

CLOS (Common Lisp Object System)

En CLOS la macro defclass define una clase, defmethod define un método, y make-instance crea una instancia de una clase: un objeto. La forma general de la macro defclass es: 

(defclass nombre-clase (superclase...) (campos...) optional-opciones-clase...) 

Las opciones de clase rara vez son usadas. defclass puede ser usado para definir la clase cuenta:

(defclass cuenta () 

          ((nombre :initarg :nombre :reader nombre) 

           (balance :initarg :balance :initform 0.00 :accessor balance) 

           (tasa-interes :allocation :class :initform .06 :reader tasa-interes)))                                                                            

En la definición de 'cuenta', vemos que la lista de superclase esta vacía, debido a que 'cuenta' no hereda de ninguna clase. Hay tres campos, para nombre, balance y tasa-interes. Cada campo puede ser seguido por pares opcionales que definen como sera usado este. El campo nombre tiene la opción :initarg, que informa que el nombre puede ser especificado cuando se crea una 'cuenta' nueva con make-instance. La opción :reader crea un método nombre para obtener el valor actual del campo. El campo balance tiene tres opciones. :initarg, informando que el balance puede ser especificado cuando la cuenta es creada; :initform, que informa que si el balance no esta especificado toma el valor por defecto 0.00 y : accessor, que crea un método para obtener el valor del campo tal como :reader lo hace, y también crea un método para actualizar el campo con setf. El campo tasa-interes tiene una opción :initform para establecer un valor por defecto y una opcion :allocation que informa que este campo es parte de la clase, no de cada instancia de clase.

Aquí vemos la creación de un objeto, y la aplicación de los métodos definidos para él:

> (setf a1 (make-instance 'cuenta :balance 5000.00 

     :nombre "Akkiz"))  

#<CUENTA 26726272> 

                        

> (nombre a1)  

"Akkiz" 

                        

> (balance a1)  

5000.0 


> (tasa-interes a1)  

0.06 

CLOS difiere de la mayoría de los sistemas orientados a objetos en que los métodos son definidos de forma separada de las clases. Para definir un método (además de las definidas automáticamente por las opciones :reader, :writer o :accessor) usaremos la macro defmethod. Esta es similar en forma a defun:

(defmethod nombre-metodo (parametros...) cuerpo...) 

Los parámetros requeridos para un defmethod pueden ser de la forma (var clase), siendo este un método que aplica solo para argumentos de esa clase. Aquí mostramos el método para extraer dinero de una cuenta. Observe que CLOS no tiene una noción de variables de instancia, solo campos de instancia. Así tenemos que usar el método (balance cta) en lugar de la variable de instancia balance:

(defmethod retirar ((cta cuenta) monto) 

  (if (< monto (balance cta)) 

      (decf (balance cta) monto) 

      'fondos-insuficientes))

Con CLOS es fácil definir una cuenta-limitada como una subclase de cuenta, y definir el método extraer para cuenta-limitada:

(defclass cuenta-limitada (cuenta) 

  ((limite :initarg :limite :reader limite)))

           

(defmethod retirar ((cta cuenta-limitada) monto)                                                         

  (if (> monto (limite cta)) 

       'limite-superado 

       (call-next-method))) 

Observe el uso de call-next-method para invocar al método retirar de la clase cuenta. Observe también que todos los otros métodos para cuentas automáticamente funcionarán sobre instancias de la clase cuenta-limitada, debido a que ésta es definida por herencia de cuenta. En el siguiente ejemplo, mostramos que el método nombre es heredado, que método retirar para cuenta-limitada es invocado primero, y que el método retirar para cuenta es invocado a través de la función call-next-method:

> (setf a2 (make-instance 'cuenta-limitada

      :nombre "Ebru Sahin" 

      :balance 500.00 

      :limite 100.00))  

#<CUENTA-LIMITADA 24155343> 

  

> (nombre a2)  

"Ebru Sahin" 

  

> (retirar a2 200.00) 

LIMITE-SUPERADO 

  

> (retirar a2 20.00)  

480.0 

En general, hay varios métodos apropiados para un mensaje. En ese caso, todos los métodos apropiados se disparan juntos y se ordenan, el mas específico va primero. Un método menos específico que el anterior es llamado luego, y así sucesivamente. De este modo el método para cuenta-limitada es llamado primero antes que el método para cuenta. La función call-next-method puede ser usada dentro del cuerpo de un método para llamar al próximo método mas específico. La historia completa es aun mas complicada. Como ejemplo de esto, considere la clase cuenta-revisada, que muestra y mantiene una auditoría de todos los depósitos y extracciones. Esta podría ser definida usando una característica de CLOS, los métodos :before y :after. ("antes" y "después").      

(defclass cuenta-revisada (cuenta) 

  ((auditoria :initform nil :accessor auditoria))) 

           

(defmethod retirar :before ((cta cuenta-revisada) monto) 

  (push (print `(debito ,monto)) 

        (auditoria cta))) 

           

(defmethod retirar :after ((cta cuenta-revisada) monto) 

  (push (print `(debito (,monto) hecho)) 

        (auditoria cta)))    

Ahora una llamada a retirar con una cuenta-revisada como el primer argumento tiene tres métodos aplicables: el método primario de cuenta y los métodos :before y :after. Aquí un ejemplo: 

> (setf a3 (make-instance 'cuenta-revisada :balance 1000.00)) 

#<CUENTA-REVISADA 33555607> 

  

> (retirar a3 100.00) 

(DEBITO 100) 

(DEBITO (100) HECHO) 

900.0 

  

> (auditoria a3) 

((DEBITO (100) HECHO) (DEBITO 100)) 


> (setf (auditoria a3) nil) 

NIL 



  

miércoles, 9 de marzo de 2022

Sistemas expertos: MYCIN

 Hola amigos, traduje el programa mycin comentado en el libro "Paradigmas de inteligencia artificial" de Peter Norvig al español (pag. 530). 

Los comandos mas usados son:

?: muestra los posibles valores.

por-que?: explica por que pide un dato.








Aqui un ejemplo de su ejecucion:                                                                            

>> (mycin)

------ PACIENTE-1 ------

Nombre del paciente:  Silvia Saint

Sexo: femenino

Edad: 29

------ CULTIVO-1 ------

Que tipo de cultivo fue extraido de CULTIVO-1? sangre

Hace cuantos dias fue extraido este cultivo de (CULTIVO-1) ? 4

------ ORGANISMO-1 ------

Ingrese la identidad (genero) de ORGANISMO-1: desconocido

El tinte de gram de ORGANISMO-1: ?

Un GRAM debe ser del tipo (MEMBER ACID-FAST POS NEG)

El tinte de gram de ORGANISMO-1: neg

Es ORGANISMO-1 bacilo o coco (etc.): bacilo

Cual es el AEROBICIDAD de ORGANISMO-1? por-que?

[Por que el valor de AEROBICIDAD es preguntado?]

Es sabido que:

 1) LA GRAM DEL ORGANISMO ES NEG

 1) LA MORFOLOGIA DEL ORGANISMO ES BACILO

Por lo tanto,

Regla 107:

 Si

 1) LA AEROBICIDAD DEL ORGANISMO ES AEROBICO

 Entonces hay evidencia (0.8) de que

 1) LA IDENTIDAD DEL ORGANISMO ES ENTEROBACTERIACEAE

Cual es el AEROBICIDAD de ORGANISMO-1? aerobico

Esta Silvia Saint comprometido? si

Es Silvia Saint un pacente quemado? Si es asi, es leve o grave? grave

Hallazgos para ORGANISMO-1:

 IDENTIDAD: ENTEROBACTERIACEAE (0.800)  PSEUDOMONAS (0.760)

Hay otro ORGANISMO?  (Y or N) y

------ ORGANISMO-2 ------

Ingrese la identidad (genero) de ORGANISMO-2: desconocido

El tinte de gram de ORGANISMO-2: (neg .8 pos .2)

Es ORGANISMO-2 bacilo o coco (etc.): bacilo

Cual es el AEROBICIDAD de ORGANISMO-2? anaerobico

Hallazgos para ORGANISMO-2:

 IDENTIDAD: BACTEROIDES (0.720)  PSEUDOMONAS (0.646)

Hay otro ORGANISMO?  (Y or N) n

Hay otro CULTIVO?  (Y or N) n

Hay otro PACIENTE?  (Y or N) n

NIL