I'm following an article where the author defines the following macro:
(defmacro make-is-integral-multiple-of (n)
(let ((function-name (intern (concatenate
'string
(symbol-name :is-integral-multiple-of- )
(write-to-string n)))))
`(defun ,function-name (x)
(equal 0 (mod x, n)))))
The macro is easy to read and understand, but I wonder: when and why do we explicitly need the intern
function?
Removing it breaks the macro, which then returns the error:
The value "IS-INTEGRAL-MULTIPLE-OF-3"
is not of type
(OR SYMBOL CONS).
Does that mean that intern
must be called every time the macro is supposed to define a new symbol? Are there any uses of intern
outside of a defmacro
statement? Insights are welcome.
Interns assist the company with tasks set out by various teams, such as research, data capturing and working closely with different team members to learn more about the company.
intern() method : In Java, when we perform any operation using intern() method, it returns a canonical representation for the string object. A pool is managed by String class. When the intern() method is executed then it checks whether the String equals to this String Object is in the pool or not.
Function names
The name of a function needs to be of type (OR SYMBOL CONS)
. This is required by the Common Lisp standard.
Thus the name needs to be a symbol or a list. Usually function names in Lisp have to be symbols. That they can be lists is relatively special for setf functions. In Common Lisp it can only be a list like (setf foo)
, with setf
as the first symbol. Other lists as function names are not allowed in plain Common Lisp. (side-note, the older Lisp Machine Lisp had other lists as function names).
(defun foo (bar) ; FOO is a symbol and the name of the function
(+ 42 bar))
The following is unusual and actually a feature of Common Lisp:
(defun (setf a) (new-value thing) ; (setf a) is the name of the function
(setf (first thing) new-value))
Generating Function Names with INTERN and MAKE-SYMBOL
So, if you want to generate a new function name, it needs to be a symbol. First generate the new name as a string and then generate a symbol from that string.
There are several ways to create a symbol. INTERN
will look if the symbol already exists in the package (the current package is the default). If it does not exist, it will create a new one and intern that symbol in that package.
One could also use MAKE-SYMBOL
to create a symbol, but that symbol would not be in any package. This makes it usually difficult to access that symbol.
Typically a function name should be a symbol, which is interned in some package. Only in rare situations, for example some cases of computed code, it can be useful to have an uninterned symbol as a function name.
intern
finds or creates a
symbol with the supplied name in a package.
This means that it has to be used when a macro creates a symbol.
The macro in your example is a fairly typical use case, except that people usually use uninterned symbols like #:is-integral-multiple-of-
instead of keywords :is-integral-multiple-of-
.
There are other situations when it could be useful.
Generally speaking, a package is a special purpose table mapping strings to symbols, and intern
corresponds to (setf gethash)
.
E.g., you can use one of the following approaches to keep your data:
(defvar *operators* (make-hash-table :test 'equal))
(defstruct operator name help function)
(defun make-op (name help function)
(setf (gethash name *operators*)
(make-operator :name name
:help help
:function function)))
(make-op "build-house"
"construct a house out of the supplied materials"
(lambda (bricks mortar) ...))
(funcall (operator-function (gethash "build-house" *operators*))
(list "brick1" "brick2" ...)
(make-mortar))
or
(defpackage #:operators)
(defun make-op (name help function)
(let ((op (intern name #:operators)))
(setf (symbol-value op) help
(fdefinition op) function)))
(make-op "build-house"
"construct a house out of the supplied materials"
(lambda (bricks mortar) ...))
(funcall #'operators::build-house
(list "brick1" "brick2" ...)
(make-mortar))
Operator name is asscessed using symbol-name
, help is symbol-value
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With