* Note. Despite using StackOverflow frequently for a long time, this is the first question I posted on my own. Sorry if it is a little detailed. Constructive criticism was appreciated.
When I define a structure in Common Lisp using defstruct, a predicate function is automatically generated that checks whether its argument is a type defined by defstruct. For instance:
(defstruct book title author) (let ((huck-finn (make-book :title "The Adventures of Huckleberry Finn" :author "Mark Twain"))) (book-p huck-finn)) => True
However, when defining a class using defclass, such functions do not seem to be generated by default (is there any way to specify this?), So I try to add this function myself because I would like: a) for this syntax to be consistent between structures and classes, b) have an abbreviation for (typep obj 'classname) , which I need to write very often and visually noisy, and c) as a programming exercise, since I'm still relatively new to Lisp.
I could write a macro that defines the predicate function given by the class name:
(defclass book () ((title :initarg :title :accessor title) (author :initarg :author :accessor author))) ;This... (defmacro gen-predicate (classname) ...) ;...should expand to this... (defun book-p (obj) (typep obj 'book)) ;...when called like this: (gen-predicate 'book)
The name I need to pass to defun should look like 'classname-p . Here, where itβs hard for me. To create such a symbol, I could use the "symb" function from Paul Graham On Lisp (p. 58). When it starts on REPL:
(symb 'book '-p) => BOOK-P
My macro predicate gene looks like this:
(defmacro gen-predicate (classname) `(defun ,(symb classname '-p) (obj) (typep obj ,classname))) (macroexpand `(gen-predicate 'book)) => (PROGN (EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN '|'BOOK-P| 'NIL T)) (SB-IMPL::%DEFUN '|'BOOK-P| (SB-INT:NAMED-LAMBDA |'BOOK-P| (OBJ) (BLOCK |'BOOK-P| (TYPEP OBJ 'BOOK))) NIL 'NIL (SB-C:SOURCE-LOCATION))) T
It would seem that the character created (symb 'book '-p) is actually considered |'BOOK-P| implementation (SBCL), not BOOK-P . Of course, this now works:
(let ((huck-finn (make-instance 'book))) (|'BOOK-P| huck-finn)) => True
Why is a character created using the inter interned character as |'BOOK-P| ? In On Lisp (on the same page as above), Graham says: "Any line can be the print name of a character, even a string containing lowercase letters or macro characters, like parentheses. When a character name contains such oddities, it prints in vertical bars " In this case, there are no such oddities, is it? And do I correctly believe that the "name-print" of a character is what is actually displayed on the standard output when printing a character and, in the case of such oddities, differs from the shape of the character itself?
To write macros defining a function, such as gen-predicate , whose specific functions are named based on the arguments passed to the macro, it seems to me that Lisp hackers have probably been doing it for ages. User Kaz says here ( Combining characters with a total of lisp ) that you can often avoid "chopping up" characters, but this can defeat the purpose of this macro.
Finally, assuming that I could get the gen-predicate to work, how do I want it to be the best way to ensure that it is called for each new class as it is defined? Just as an initialize-instance can be configured to perform certain actions when creating an instance of a class, is there a generic defclass function that can perform actions when defining a class?
Thanks.