Next: , Previous: , Up: Quoting   [Contents][Index]


14.4.3 Quoting with ` (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 ‘,’ marker

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.

The ‘,@’ marker

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)

The ‘,.’ marker

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: , Previous: , Up: Quoting   [Contents][Index]