listemacslispelispcons

What's the point of building a list with a non-list tail?


The Emacs lisp manual states about the function nconc that:

Since the last argument of nconc is not itself modified, it is reasonable to use a constant list, such as '(4 5), as in the above example. For the same reason, the last argument need not be a list

And indeed I can write

(setq x '(1 2 3))
=> (1 2 3)

(nconc x 0)
=> (1 2 3 . 0)

but that yields a totally broken list:

(length x)
=> eval: Wrong type argument: listp, 0

(butlast x)
=> butlast: Wrong type argument: listp, 0

Solution

  • They're not "broken" lists; they're actually known as improper lists (as opposed to nil-terminated lists, which are proper lists). Many list functions, such as length and butlast that you just named, expect proper lists. To distinguish proper lists from improper lists, you can use proper-list-p.

    Improper lists are used in association lists (where the associations are often not proper; though the alist itself must be proper).


    If you want to make an improper list proper, you have two options:

    Here's a procedure I wrote called properise which will do the former:

    (defun properise (x)
      (let ((r nil))
        (while (consp x)
          (push (pop x) r))
        (nreverse r)))
    

    (If you want the latter behaviour, add (unless (null x) (push x r)) just before the nreverse line.)