Specialize Generic Function (Multimethod) on Two Arguments - lisp

I am trying to build a binary search tree in common lisp. I have defined the binary search class using the CLOS like this:
(defclass bst ()
((root :type node
:accessor tree-root
:initform nil
:initarg root)))
I am trying to define a generic function that takes in the tree object and a key and returns a boolean true if the tree contains the key and nil if the tree does not contain the key.
Right now I have the following definition of a generic function:
(defgeneric contains ((tree bst) (key))
(:documentation "returns boolean of whether the given tree contains a particular key)
I get the following error when I load the file into the REPL (I am using SBCL):
Required argument is not a symbol: (TREE BST)
Am I misunderstanding how generic functions work? I can't seem to define the function properly.

Yes, defgeneric defines a generic function. You can either specify methods in the call to defgeneric or by using defmethod.
You need one of:
(defgeneric contains (tree key)
(:documentation "returns boolean of whether the given tree contains a particular key")
(:method ((tree bst) key) ...))
or:
(defgeneric contains (tree key)
(:documentation "returns boolean if a given tree contains a given key"))
(defmethod contains ((tree bst) key)
...)

Related

how to specify that a method argument is a list of (e.g.) string

In CLOS, how to specify that a method argument is a list of (e.g.) strings?
e.g. something like:
(defmethod m1 ((x (every 'string)))
(dolist (y x) (print (char y 0))))
You can't. Methods can only be specialized on classes, not types. You could manually define the type list-of-strings with deftype and satisfies, but it would still be invalid to use it as a specializer in a defmethod.
From the defmethod entry of the CLHS:
Only required parameters can be specialized. If parameter-specializer-name is a symbol it names a class.

Common Lisp: pass by value vs pass by reference [duplicate]

This question already has answers here:
Common lisp push from function
(4 answers)
Closed 1 year ago.
I want to write a function in Common Lisp, which destructively modifies its argument. In C or Rust I would use a pointer/reference to an object, which can be dereferenced inside the body of the function. In CL I write:
(defun foo (lst)
(setf lst NIL))
But after evaluating this form:
(let ((obj (list "a" "b")))
(foo obj)
obj) => ("a" "b")
one sees that the function foo has no effect. I can explain that by pass by value semantic, where we modify a local copy of the argument pushed onto the function stack.
If we define another function:
(defun bar (lst)
(setf (car lst) NIL))
and evaluate a similar form
(let ((obj (list "a" "b")))
(bar obj)
obj) => (NIL "b")
we will clearly see that the lst was modified as if we would use the pass by reference semantic. So, (setf lst NIL) did not worked but (setf (car lst) NIL) did. Could you please explain why?
Common Lisp passes arguments by value, but in most cases (other than primitive value types like fixnums or floats) the value is a reference. This is the same way that most managed languages work (e.g. Java, Python, JS).
In the LET-form, the value of the variable OBJ is a reference to a list, not the list itself. That reference is passed by value, so that inside the functions, the value of the parameter LST is another reference to the same list.
In FOO, the reference value is replaced with NIL, but the list that was previously referred to is not touched at all. In BAR, the list is retrieved from the heap and its CAR is replaced with NIL. Since OBJ holds a reference to the same list, the modification affects it as well.
For some operations the usual style is this:
(let ((obj (list "a" "b")))
(setf obj (nbar obj)) ; nbar is destructively modifying the list argument
(foo obj))
Above uses SETF to use the return value to change the binding of obj, since the function nbar itself can't do it.
Since NBAR has no access to the lexical variable obj and thus can't change it, one is supposed to return the object from NBAR and then one sets the variable to the result value - overwriting the previous binding.
Examples, where this rule is applicable: calls to sort, nreverse, ...

Common Lisp: How to quote parenthese in SBCL

In Common Lisp, the special operator quote makes whatever followed by un-evaluated, like
(quote a) -> a
(quote {}) -> {}
But why the form (quote ()) gives me nil? I'm using SBCL 1.2.6 and this is what I got in REPL:
CL-USER> (quote ())
NIL
More about this problem: This is some code from PCL Chapter 24
(defun as-keyword (sym)
(intern (string sym) :keyword))
(defun slot->defclass-slot (spec)
(let ((name (first spec)))
`(,name :initarg ,(as-keyword name) :accessor ,name)))
(defmacro define-binary-class (name slots)
`(defclass ,name ()
,(mapcar #'slot->defclass-slot slots)))
When the macro expand for the following code:
(define-binary-class id3-tag
((major-version)))
is
(DEFCLASS ID3-TAG NIL
((MAJOR-VERSION :INITARG :MAJOR-VERSION :ACCESSOR MAJOR-VERSION)))
which is NIL rather than () after the class name ID3-TAG.
nil and () are two ways to express the same concept (the empty list).
Traditionally, nil is used to emphasize the boolean value "false" rather than the empty list, and () is used the other way around.
The Common LISP HyperSpec says:
() ['nil], n. an alternative notation for writing the symbol nil, used
to emphasize the use of nil as an empty list.
Your observation is due to an object to having more than one representation. In Common Lisp the reader (that reads code and reads expressions) parses text to structure and data. When it's data the writer can print it out again but it won't know exactly how the data was represented when it was initially read in. The writer will print one object exactly one way, following defaults and settings, even though there are several representations for that object.
As you noticed nil, NIL, nIL, NiL, ... ,'nil, 'NIL, (), and '() are all read as the very same object. I'm not sure the standard dictates exactly how it's default representation out should be so I guess some implementations choose one of NIL, nil or maybe even ().
With cons the representation is dependent on the cdr being a cons/nil or not:
'(a . nil) ; ==> (a)
'(a . (b . c)) ; ==> (a b . c)
'(a . (b . nil)) ; ==> (a b)
With numbers the reader can get hints about which base you are using. If no base is used in the text it will use whatever *read-base* is:
(let ((*read-base* 2)) ; read numbers as boolean
(read-from-string "(10 #x10)")) ; ==> (2 16)
#x tells the reader to interpret the rest as a hexadecimal value. Now if your print-base would have been 4 the answer to the above would have been visualized as (2 100).
To sum it up.. A single value in Common Lisp may have several good representations and all of them would yield the very same value. How the value is printed will follow both implementation, settings and even arguments to the functions that produce them. Neither what it accepts as values in or the different ways it can visualize the value tells nothing about how the value actually gets stored internally.

combining two variables into one function name in macro

I was toying around with macros and clos, where I created an "object" macro to create instances
(defmacro object (class &rest args)
`(make-instance ',class ,#args))
Now doing this, I also ended up kind of wanting to do something similar for accessor functions created by clos. Example:
(defclass person () ((name :accessor person-name :initarg :name)))
then creating the instance
(setf p1 (object person :name "tom"))
now to get the name from the object obviously I would call person-name, however just as with the object macro, I wanted to create a "gets" macro to do this. So ideally:
(gets person name p1) which then would return the name.
The problem then is the binding of person and name (person-name) and how to do that. Is there anyway to get those two arguments bound together in the macro? sort of like:
(defmacro gets (class var object)
`(,class-,var ,object))
I think I may have misunderstood the original intent. At first I thought you were asking how to generate the accessor names for the class definition, which third part of the answer addresses. After reading through a second time, it actually sounds like you want to generate a new symbol and call it with some argument. That's easy enough too, and is given in the second part of this answer. Both the second and third parts depend on being able to create a symbol with a name that's built from the names of other symbols, and that's what we start with.
"Concatenating" symbols
Each symbol has a name (a string) that you can obtain with symbol-name. You can use concatenate to create a new string from some old strings, and then use intern to get a symbol with the new name.
(intern (concatenate 'string
(symbol-name 'person)
"-"
(symbol-name 'name)))
;=> PERSON-NAME
Reconstructing an accessor name
(defmacro gets (class-name slot-name object)
(let ((accessor-name
(intern (concatenate 'string
(symbol-name class-name)
"-"
(symbol-name slot-name))
(symbol-package class-name))))
`(,accessor-name ,object)))
(macroexpand-1 '(gets person name some-person))
;=> (PERSON-NAME SOME-PERSON)
For a number of reasons, though, this isn't very robust. (i) You don't know whether or not the slot has an accessor of the form <class-name>-<slot-name>. (ii) Even if the slot does have an accessor of the form <class-name>-<slot-name>, you don't know what package it's in. In the code above, I made the reasonable assumption that it's the same as the package of the class name, but that's not at all required. You could have, for instance:
(defclass a:person ()
((b:name :accessor c:person-name)))
and then this approach wouldn't work at all. (iii) This doesn't work with inheritance very well. If you subclass person, say with north-american-person, then you can still call person-name with a north-american-person, but you can't call north-american-person-name with anything. (iv) This seems to be reïnventing slot-value. You can already access the value of a slot using the name of the slot alone with (slot-value object slot-name), and I don't see any reason that your gets macro shouldn't just expand to that. There you wouldn't have to worry about the particular name of the accessor (if it even has one), or the package of the class name, but just the actual name of the slot.
Generating accessor names
You just need to extract the names of the symbols and to generate a new symbol with the desired name.
If you want to automatically generate accessors with defstruct style names, you can do it like this:
(defmacro define-class (name direct-superclasses slots &rest options)
(flet ((%slot (slot)
(destructuring-bind (slot-name &rest options)
(if (listp slot) slot (list slot))
`(,slot-name ,#options :accessor ,(intern (concatenate 'string
(symbol-name name)
"-"
(symbol-name slot-name)))))))
`(defclass ,name ,direct-superclasses
,(mapcar #'%slot slots)
,#options)))
You can check that this produces the kind of code that you'd expect by looking at the macroexpansion:
(pprint (macroexpand-1 '(define-class person ()
((name :type string :initarg :name)
(age :type integer :initarg :age)
home))))
(DEFCLASS PERSON NIL
((NAME :TYPE STRING :INITARG :NAME :ACCESSOR PERSON-NAME)
(AGE :TYPE INTEGER :INITARG :AGE :ACCESSOR PERSON-AGE)
(HOME :ACCESSOR PERSON-HOME)))
And we can see that it works as expected:
(define-class person ()
((name :type string :initarg :name)
(age :type integer :initarg :age)
home))
(person-name (make-instance 'person :name "John"))
;=> "John"
Other comments on your code
(defmacro object (class &rest args)
`(make-instance ',class ,#args))
As Rainer pointed out this isn't very useful. For most cases, it's the same as
(defun object (class &rest args)
(apply 'make-instance class args))
except that you can (funcall #'object …) and (apply #'object …) with the function, but you can't with the macro.
Your gets macro isn't really any more useful than slot-value, which takes an object and the name of a slot. It doesn't require the name of the class, and it will work even if the class doesn't have a reader or accessor.
Don't (naïvely) create symbol names with format
I've been creating symbol names with concatenate and symbol-name. Sometimes you'll see people use format to construct the names, e.g., (format nil "~A-~A" 'person 'name), but that's prone to issues with capitalization settings that can be changed. For instance, in the following, we define a function foo-bar, and note that the format based approach fails, but the concatenate based approach works.
CL-USER> (defun foo-bar ()
(print 'hello))
FOO-BAR
CL-USER> (foo-bar)
HELLO
HELLO
CL-USER> (setf *print-case* :capitalize)
:Capitalize
CL-USER> (funcall (intern (concatenate 'string (symbol-name 'foo) "-" (symbol-name 'bar))))
Hello
Hello
CL-USER> (format nil "~a-~a" 'foo 'bar)
"Foo-Bar"
CL-USER> (intern (format nil "~a-~a" 'foo 'bar))
|Foo-Bar|
Nil
CL-USER> (funcall (intern (format nil "~a-~a" 'foo 'bar)))
; Evaluation aborted on #<Undefined-Function Foo-Bar {1002BF8AF1}>.
The issue here is that we're not preserving the case of the symbol names of the arguments. To preserve the case, we need to explicitly extract the symbol names, rather than letting the print functions map the symbol name to some other string. To illustrate the problem, consider:
CL-USER> (setf (readtable-case *readtable*) :preserve)
PRESERVE
;; The symbol-names of foo and bar are "foo" and "bar", but
;; you're upcasing them, so you end up with the name "FOO-BAR".
CL-USER> (FORMAT NIL "~{~A~^-~}" (MAPCAR 'STRING-UPCASE '(foo bar)))
"FOO-BAR"
;; If you just concatenate their symbol-names, though, you
;; end up with "foo-bar".
CL-USER> (CONCATENATE 'STRING (SYMBOL-NAME 'foo) "-" (SYMBOL-NAME 'bar))
"foo-bar"
;; You can map symbol-name instead of string-upcase, though, and
;; then you'll get the desired result, "foo-bar"
CL-USER> (FORMAT NIL "~{~A~^-~}" (MAPCAR 'SYMBOL-NAME '(foo bar)))
"foo-bar"
This function creates symbols from string designators:
(defun symb (&rest args)
(intern (format nil "~{~a~^-~}" (mapcar #'string args))))
The function uses format, yet passes Joshua's test:
CL-USER> (symb 'foo :bar "BAZ")
FOO-BAR-BAZ
NIL
CL-USER> (defun foo-bar ()
(print 'hello))
FOO-BAR
CL-USER> (foo-bar)
HELLO
HELLO
CL-USER> (setf *print-case* :capitalize)
:Capitalize
CL-USER> (funcall (symb 'foo 'bar))
Hello
Hello
If you want your gets to use accessor methods:
(defmacro gets (class var object)
`(,(intern (format nil "~a-~a" (symbol-name class) (symbol-name var))) ,object))
In general, what you're trying to accomplish is not really useful. make-instance is a well known symbol, easily greppable, part of the standard and optimized by some implementations when the class name is constant. So with your object macro, you're just saving a few characters and a single-quote. Usually, one hides make-instance in specific cases where you don't want to provide a direct way to initialize instances, or more likely, when you want to provide layers of initialization (e.g. phases of initialization, Lisp slots and foreign objects).
PS: I remember vaguely that someone prominent in the standardization of Common Lisp argued in favor of always wrapping/hiding make-instance in a function (e.g. make-<class-name>), but I can't find either a reference or the reasoning.
PPS: Here's a rather old discussion (2004) about it in comp.lang.lisp (and another one from 2002). The main reasons people cite in favor of constructor functions are:
Required arguments; achievable at runtime instead of at compile-time with :initform (error ...) in a slot that requires a provided initial value
Generally, hide implementation details: class instance, structure instance, cons, something else
2.1. Not wanting to export the actual class name
2.2. Being able to return an instance of some other class, usually a subclass
Convenient shorthand for a specific class
I striked always, because it seems proponents to constructor functions for CLOS objects don't necessarily want to hide the protocol that make-instance follows (allocate-instance, initialize-instance → shared-initialize) to implementers or extenders of the API or framework, although they might want to hide it to the consumers of the API or framework.
For something faster, you might want to access slots directly, but that doesn't use accessor methods, and hence doesn't support side-effects, e.g. :before and :after methods:
(defmacro gets (class var object)
(let ((object-var (gensym)))
`(let ((,object-var ,object))
(declare (optimize (speed 3) (safety 0) (debug 0))
(type ,class ,object-var))
(slot-value ,object-var ',var))))
This might be a direct slot access on some implementations.
Finally, you also have with-slots and with-accessors in the standard.
Try playing with something like this:
(let ((a 'a)
(dash '-)
(b 'b))
`(,a,dash,b))
The other possibilities is to use intern, or more user friendly, alexandria's symbolicate.

How to change the elements obj to alist in cl-mongo?

The db.find will return the documents in MongoDB.
I want to get all the elements of the document and then change to alist.
But I have not found the function to get the elements.
I found elements is the hashmap in document, and it has a accessor called elements.
But when I use (elements docTmp) in my own package, it return that there is no function called elements.
I'd suggest not to go digging in the internals of the document but to use the provided function mapdoc . You can also consider the recursive parsing to convert the possible subdocuments to alists too. So the code may look like this:
(defgeneric mongo-document->alist (doc))
(defmethod mongo-document->alist ((doc cl-mongo:document))
(let ((alist '()))
(cl-mongo:mapdoc (lambda (key value)
(push
(cons
key
(mongo-document->alist value))
alist))
doc)
alist))
(defmethod mongo-document->alist ((obj t))
obj)