2010-03-29 3 views
6

Esempi di cosa è possibile fare.CLOS ha una distribuzione di specializzazione eql su stringhe?

(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" 

Funziona anche con un tipo di stringa generale.

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

Non con una stringa specifica, tuttavia

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

immagino che non funziona perché eql non funziona sulle stringhe nel modo in cui sarebbe necessario per farlo funzionare.

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

C'è un modo per farlo?

risposta

7

Risposta breve: Sì , esso ha.

Risposta lunga:

hai scritto:

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

Questo perché hai il sintassi sbagliata. Dovrebbe essere:

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

che di solito è formattato come:

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

Se si formatta in questo modo e utilizza lo strumento rientro built-in del vostro editor preferito, si vedrebbe che gli sguardi indentazione errato per il tuo codice:

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

Inoltre, può essere utile cercare di capire il messaggio di errore mostrato dal compilatore.

Torna il tema:

È possibile utilizzare le stringhe come qualsiasi altro oggetto Lisp per EQL la spedizione in CLOS.

È solo che esistono molte stringhe che assomigliano a "A" ed EQL confronta per identità (con un'eccezione per numeri e caratteri). EQL non confronta le stringhe con i loro caratteri.

In genere (EQL "A" "A") restituisce NIL. (Nota a margine: in realtà nel codice compilato dal compilatore questa espressione teoricamente può essere T. Perché al compilatore è consentito riutilizzare gli oggetti dati per risparmiare spazio nel codice compilato.Qui abbiamo stringhe letterali, oggetti di dati.)

Se si immette nella riga di comando

(some-fn "A") 

non si innescherà l'invio EQL.

Ma questo funziona come previsto:

(defparameter *a-string* "A") 

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

e poi

(some-fn *a-string*) 

È necessario assicurarsi che la variabile ha un valore. La variabile viene valutata quando viene valutata l'espansione macro del modulo DEFMETHOD. Il valore è quindi l'oggetto utilizzato per l'invio EQL.

Come Dirk ha menzionato nella sua risposta, si possono usare i simboli. Lo scopo dei simboli è che (EQL '| A |' | A |) è in genere T. I simboli sono realizzati come EQ durante il processo di lettura.

Sommario:

EQL spedizione oltre le stringhe lavora in CLOS. Per l'uso pratico, è necessario chiamare la funzione con lo stesso, in termini di EQL, stringa.

+0

Ops. Non ho nemmeno notato l'errore di sintassi. Buona pesca. Tecnicamente, usare la stessa istanza di stringa (al contrario di "una stringa con lo stesso contenuto") equivale a fare un qualche tipo di internamento/unificazione manuale, se le tue stringhe provengono da fonti esterne (ad esempio, leggono da un file o somesuch) che potrebbero renderizza utilizzando stringhe semplici qui poco pratiche. – Dirk

+0

Sì, l'ho copiato male. Sto usando emacs ecc ... Questa era una domanda di un amico a cui non potevo rispondere. Mi piace l'uso del defparam per risolverlo. È del tutto portatile? – mhb

+0

@mhb: sì, dovrebbe essere portatile –

4

Purtroppo non per quanto ne so. Lo specialista eql utilizza solo il confronto eql (che è essenzialmente un confronto tra puntatori per le stringhe). Per confrontare il contenuto delle stringhe, è necessario uno specialista equal (o equalp), che non esiste.

Se avete solo un piccolo insieme di stringhe che è necessario specializzarsi su, si potrebbe considerare l'utilizzo di parole chiave:

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

quale si desidera chiamare con

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

Non c'è bisogno di citare le parole chiave, si valutano da soli. – Vatine

+0

@Vatine: è un'abitudine. Spesso cito anche 'nil' (o'() ') a seconda dell'uso (ad esempio, in': initform's di 'defclass' o' defstruct'.) Dovrei cercare un aiuto professionale? :-) – Dirk

Problemi correlati