While reading about CLOS (in ANSI Common Lisp by Paul Graham), I noticed that there are nine functions that can be given to defmethod
as its second argument:
+
, and
, append
, list
, max
, min
, nconc
, or
and progn
. According to this answer, they are called simple method combinations.
Why only these nine? What is the reason I cannot pass an arbitrary function as the second argument?
Suppose I defined xor
as
(defun xor (&rest args)
(loop for a in args counting (not (null a)) into truths
finally (return (= truths 1))))
(this could certainly be improved). I would like to define several classes describing clothes and their combinations using xor
:
(defgeneric looks-cool (x)
(:method-combination xor))
(defclass black-trousers () ())
(defclass quilt () ())
(defclass white-shirt () ())
(defclass hawaii-shirt () ())
(defmethod looks-cool xor ((tr black-trousers)) nil)
(defmethod looks-cool xor ((qu quilt)) t)
(defmethod looks-cool xor ((ws white-shirt)) nil)
(defmethod looks-cool xor ((hs hawaii-shirt)) t)
(defclass too-stiff (black-trousers white-shirt) ())
(defclass scottish (quilt white-shirt) ())
(defclass also-good (black-trousers hawaii-shirt) ())
(defclass too-crazy (quilt hawaii-shirt) ())
Now if this compiled (which it doesn't), I would be able to use Lisp to guide me as to what to wear:
> (looks-cool (make-instance 'too-stiff))
NIL
> (looks-cool (make-instance 'scottish))
T
> (looks-cool (make-instance 'also-good))
T
> (looks-cool (make-instance 'too-crazy))
NIL
I am well aware that this is a rather artificial example of no practical importance. Still, I would like to know whether there is some deeper reason behind or whether the restriction to the nine functions is just to make implementation easier.
Use the standard Common Lisp macro DEFINE-METHOD-COMBINATION to define your own simple method combinations:
Example:
(define-method-combination xor :identity-with-one-argument t)
Then:
CL-USER 5 > (mapcar #'looks-cool
(list (make-instance 'too-stiff)
(make-instance 'scottish)
(make-instance 'also-good)
(make-instance 'too-crazy)))
(NIL T T NIL)
If we look at (define-method-combination xor :identity-with-one-argument t)
, it has several meanings for the name xor
:
it uses an operator xor
- a function, macro or special form - not only functions are allowed. If the operator name should be different from the method combination name -> use the :operator
keyword to specify that.
it defines a method combination named xor
. This name can be used in defgeneric
.
it defines a method qualifier xor
. This can be used in defmethod
.
Note that one can also define more complex method combinations with that DEFINE-METHOD-COMBINATION
.