Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of the `intern` function?

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.

like image 860
dangom Avatar asked Oct 02 '16 16:10

dangom


People also ask

What are the responsibilities of an intern students?

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.

What is the use of intern () in Java?

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.


2 Answers

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.

like image 129
Rainer Joswig Avatar answered Nov 15 '22 10:11

Rainer Joswig


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.

like image 27
sds Avatar answered Nov 15 '22 09:11

sds