Next: Nested quoting, Previous: Quoting with function, Up: Quoting [Contents][Index]
`
(backquote)While '
quotes its expression completely it is very
complicated to quote, say, a list of several elements but leave one
element unquoted (i.e. evaluate it). The result would probably look
like:
(setq e 5) (list 'a 'b 'c 'd e 'e 'e 'e) ⇒ (a b c d 5 e e e)
In this sense, a backquote is somewhat the reverse operation of a
‘'’. Backquote allows you to quote the entire list, but
selectively evaluate elements of that list. However, in the simplest
case, it is identical to quote
. These two forms yield
identical results:
`(a list of (+ 2 3) elements) ⇒ (a list of (+ 2 3) elements)
'(a list of (+ 2 3) elements) ⇒ (a list of (+ 2 3) elements)
However, unlike quote
which has a special read-syntax,
backquoting is implemented as macro and the routines backquote
and `
do not coincide.
The special marker ‘,’ can be used inside of the argument to inhibit the quotation for this particular expression. Thus the backquote alternative of the motivation example above could be:
(setq e 10) `(a b c d ,e e e e) ⇒ (a b c d 10 e e e)
Please note, the comma is not treated specially by the lisp reader, thus it is a perfectly valid part of a symbol. If you want to protect against strange behaviour do not use a leading ‘,’ in your variable or function names. In reality symbols with leading commas can be of great use in nested quoting constructions, see Nested quoting. However, make sure that none of such bindings escapes to the normal lisp environment.
With the special marker ‘,@’ inside of a backquoted expression you can splice an evaluated value into the resulting list. The elements of the spliced list become elements at the same level as the other elements of the resulting list. The equivalent code without using ‘`’ is often unreadable.
Like the comma operator ‘,@’ is not treated specially by the lisp reader either. You will have to take care for symbol names with leading ‘,@’ in foreign (i.e. non-backquoting) contexts and their bindings yourself.
Let us now look at a more pragmatic example of backquoting.
(defun interior (function fix-arg) "Return the insertion of FIX-ARG in FUNCTION, that is a function which is derived from FUNCTION by fixating the first argument to FIX-ARG and keeping the rest variable. This process is often referred to as currying. Mathematically it is a special interior product (hence the name)." (let* ((body (indirect-function function)) (args (cond ((subrp body) (error "Error: Cannot handle built-in functions.")) ((compiled-function-p body) (compiled-function-arglist body)) (t (cadr body)))) (newarglist (if args (cdr args) (error "Error: %s accepts no arguments." function))) (newargs (delq '&optional (copy-list newarglist)))) `(lambda ,newarglist (,function ',fix-arg ,@newargs)))) ⇒ interior
This definition is far from perfect but sufficient for our
purposes. Since we excluded built-in functions in the above code we
define a simple lisp equivalent of the list
function.
(defun list-demo (a b c d) "Return the list (A B C D)." (list a b c d)) ⇒ list-demo
(list-demo 1 'a 2 t) ⇒ (1 a 2 t)
Now we look at the interior product of ‘?a’ and
list-demo
.
(interior #'list-demo ?a) ⇒ (lambda (b c d) (list-demo (quote ?a) b c d))
As you can see, ,function
and ,fix-arg
have been
replaced with the according argument passed to interior
.
Additionally we quote the replace of ,fix-arg
to prevent
another expansion of the replacement during the call of the resulting
function. Also note how the list in newargs which had the local
binding ‘(b c d)’ within interior
has been spliced into the
function call expression.
(fset #'list-demo-a (interior #'list-demo ?a)) ⇒ (lambda (b c d) (list-demo (quote ?a) b c d)) (list-demo-a 'and 3 'args) => (?a and 3 args)
Now let’s have a glance at a prominent annoyance. The
function argument of the mapcar
function is passed
exactly one argument (an element of the given list). Sometimes it is
wishful to map a two-argument function whose first argument is
constant during the mapping anyway. In this scenario our
interior
comes in very handy.
(defvar demo-hook nil) => demo-hook (mapcar (interior #'add-hook 'demo-hook) '(first-fun another-fun)) ⇒ ((first-fun) (another-fun first-fun)) demo-hook ⇒ (another-fun first-fun)
Instead of the splicing operator ‘,@’ which internally uses
append
to splice an expression into the list at place, you can
always use the destructive form ‘,.’ instead which internally
uses nconc
. Refer to the documentation of nconc
for
more information, see Rearrangement.
(setq test-list '(a b)) ⇒ (a b)
`(,.test-list ,(+ 2 3)) ⇒ (a b 5) `(,.test-list ,(+ 3 4)) ⇒ (a b 5 7)
test-list ⇒ (a b 5 7)
Next: Nested quoting, Previous: Quoting with function, Up: Quoting [Contents][Index]