Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does CLOS have an eql specialization dispatch on strings?

Tags:

common-lisp

Examples of what you can do.

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

It also works with a general 'string type.

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

Not with a specific string, however

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

I imagine it doesn't work because eql does not work on strings in the way that would be necessary for it to work.

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

Is there a way to do it?

like image 362
mhb Avatar asked Mar 29 '10 20:03

mhb


People also ask

Does Lisp have classes?

Since Common Lisp provides non-CLOS classes for structures and built-in data types (numbers, strings, characters, symbols, ...), CLOS dispatch works also with these non-CLOS classes. CLOS also supports dispatch over individual objects (eql specializers).

Is lisp a generic?

A generic function is a lisp function which is associated with a set of methods and dispatches them when it's invoked. All the methods with the same function name belong to the same generic function. The defmethod form is similar to a defun .

Is Lisp Object Oriented?

Lisp is an object-oriented language, yes, but not because it has adopted the object-oriented model. Rather, that model turns out to be just one more permutation of the abstractions underlying Lisp. And to prove it we have CLOS, a program written in Lisp, which makes Lisp an object-oriented language.


1 Answers

Short answer: Yes, it has.

Long answer:

You wrote:

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

That's because you got the syntax wrong. It should be:

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

Which is usually formatted as:

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

If you format it this way and use the built-in indentation tool of your favorite editor, you would see that the indentation looks wrong for your code:

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

It also may help to try to understand the error message shown by the compiler.

Back to the topic:

You can use strings as any other Lisp object for EQL dispatch in CLOS.

It is just that there are many possible strings that look like "A" and EQL compares for identity (with an exception for numbers and characters). EQL does not compare strings by their characters.

Typically (EQL "A" "A") returns NIL. (Side note: Actually in code compiled by the compiler this expression theoretically can be T. Because the compiler is allowed to reuse data objects to save space in the compiled code. Here we have literal strings, data objects.)

If you enter on the command line

(some-fn "A")

it won't trigger the EQL dispatch.

But this works as expected:

(defparameter *a-string* "A")

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

and then

(some-fn *a-string*)

You need to make sure that the variable has a value. The variable is evaluated, when the macro expansion of the DEFMETHOD form is evaluated. The value then is the object that is used for EQL dispatch.

As Dirk has mentioned in his answer, one can use symbols. The purpose of symbols is that (EQL '|A| '|A|) is usually T. Symbols are made EQ during the reading process.

Summary:

EQL dispatch over strings works in CLOS. For practical use, you need to call the function with the same, in terms of EQL, string.

like image 68
Rainer Joswig Avatar answered Sep 21 '22 00:09

Rainer Joswig