2010-03-29 11 views
6

Ejemplos de lo que puede hacer.¿CLOS tiene un despacho de especialización eql en cadenas?

(defmethod some-fn ((num real)) 
    (print "an integer")) 
(defmethod some-fn ((num real)) 
    (print "a real")) 
(defmethod some-fn ((num (eql 0))) 
    (print "zero")) 

(some-fn 19323923198319) 
"an integer" 
(some-fn 19323923198319.3) 
"a real" 
(some-fn 0) 
"zero" 

También funciona con un tipo de cadena general.

(defmethod some-fn ((num string)) 
    (print "a string")) 
(some-fn "asrt") 
"a string" 
No

con una cadena específica, sin embargo

(defmethod some-fn ((num (eql "A"))) 
    (print "a specifict string")))  
(some-fn "A") 
    => "A string" 

Me imagino que no funciona porque eql no funciona en cadenas en la forma en que sería necesaria para que funcione.

(eql "a" "a") => nil 

¿Hay alguna manera de hacerlo?

Respuesta

7

Respuesta corta: Sí , Tiene.

Respuesta larga:

Usted escribió:

(defmethod some-fn ((num (eql "A")) (print "a specifict string"))) 
=> doesn't compile 

Eso es porque tienes el sintaxis incorrecta. Debe ser:

(defmethod some-fn ((num (eql "A"))) (print "a specific string")) 
=> does compile 

que generalmente se formatea como:

(defmethod some-fn ((num (eql "A"))) 
    (print "a specifict string")) 

Si formatea esta manera y utiliza la herramienta hendidura incorporada de su editor favorito, se vería que las miradas de sangría incorrecto para su código:

(defmethod some-fn ((num (eql "A")) 
        (print "a specifict string"))) 

También puede ayudar a tratar de entender el mensaje de error que muestra el compilador.

Volviendo al tema:

Puede utilizar cadenas como cualquier otro objeto Lisp para EQL despacho en CLOS.

Es simplemente que hay muchas cadenas posibles que se parecen a "A" y EQL se compara con la identidad (con una excepción para números y caracteres). EQL no compara cadenas por sus personajes.

Normalmente (EQL "A" "A") devuelve NIL. (Nota al margen: en realidad, en el código compilado por el compilador, esta expresión, en teoría, puede ser T. Porque el compilador puede reutilizar objetos de datos para ahorrar espacio en el código compilado.Aquí tenemos las cadenas literales, objetos de datos.)

Si introduce en la línea de comandos

(some-fn "A") 

no activará el envío EQL.

Pero esto funciona como se esperaba:

(defparameter *a-string* "A") 

(defmethod some-fn ((num (eql *a-string*))) 
    (print "a specific string"))) 

y luego

(some-fn *a-string*) 

Es necesario asegurarse de que la variable tiene un valor. La variable se evalúa cuando se evalúa la macro expansión de la forma DEFMETHOD. El valor entonces es el objeto que se usa para el despacho de EQL.

Como Dirk ha mencionado en su respuesta, uno puede usar símbolos. El propósito de los símbolos es que (EQL '| A |' | A |) suele ser T. Los símbolos se convierten en EQ durante el proceso de lectura.

Resumen:

EQL despacho sobre cadenas trabaja en CLOS. Para uso práctico, debe llamar a la función con el mismo, en términos de EQL, cadena.

+0

Ops. Ni siquiera noté el error de sintaxis. Buena atrapada. Técnicamente, usar la misma instancia de cadena (a diferencia de "una cadena con el mismo contenido") equivale a hacer algún tipo de internado/unificación manual, si las cadenas provienen de fuentes externas (por ejemplo, leer de un archivo o algo así) que podrían renderizado usando cadenas simples aquí impráctico. – Dirk

+0

Sí, lo copié mal. Estoy usando emacs, etc ... Esta fue una pregunta de un amigo que no pude responder. Me gusta el uso del defparam para arreglarlo. ¿Es eso completamente portátil? – mhb

+0

@mhb: sí, debería ser portátil –

4

Desafortunadamente no tan lejos como yo sé. El especialista en eql usa solo eql para comparar (que es esencialmente una comparación de puntero para cadenas). Para comparar el contenido de las cadenas, necesitaría un especialista en equal (o equalp), que no existe.

Si usted tiene sólo una muy pequeña conjunto de cadenas que necesita especializarse en, es posible considerar el uso de palabras clave:

(defmethod operation ((arg (eql ':tag-1))) ...) 
(defmethod operation ((arg (eql ':tag-2))) ...) 

la que ustedes llamarían con

(operation (intern ... :keyword)) 
+1

No es necesario citar palabras clave, se evalúan a sí mismos. – Vatine

+0

@Vatine: es un hábito. A menudo incluso cito 'nil' (o'() 'dependiendo del uso (por ejemplo, en': initform's de 'defclass' o 'defstruct'.) ¿Debo buscar ayuda profesional? :-) – Dirk