Common Lisp the Language, 2nd Edition
Next: Common Lisp Object
Up: Pretty Printing
Previous: Compiling Format
Control
When *print-pretty*
is not nil
, the pprint
dispatch table in the variable *print-pprint-dispatch*
controls how objects are printed. The information in this table takes
precedence over all other mechanisms for specifying how to print
objects. In particular, it overrides user-defined
print-object
methods and print functions for structures.
However, if there is no specification for how to pretty print a
particular kind of object, it is then printed using the standard
mechanisms as if *print-pretty*
were nil
.
A pprint dispatch table is a mapping from keys to pairs of values.
The keys are type specifiers. The values are functions and numerical
priorities. Basic insertion and retrieval is done based on the keys with
the equality of keys being tested by equal
. The function to
use when pretty printing an object is chosen by finding the highest
priority function in *print-pprint-dispatch*
that is
associated with a type specifier that matches the object.
[Function]
copy-pprint-dispatch &optional
table
A copy is made of table, which defaults to the current
pprint dispatch table. If table is nil
, a copy is
returned of the initial value of
*print-pprint-dispatch*
.
[Function]
pprint-dispatch
object
&optional
table
This retrieves the highest priority function from a pprint table that
is associated with a type specifier in the table that matches
object. The function is chosen by finding all the type
specifiers in table that match the object and selecting the
highest priority function associated with any of these type specifiers.
If there is more than one highest priority function, an arbitrary choice
is made. If no type specifiers match the object, a function is returned
that prints object with *print-pretty*
bound to
nil
.
As a second return value, pprint-dispatch
returns a flag
that is t
if a matching type specifier was found in
table and nil
if not.
Table (which defaults to
*print-pprint-dispatch*
) must be a pprint dispatch table.
Table can be nil
, in which case retrieval is done
in the initial value of *print-pprint-dispatch*
.
When *print-pretty*
is t
,
(write object :stream s)
is equivalent to
(funcall (pprint-dispatch object) s object)
.
[Function]
set-pprint-dispatch
type
function
&optional
priority
table
This puts an entry into a pprint dispatch table and returns
nil
. The type must be a valid type specifier and
is the key of the entry. The first action of
set-pprint-dispatch
is to remove any pre-existing entry
associated with type. This guarantees that there will never be
two entries associated with the same type specifier in a given pprint
dispatch table. Equality of type specifiers is tested by
equal
.
Two values are associated with each type specifier in a pprint
dispatch table: a function and a priority. The function must
accept two arguments: the stream to send output to and the object to be
printed. The function should pretty print the object on the
stream. The function can assume that object satisfies
type. The function should obey
*print-readably*
. Any values returned by the
function are ignored.
The priority (which defaults to 0) must be a non-complex number. This number is used as a priority to resolve conflicts when an object matches more than one entry. An error is signaled if priority fails to be a non-complex number.
The table (which defaults to the value of
*print-pprint-dispatch*
) must be a pprint dispatch table.
The specified entry is placed in this table.
It is permissible for function to be nil
. In
this situation, there will be no type entry in table
after set-pprint-dispatch
is evaluated.
To facilitate the use of pprint dispatch tables for controlling the
pretty printing of Lisp code, the type-specifier argument of
the function set-pprint-dispatch
is allowed to contain the
form (cons
car-type cdr-type)
. This
form indicates that the corresponding object must be a cons whose
car satisfies the type specifier car-type and whose
cdr satisfies the type specifier cdr-type. The
cdr-type can be omitted, in which case it defaults to
t
.
The initial value of *print-pprint-dispatch*
is
implementation-dependent. However, the initial entries all use a special
class of priorities that are less than every priority that can be
specified using set-pprint-dispatch
. This guarantees that
pretty printing functions specified by users will override everything in
the initial value of *print-pprint-dispatch*
.
Consider the following examples. The first form restores
*print-pprint-dispatch*
to its initial value. The next two
forms then specify a special way of pretty printing ratios. Note that
the more specific type specifier has to be associated with a higher
priority.
(setq *print-pprint-dispatch*
(copy-pprint-dispatch nil))
(defun div-print (s r colon? atsign?)
(declare (ignore colon? atsign?))
(format s "(/ ~D ~D)" (numerator (abs r)) (denominator r)))
(set-pprint-dispatch 'ratio (formatter "#.~/div-print/"))
(set-pprint-dispatch '(and ratio (satisfies minusp))
(formatter "#.(- ~/div-print/)")
5)
(pprint '(1/3 -2/3)) prints: (#.(/ 1 3) #.(- (/ 2 3)))
The following two forms illustrate the specification of pretty
printing functions for particular types of Lisp code. The first form
illustrates how to specify the traditional method for printing quoted
objects using ``'
’’ syntax. Note the care taken to ensure
that data lists that happen to begin with quote
will be
printed readably. The second form specifies that lists beginning with
the symbol my-let
should print the same way that lists
beginning with let
print when the initial pprint dispatch
table is in effect.
(set-pprint-dispatch '(cons (member quote))
#'(lambda (s list)
(if (and (consp (cdr list)) (null (cddr list)))
(funcall (formatter "'~W") s (cadr list))
(pprint-fill s list)))))
(set-pprint-dispatch '(cons (member my-let))
(pprint-dispatch '(let) nil))
The next example specifies a default method for printing lists that
do not correspond to function calls. Note that, as shown in the
definition of pprint-tabular
above,
pprint-linear
, pprint-fill
, and
pprint-tabular
are defined with optional colon and atsign
arguments so that they can be used as pprint dispatch functions as well
as ~/.../
functions.
(set-pprint-dispatch
'(cons (not (and symbol (satisfies fboundp))))
#'pprint-fill
-5)
With a line length of 9,
(pprint '(0 b c d e f g h i j k))
prints:
(0 b c d
e f g h
i j k)
This final example shows how to define a pretty printing function for a user defined data structure.
(defstruct family mom kids)
(set-pprint-dispatch 'family
#'(lambda (s f)
(format s "~@<#<~;~W and ~2I~_~/pprint-fill/~;>~:>"
(family-mom f) (family-kids f))))
The pretty printing function for the structure family
specifies how to adjust the layout of the output so that it can fit
aesthetically into a variety of line widths. In addition, it obeys the
printer control variables *print-level*
,
*print-length*
, *print-lines*
,
*print-circle*
, *print-shared*
, and
*print-escape*
, and can tolerate several different kinds of
malformity in the data structure. The output below shows what is printed
out with a right margin of 25, *print-pretty*
t
, *print-escape* nil
, and a malformed
kids
list.
(write (list 'principal-family
(make-family :mom "Lucy"
:kids '("Mark" "Bob" . "Dan")))
:right-margin 25 :pretty T :escape nil :miser-width nil)
(PRINCIPAL-FAMILY
#<Lucy and
Mark Bob . Dan>)
Note that a pretty printing function for a structure is different from the structure’s print function. While print functions are permanently associated with a structure, pretty printing functions are stored in pprint dispatch tables and can be rapidly changed to reflect different printing needs. If there is no pretty printing function for a structure in the current print dispatch table, the print function (if any) is used instead.
Next: Common Lisp Object
Up: Pretty Printing
Previous: Compiling Format
Control
AI.Repository@cs.cmu.edu