The less-familiar parts of Lisp for beginners — pprint-dispatch

As we continue through the list of less familiar features of Common Lisp, we’re going to spend a bit of time in the pretty-printing code.  As you recall from the previous article, pretty-printing is a way to format human-readable output for better legibility, typically by the introduction of additional whitespace.  So, the first function we’ll discuss is pprint-dispatch.  This is not a function that the programmer is likely to invoke directly, but is involved in the handling of the pprint function, or other printing functions with the *print-pretty* variable set to non-nil.  The specific behaviour of pprint-dispatch depends on a standard-defined special variable, *print-pprint-dispatch*.

The table in *print-pprint-dispatch* maps types to functions and corresponding numerical priorities.  There is an implementation-defined startup table that may contain entries, but with priorities guaranteed to be lower than any entry a user might add later with set-pprint-dispatch.

Once more, this is becoming a bit abstract, so I’m now going to describe a typical invocation sequence, as I expect that will make things clearer.

  1. The Lisp instance is asked to print a certain object while *print-pretty* is non-nil.
  2. The Lisp printer calls pprint-dispatch to find the function that it should use for pretty-printing of this type of object.
  3. The type of the object is compared against the types in the table (recall that an object can, and often does, match more than one type).
  4. That entry that has the highest priority is chosen.  This will never be a default function if a user-defined function exists for any type that matches the object.
  5. If there is more than one matching entry with the highest priority (i.e. a tie), one is selected in an implementation-defined manner and returned.
  6. If there is exactly one matching entry with the highest priority, the corresponding function is returned.
  7. If there is no matching entry, the generic non-pretty-printing entry point is returned.  Note, however, that as execution continues in this case, *print-pretty* still non-nil, so user-defined methods like print-object still have an opportunity to act differently based on that variable, if so desired.

A typical invocation construct, then, is (funcall (pprint-dispatch obj) stream obj), but recall that this is likely not to be invoked explicitly by the programmer, as the implementation does this internally.

Points to remember:

  • Entries in the *print-pprint-dispatch* table take priority over print-object methods specialized on the class, even if the former is as a result of matching a less-specific class than the latter.
  • When creating programmer-defined entries, you must avoid assigning the same priority to two different types if there is a way for a single object to match both types, as the behaviour in that case is implementation-defined.
  • There are two ways that *print-pretty* can change the printing behaviour.  The first, when a matching type is found in *print-pprint-dispatch*, and the second when there is no matching type in the table, but a user-defined print-object method inspects that variable and changes its behaviour accordingly.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

反垃圾邮件 / Anti-spam question * Time limit is exhausted. Please reload CAPTCHA.