It is best to avoid #' in most instances because it is "mostly" unnecessary and makes your code more verbose. There are a few exceptions when some form of quoting is necessary (see Example 4 below).
Note: All the examples in this post have been tested in Emacs Lisp (GNU Emacs 25.2.1), but they should work identically in any ANSI common lisp. The basic concepts are the same in both dialects.
SIMPLE EXPLANATION
First, let us study a case when it is best to avoid quoting. Functions are first class objects (e.g. treated like any other object, including the ability to pass them to functions and assign them to variables) that evaluate to themselves. Anonymous functions (e.g. lambda forms) are one such example. Try the following on Emacs Lisp (M-x ielm RET) or ANY ANSI common lisp.
((lambda (x) (+ x 10)) 20) -> 30
Now, try the quoted version
(#'(lambda (x) (+ x 10)) 20) -> "function error" or "invalid function..."
If you use insist on using #', you have to write
(funcall #'(lambda (x) (+ x 10)) 20) -> 30
DETAILED EXPLANATION
To really understand when quoting is required, one must know how Lisp evaluates expressions. Read on. I promise to make this succinct.
You need to know a few basic facts about Lisp:
- Lisp "always" evaluates every expression. Well, unless the expression is quoted, in which case it is returned unevaluated.
- Atoms evaluate to themselves. Atomic expressions are NOT lists. Examples include numbers, strings, hash tables, and vectors.
- Symbols (variable names) store two types of values. They can hold regular values and functional definitions. Hence, Lisp symbols have two slots called cells to store these two types. Non-functional content is typically held in the symbol's value cell and functions in the function cell. The ability to hold both non-functional and functional definitions simultaneously place Emacs Lisp and Common Lisp in the 2-Lisp category. Which of the two cells is used in an expression depends on how the symbol is used -- more specifically its position in a list. In contrast, symbols in some dialects of Lisp, Scheme being the best known, can hold only one value. Scheme has no concept of value and function cells. Such Lisps are collectively called 1-Lisps.
Now, you need a rough understanding of how Lisp evaluates S-expressions (parenthetical expressions). Every S-expression is evaluated roughly as follows:
- If quoted, return it unevaluated
- If unquoted, get its CAR (e.g. first element) and evaluate it using the following rules:
a. if an atom, simply return its value (e.g. 3 -> 3, "pablo" -> "pablo")
b. if an S-expression, evaluate it using the same overall procedure
c. if a symbol, return the contents of its function cell
- Evaluate each of the elements in the CDR of the S-expression (e.g. all but the first element of the list).
- Apply the function obtained from the CAR to the values obtained from each of the elements in the CDR.
The above procedure implies that any symbol in the CAR of an UNQUOTED S-expression must have a valid functional definition in its function cell.
Now, let's go back to the example from the beginning of the post. Why does
(#'(lambda (x) (+ x 10)) 20)
generate an error? It does because #'(lambda (x) (+ x 10)), the CAR of the S-expression, is not evaluated by the Lisp interpreter due to the functional quote #'.
#'(lambda (x) (+ x 10))
is not a function, but
(lambda (x) (+ x 10))
is. Keep in mind that the purpose of quoting is to prevent evaluation. On the other hand, a lambda form evaluates to itself, a functional form, which is valid as the CAR of an UNQUOTED list. When Lisp evaluates the CAR of
((lambda (x) (+ x 10)) 20)
it gets (lambda (x) (+ x 20))
, which is a function that can be applied to the rest of the arguments in a list (provided the length of the CDR equals the number of arguments allowed by the lambda expression). Hence,
((lambda (x) (+ x 10)) 20) -> 30
The question is thus when to quote functions or symbols holding functional definitions. The answer is almost NEVER unless you do things "incorrectly." By "incorrectly" I mean that you place a functional definition in a symbol's value cell or functional cell when you should do the opposite. See the following examples to gain a better understanding:
EXAMPLE 1 - Functions Stored in Value Cells
Suppose you need to use apply
with a function that expects a variable number of arguments. One such example is the symbol +
. Lisp treats +
as a regular symbol. The functional definition is stored in +
's functional cell. You can assign a value to its value cell if you like using
(setq + "I am the plus function").
If you evaluate
+ -> "I am the plus function"
However, (+ 1 2)
still works as expected.
(+ 1 2) -> 3
The function apply is quite useful in recursion. Suppose you want to sum all the elements in a list. You CANNOT write
(+ '(1 2 3)) -> Wrong type...
The reason is that + expects its arguments to be numbers. apply solves this problem
(apply #'+ '(1 2 3)) -> (+ 1 2 3) -> 6
Why did I quote + above? Remember the evaluation rules I outlined above. Lisp evaluates the symbol apply by retrieving the value stored in its function cell. it gets a functional procedure it can apply to a list of arguments. However, if I do not quote +
, Lisp will retrieve the value stored in its value cell because it is NOT the first element in the S-expression. Because we set +
's value cell to "I am the plus function," Lisp does not get the functional definition held in +'s function cell. Actually, if we had not set its value cell to "I am the plus function," Lisp would have retrieved nil, which is NOT a function, as required by apply.
Is there a way to use +
unquoted with apply? Yes, there is. You can just evaluate the following code:
(setq + (symbol-function '+))
(apply + '(1 2 3))
This will evaluate to 6
, as expected because as Lisp evaluates (apply + '(1 2 3))
it now finds the functional definition of + stored in +'s value cell.
EXAMPLE 2 - Storing Functional Definitions in Value Cells
Suppose you store a functional definition in the symbol's value cell. This is achieve as follows:
(setq AFunc (lambda (x) (* 10 x)))
Evaluating
(AFunc 2)
generates an error because Lisp cannot find a function in AFunc
's function cell. You get around this by using funcall, which tells Lisp to use the value in the symbol's value cell as a functional definition. You do this using "funcall."
(funcall AFunc 2)
Assuming the functional definition stored in the symbol's value cell is valid,
(funcall AFunc 2) -> 20
You could avoid having using funcall
by placing the lambda form in the symbol's function cell using fset
:
(fset 'AFunc (lambda (x) (* 10 x)))
(AFunc 2)
This code block will return 20
because lisp finds a functional definition in AFunc
's function cell.
EXAMPLE 3 - Local Functions
Say you are writing a function and need a function that won't be used anywhere else. A typical solution is to define a function valid only inside the scope of the main one. Try this:
(defun SquareNumberList (AListOfIntegers)
"A silly function with an unnecessary
local function."
(let ((Square (lambda (ANumber) (* ANumber ANumber))))
(mapcar Square AListOfIntegers)
)
)
(SquareNumberList '(1 2 3))
This code block will return
(1 4 9)
The reason Square is not quoted in the above example is that S-expression is evaluated according to the rules I outlined above. First, Lisp pulls the functional definition of mapcar
. Next, Lisp pulls the contents of its second argument's (e.g. 'Square) value cell. Finally, it returns (1 2 3)
unevaluated for the third argument.
EXAMPLE 4 - Contents of a Symbol's Value and Function Cells
Here is one case when quotes are required.
(setq ASymbol "Symbol's Value")
(fset 'ASymbol (lambda () "Symbol's Function"))
(progn
(print (format "Symbol's value -> %s" (symbol-value 'ASymbol)))
(print (format "Symbol's function -> %s" (symbol-function 'ASymbol)))
)
The above code will evaluate to
"Symbol's value -> Symbol's Value"
"Symbol's function -> (lambda nil Symbol's Function)"
nil
Quote are required in
(fset 'ASymbol (lambda () "Symbol's Function"))
and
(symbol-value 'ASymbol)
and
(symbol-function 'ASymbol)
because otherwise Lisp would get the value of ASymbol in each case, preventing fset
, symbol-value, and symbol-function from working correctly.
I hope this lengthy post proves useful to someone.