1
0
Fork 0
cl-sites/HyperSpec-7-0/HyperSpec/Issues/iss270_w.htm
2024-04-01 10:24:07 +02:00

1515 lines
132 KiB
HTML

<!-- Common Lisp HyperSpec (TM), version 7.0 generated by Kent M. Pitman on Mon, 11-Apr-2005 2:31am EDT -->
<HTML>
<HEAD>
<TITLE>CLHS: Issue PRETTY-PRINT-INTERFACE Writeup</TITLE>
<LINK HREF="../Data/clhs.css" REL="stylesheet" TYPE="text/css" />
<META HTTP-EQUIV="Author" CONTENT="Kent M. Pitman">
<META HTTP-EQUIV="Organization" CONTENT="LispWorks Ltd.">
<LINK REL=TOP HREF="../Front/index.htm">
<LINK REL=COPYRIGHT HREF="../Front/Help.htm#Legal">
<LINK REL=DISCLAIMER HREF="../Front/Help.htm#Disclaimer">
<LINK REL=PREV HREF="../Issues/iss269_w.htm">
<LINK REL=UP HREF="../Issues/iss270.htm">
<LINK REL=NEXT HREF="../Issues/iss271_w.htm">
</HEAD>
<BODY>
<H1><A REV=MADE HREF="http://www.lispworks.com/"><IMG WIDTH=80 HEIGHT=65 ALT="[LISPWORKS]" SRC="../Graphics/LWSmall.gif" ALIGN=Bottom></A><A REL=TOP HREF="../Front/index.htm"><IMG WIDTH=237 HEIGHT=65 ALT="[Common Lisp HyperSpec (TM)]" SRC="../Graphics/CLHS_Sm.gif" ALIGN=Bottom></A> <A REL=PREV HREF="../Issues/iss269_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="../Issues/iss270.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="../Issues/iss271_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
<HR>
<H2>Issue PRETTY-PRINT-INTERFACE Writeup</H2>
<PRE>Version 3 (by Guy Steele Jr) supersedes version 2 and is changed from<P>
version 1 as follows: adds a functional interface to supplement the<P>
interface through <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A>, and reflects comments by Barrett and<P>
Pierson.<P>
<P>
Version 4 (by Dick Waters) is changed from version 3 as follows: The<P>
short summary is updated to reflect the functional interface. The<P>
functional interface is changed following suggestions made by Dave Moon.<P>
The proposal is amended in a few minor ways to increase the<P>
compatibility with variable width fonts. Additional discussion has been<P>
added with regard to the advantages of XP with respect to handling<P>
detection and abbreviation, the interaction with CLOS, and<P>
the extended type specifier <A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>CONS</B></A> used by XP.<P>
<P>
Version 5 (by Waters, Haflich, Laubsch, Loosemore, Pierson, and van Roggen).<P>
On June 27 it was voted 12 to 4 in a plenary session of X3J13 that an add<P>
hoc committee on pretty printing be created containing the above members<P>
with the charter of ironing out the final details of the pretty print<P>
interface and that if this committee could come to a unanimous decision on<P>
the interface, the interface would become part of the draft Common Lisp<P>
<A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> without the need of a further vote by the full committee. The<P>
unanimity of the add hoc committee has been signaled by having each member<P>
of the committee send a message to X3J13 to this effect.<P>
In addition to the main vote above, five straw polls were taken. Three<P>
of these votes were overwhelming; however, two appeared too close to be<P>
definitive. In order of the clarity of the outcome the straw votes were:<P>
16-0 in favor of the basic functional interface,<P>
10-4 against the inclusion of #&quot;...&quot;,<P>
12-7 in favor of having some way to convert a <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string into a function,<P>
11-8 in favor of allowing <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> to take a function as well as a string,<P>
10-8 against the pretty printer extensions of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A>.<P>
The subcommittee followed these recommendations except for the last.<P>
(See <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> end of <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> discussion section.)<P>
Version 5 is changed from version 4 as follows: The names of the<P>
functions and variables have been changed to better reflect that (for the<P>
most part) they are a group that applies only to pretty printing. The<P>
variables *DEFAULT-RIGHT-MARGIN* and *LAST-ABBREVIATED-PRINTING* have been<P>
eliminated. The readmacro construct #&quot;...&quot; has been eliminated and a new<P>
macro <A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A> introduced in its place. The way <A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A><P>
abbreviation is indicated has been improved to ensure that the delimiters<P>
will be balanced in the output and to ensure that the reader will complain<P>
if you later try to read the output. The macros LOGICAL-BLOCK-POP and<P>
LOGICAL-BLOCK-COUNT have been eliminated and the functionality they<P>
supported provided in a slightly different form by two new macros<P>
<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A> and <A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A>. The macro<P>
DEFINE-PRINT-DISPATCH has been replaced by a function <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A>.<P>
The proposal has been reorganized to show that the functional interface is<P>
more fundamental than the <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface, to clarify exactly what happens<P>
in error situations, and to indicate that the examples are merely examples<P>
and not part of the proposal.<P>
<P>
================================================================================<P>
<P>
<B>Issue:</B> <A HREF="iss270.htm">PRETTY-PRINT-INTERFACE</A><P>
<P>
<B>References:</B> Description of XP by Dick Waters (attached)<P>
<A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> (CLtL p. 371)<P>
<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A> (CLtL p. 382)<P>
<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>PPRINT</B></A> (CLtL p. 383)<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> (CLtL pp. 385-407)<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> ~T directive (CLtL pp. 398-399)<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> ~&lt; directive (CLtL pp. 404-406)<P>
<P>
<B>Related issues: <P>
</B><P>
<B>Category:</B> CLARIFICATION CHANGE ADDITION<P>
<P>
<B>Edit history:</B> Version 1, 24-Feb-89 by Steele<P>
Version 2, 15-Mar-89 by Steele and Waters<P>
Version 3, 15-Mar-89 by Steele<P>
Version 4, 22-Mar-89 by Waters<P>
Version 5, 20-Jul-89 by Waters et al<P>
<P>
<B>Problem description:<P>
</B> At present, Common Lisp provides no specification whatsoever of how<P>
pretty-printing is to be accomplished, and no way for the user to control<P>
it. In particular, there is no protocol by which a user can write a<P>
print-function for a <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A>, or a <A REL=DEFINITION HREF="../Body/t_method.htm#method"><B>method</B></A> for <A REL=DEFINITION HREF="../Body/f_pr_obj.htm#print-object"><B>PRINT-OBJECT</B></A>, that will<P>
interact smoothly with the built-in pretty-printer in a portable manner.<P>
<P>
<B>Proposal (PRETTY-PRINT-INTERFACE:XP):<P>
</B><P>
Adopt the interfaces and protocols of the XP pretty-printer by Dick Waters,<P>
described in full in the attached document. Here is a very brief summary<P>
of the proposal.<P>
<P>
New variables: <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A><P>
<A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A><P>
<A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A><P>
<A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A><P>
<P>
New functions: <A REL=DEFINITION HREF="../Body/f_cp_ppr.htm#copy-pprint-dispatch"><B>COPY-PPRINT-DISPATCH</B></A><P>
<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A><P>
<A REL=DEFINITION HREF="../Body/f_ppr_di.htm#pprint-dispatch"><B>PPRINT-DISPATCH</B></A><P>
<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A><P>
<A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>PPRINT-TAB</B></A><P>
<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A><P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>PPRINT-FILL</B></A><P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-linear"><B>PPRINT-LINEAR</B></A><P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A><P>
<P>
New macros: <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A><P>
<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A><P>
<A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A><P>
<P>
New <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> directives: ~W ~_ ~I ~:T ~/name/ ~&lt;...~:&gt;<P>
<P>
The function <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A> is extended to accept four additional keyword arguments<P>
:PPRINT-DISPATCH, :RIGHT-MARGIN, :LINES, and :MISER-WIDTH corresponding to<P>
the four new variables.<P>
<P>
The function <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> is extended so that it can accept a function instead of<P>
a <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string. (This change is also made in the other functions that<P>
accept <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> strings such as <A REL=DEFINITION HREF="../Body/a_error.htm#error"><B>ERROR</B></A> and <A REL=DEFINITION HREF="../Body/f_warn.htm#warn"><B>WARN</B></A>.)<P>
<P>
Examples: See attached document.<P>
<P>
<B>Rationale:<P>
</B> There ought to be a good user interface to the pretty printer.<P>
This is the only proposal for which there is a portable implementation<P>
that has seen extensive use and is being made freely available.<P>
<P>
<B>Current practice:<P>
</B> XP son of PP son of GPRINT son of #PRINT is the latest in a line of pretty<P>
printers that goes back 13 years. All of these printers use essentially<P>
the same basic algorithm and conceptual interface. Further, except for<P>
#PRINT, which was implemented solely to satisfy the author's personal<P>
needs, each of these printers has had extensive use. XP has been in<P>
experimental use as the pretty printer in CMU Common Lisp for 6 months. PP<P>
has been the pretty printer in DEC Common Lisp for the past 3 years. Prior<P>
to three years ago, GPRINT was used for 2 years as the pretty printer in<P>
DEC Common Lisp. In addition, GPRINT has been the pretty printer in<P>
various generations of Symbolics Lisp for upwards of 5 years.<P>
(See Waters R.C., &quot;User Format Control in a Lisp Prettyprinter&quot;, ACM TOPLAS,<P>
5(4):513--531, October 1983.)<P>
<P>
Cost to Implementors: A fair amount of effort (several man-weeks at most).<P>
Source code for XP is available to all comers from Dick Waters. It has<P>
been arranged with MIT for anyone who wants to to get a non-exclusive<P>
royalty-free license for XP from MIT. The system is documented in great<P>
detail in:<P>
Waters, Richard C., &quot;XP: A Common Lisp Pretty Printing System&quot;,<P>
Artificial Intelligence Laboratory Technical Memo 1102a,<P>
Massachusetts Institute of Technology, Cambridge MA, July 1989.<P>
<P>
Cost to Users: None (I think). This is an upward-compatible extension.<P>
Cost of non-adoption: Continued inability for user print-functions<P>
to interact with the pretty-printer in a useful and portable manner.<P>
<P>
Performance impact: XP is claimed to be quite fast.<P>
<P>
Benefits: User control of pretty-printing in a portable manner.<P>
<P>
<B>Aesthetics:<P>
</B> Using ~&lt;...~:&gt; may strike some as uncomfortably close in the syntactic<P>
space of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> directives to the existing ~&lt;...~&gt;. However, it is very<P>
unlikely that both of these directives (pretty-print logical block and<P>
columnar justification, respectively) will be used in the same call to<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A>. Previous versions of XP used ~!...~. instead of ~&lt;...~:&gt; but this<P>
made <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> strings very difficult to read; it is preferable to have a<P>
directive that looks like matching brackets of some sort.<P>
<P>
Dan Pierson comments: You might mention that some people will undoubtedly<P>
find piling more hair on <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> ugly (of course these same people may<P>
well find <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> in general ugly :-)).<P>
<P>
<B>Discussion:<P>
</B><P>
Zetalisp used ~:T to mean pixelwise tabulation, so the use of ~:T<P>
suggested here may be a problem. If so, another suggestion for naming<P>
this directive would be appreciated.<P>
<P>
The ~/.../ directive is already in Zetalisp, and is not an idea new<P>
to this proposal. However, it should be noted that the proposal for<P>
~/.../ here is simpler than, and incompatible with, the current Zatalisp<P>
practice.<P>
<P>
Guy Steele and Dick Waters strongly support this proposal. (As an example,<P>
Guy Steele has a portable simulator for Connection Machine Lisp, and would<P>
like very much to have xappings and xectors pretty-print properly.)<P>
<P>
---<P>
<P>
Dan Pierson comments: You can add me to the list of strong supporters of<P>
this proposal. While the proposal is long and complex, it is supported by<P>
a long history of usage in several different Lisp environments.<P>
<P>
The utility of <A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A> becomes more obvious if it is pointed out<P>
that Dick's pretty printers are implemented to print each line as it<P>
is computed. This means that a small value for <A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A> saves<P>
significant time as well as output medium space.<P>
<P>
The advantages of compiled format strings (format functions) should be<P>
brought out as benefits in their own right. The current proposal just<P>
mentions them as a minor feature of XP.<P>
<P>
At first this struck me a very cute end run around the failure of<P>
STREAM-INFO, then I realized that one of the problems with STREAM-INFO<P>
may have been that it was a <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> at the wrong level. STREAM-INFO<P>
permitted people to use XP, but not to count on it. This proposal<P>
makes it possible to write portable code whose new data structures and<P>
language elements print correctly in whatever Common Lisp environment<P>
they're run in. [End of comments by Pierson]<P>
<P>
---<P>
<P>
It has been noted by Guy Steele that some places in the initial document<P>
where it says that circularity detection is handled correctly, this is<P>
true a fortiori following the decision on <A HREF="iss275.htm">PRINT-CIRCLE-STRUCTURE</A>.<P>
However, Waters notes that the vote on <A HREF="iss275.htm">PRINT-CIRCLE-STRUCTURE</A> said<P>
nothing about the handling of <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A>. Therefore, the fact that<P>
XP handles <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A> correctly is an improvement.<P>
<P>
In addition, <A HREF="iss275.htm">PRINT-CIRCLE-STRUCTURE</A> is also silent on what is supposed<P>
to happen if a user program decomposes a list itself (e.g., with <A REL=DEFINITION HREF="../Body/m_dolist.htm#dolist"><B>DOLIST</B></A><P>
or ~{~}) rather than calling a print function. Assumedly <A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A><P>
etc. is not handled in this case. In contrast, if one uses<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> or ~&lt;~:&gt;, then <A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A>, and<P>
<A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A> are all automatically handled correctly.<P>
<P>
For example, (format nil &quot;-~1{~A ~A ~A ~A ~A ~}-&quot; '#1=(1 #1# 2 . #1#))<P>
produces &quot;-1 #1=(1 #1# 2 . #1#) 2 1 #1=(1 #1# 2 . #1#) -&quot;<P>
even under <A HREF="iss275.htm">PRINT-CIRCLE-STRUCTURE</A> and<P>
(<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>format</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> &quot;-~1{~A ~}-&quot; '#1=(1 #1# 2 . #1#)) <P>
causes infinite looping. However, in XP,<P>
(<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>format</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> &quot;-~:&lt;~W ~W ~W ~W ~W~:&gt;-&quot; '#1=(1 #1# 2 . #1#))<P>
produces &quot;-#1=(1 #1# 2 . #1#)-&quot;.<P>
This proves to be very useful when writing pretty printing functions for<P>
things. Note also that ~&lt;~:&gt; supports <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A> and <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A><P>
correctly. All the same things can be said about the functional interface<P>
and using <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> rather than traversing a list yourself in<P>
some fashion.<P>
<P>
All in all, Waters claims that <A HREF="iss275.htm">PRINT-CIRCLE-STRUCTURE</A> covers at most 1/4<P>
of what XP does in support of <A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A> and does not cover anything<P>
of what XP does to support <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A>, and<P>
robustness in the face of malformed arguments. These are vital<P>
features for writing printing functions that really work right all the time.<P>
<P>
---<P>
<P>
It has been suggested that objects should be looked up in <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch<P>
tables by looking for the most specific type specifier that applies, rather<P>
than looking for the highest priority type specifier that applies. There<P>
are two problems with this. First, it is possible for two type specifiers<P>
to apply without one being more specific than the other. For example,<P>
consider the type specifiers (<A REL=DEFINITION HREF="../Body/a_or.htm#or"><B>OR</B></A> <A REL=DEFINITION HREF="../Body/t_intege.htm#integer"><B>INTEGER</B></A> <A REL=DEFINITION HREF="../Body/a_float.htm#float"><B>FLOAT</B></A>) and (<A REL=DEFINITION HREF="../Body/a_or.htm#or"><B>OR</B></A> <A REL=DEFINITION HREF="../Body/t_intege.htm#integer"><B>INTEGER</B></A> <A REL=DEFINITION HREF="../Body/a_ration.htm#rational"><B>RATIONAL</B></A>)<P>
or the type specifiers (<A REL=DEFINITION HREF="../Body/a_not.htm#not"><B>NOT</B></A> <A REL=DEFINITION HREF="../Body/a_comple.htm#complex"><B>COMPLEX</B></A>) and (<A REL=DEFINITION HREF="../Body/a_not.htm#not"><B>NOT</B></A> <A REL=DEFINITION HREF="../Body/t_intege.htm#integer"><B>INTEGER</B></A>).<P>
<P>
A much more serious problem is that the only way to tell whether one type<P>
specifier is more specific than another is to use <A REL=DEFINITION HREF="../Body/f_subtpp.htm#subtypep"><B>SUBTYPEP</B></A>. Unfortunately,<P>
even with the clarifications and extensions introduced by X3J13 with regard<P>
to <A REL=DEFINITION HREF="../Body/f_subtpp.htm#subtypep"><B>SUBTYPEP</B></A> in particular and the type system in general, <A REL=DEFINITION HREF="../Body/f_subtpp.htm#subtypep"><B>SUBTYPEP</B></A> is not<P>
very dependable. There are critical situations where it cannot reasonably<P>
work in any implementation (e.g., when a type specifier contains <A REL=DEFINITION HREF="../Body/t_satisf.htm#satisfies"><B>SATISFIES</B></A>)<P>
and many other situations where it can vary from one implementation to<P>
another. Unfortunately, <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch tables are expected to contain<P>
type specifiers containing <A REL=DEFINITION HREF="../Body/t_satisf.htm#satisfies"><B>SATISFIES</B></A> on a regular basis. In addition, the<P>
variability in <A REL=DEFINITION HREF="../Body/f_subtpp.htm#subtypep"><B>SUBTYPEP</B></A> would reduce the portability of user-defined <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A><P>
dispatch tables if dispatching through them depended on <A REL=DEFINITION HREF="../Body/f_subtpp.htm#subtypep"><B>SUBTYPEP</B></A>. All in<P>
all, it seems much better for the pretty printing to rely on priorities<P>
rather than on <A REL=DEFINITION HREF="../Body/f_subtpp.htm#subtypep"><B>SUBTYPEP</B></A><P>
<P>
---<P>
<P>
It has been noted by Dave Moon that things would be much more elegant if<P>
<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> could be expressed directly as a CLOS <A REL=DEFINITION HREF="../Body/m_defmet.htm#defmethod"><B>DEFMETHOD</B></A> for<P>
an appropriate generic function. Dick Waters agrees with this. However,<P>
<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> depends on type specifiers that are more complex than<P>
the ones CLOS deals with and ones that do not have clear subtype/supertype<P>
relationships, compensating for the latter problem by supporting numerical<P>
priorities to disambiguate things. (The defaulting behavior is a key<P>
feature of the pretty printer.) At the very least, this means that<P>
<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> will not fit into CLOS in a simple way.<P>
<P>
Given the problems, Moon suggests that &quot;it does seem that right now it<P>
might be best to keep a separate <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> macro, with the<P>
idea that the expansion is implementation-dependent at the moment, but<P>
might some day be changed to be defined to expand into <A REL=DEFINITION HREF="../Body/m_defmet.htm#defmethod"><B>DEFMETHOD</B></A>. I<P>
haven't looked to see whether any syntactic changes would be appropriate<P>
to make that transition smoother.&quot;<P>
<P>
(Waters also worries that <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> overhead needed to locate <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> right CLOS<P>
<A REL=DEFINITION HREF="../Body/t_method.htm#method"><B>method</B></A> would seriously degrade <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> pretty printer, because <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> printer<P>
has to <A REL=DEFINITION HREF="../Body/m_do_do.htm#do"><B>do</B></A> this for <A REL=DEFINITION HREF="../Body/f_everyc.htm#every"><B>every</B></A> part of <A REL=DEFINITION HREF="../Body/f_everyc.htm#every"><B>every</B></A> object printed. This dispatching is<P>
currently done by very fast code that is tuned to take advantage of <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A><P>
observed distribution of kinds of objects that have <A REL=DEFINITION HREF="../Body/d_specia.htm#special"><B>special</B></A> pretty<P>
printers attached to them. Even with this <A REL=DEFINITION HREF="../Body/d_specia.htm#special"><B>special</B></A> purpose code,<P>
dispatching takes a significant part of <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> pretty printer's <A REL=DEFINITION HREF="../Body/m_time.htm#time"><B>time</B></A>.)<P>
<P>
---<P>
<P>
Dave Moon also comments that it is not good to have something that looks<P>
like a type specifier (i.e., the extended form of the <A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>CONS</B></A> type specifier<P>
used by <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A>) and yet is not a real type specifier. He<P>
suggests that we should either amend Common Lisp to accept the extended<P>
form of the <A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>CONS</B></A> type specifier, or stop having <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> use it. <P>
<P>
Many of the members of the ad hoc pretty printing subcommittee agree that<P>
(<A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>CONS</B></A> car-type cdr-type) should be made a full fledged type specifier. In<P>
fact it has been suggested that there should be a much wider variety of<P>
ways to talk about lists and their contents than currently exists.<P>
However, the subcommittee feels that it would be going significantly beyond<P>
our charter to change anything about the type system.<P>
<P>
Therefore, we opted for the opposite tack of making it very clear in this<P>
proposal that while the function <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> accepts the form<P>
(<A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>CONS</B></A> car-type cdr-type), this form is not a type specifier.<P>
<P>
---<P>
<P>
To a considerable extent, the design of the XP interface is completely<P>
neutral about the issue of variable- versus fixed- width fonts. In<P>
particular, most of the discussion of how the formating proceeds either<P>
talks about absolute positions of zero or talks about something being<P>
in the same horizontal position as something else. These statements are<P>
all font-independent. (Further, although Waters' current implementation<P>
does not support variable-width fonts, the algorithms used could be<P>
extended to support them without radical changes.)<P>
<P>
Nevertheless, there are 8 places where users specify explicit non-zero<P>
lengths: the variables <A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A> and <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A>,<P>
the numeric arguments to ~T, ~I, and ~/pprint-tabular/ and their associated<P>
functions <A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>PPRINT-TAB</B></A>, <A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A>, and <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A>.<P>
<P>
It is proposed that all of these lengths be in the same units, and that<P>
this unit be ems (the length of an &quot;m&quot; in the font currently being used<P>
to output characters to the relevant output stream at the moment that<P>
the command is encountered or a variable is consulted).<P>
<P>
It is further proposed that users and implementors be advised to set things<P>
up so that explicit lengths do not have to be specified. For implementors,<P>
this means making streams smart enough that they know how wide they are.<P>
(This avoids the use of <A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A>.) For users, this means<P>
relying on streams knowing their own widths (which is a good idea for<P>
adaptability in any case) and using ~:I (instead of just ~I) to specify<P>
indentations wherever possible. Further, it should be noted that since<P>
<A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> is essentially heuristic in nature, it does not<P>
matter if its value is only an approximate length and users will only need<P>
to change the value of <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> in unusual situations.<P>
This leaves only tabbing as an area where explicit lengths have to be<P>
specified on a regular basis. Fortunately, approximate lengths are often<P>
acceptable in this situation as well.<P>
<P>
---<P>
<P>
The currently proposed syntax for <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> was suggested by<P>
Dave Moon based on his experience with similar constructs at Symbolics.<P>
Waters had originally suggested using a <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> binding pair to specify<P>
the underlying stream separately from the variable used to hold the special<P>
stream used within the logical block. However, this invites user mistakes.<P>
The problem is that peculiar results will be obtained if any I/O is sent<P>
directly to the underlying stream from within the logical block. By<P>
arranging the syntax as proposed, the same variable is always used for the<P>
special stream within the logical block as is used for the underlying<P>
stream outside of the block. As a result, it is syntactically impossible<P>
to directly access the underlying stream (unless it is stored in two<P>
different variables) and the user is painlessly saved from making mistakes.<P>
Also, the <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> macro is rendered more compact.<P>
<P>
---<P>
<P>
Another interesting issue is the interaction between pretty-printing and<P>
<A REL=DEFINITION HREF="../Body/v_pr_rda.htm#STprint-readablyST"><B>*PRINT-READABLY*</B></A>. Note first, that <A REL=DEFINITION HREF="../Body/m_w_std_.htm#with-standard-io-syntax"><B>WITH-STANDARD-IO-SYNTAX</B></A> binds<P>
<A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> to <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>. In general one should expect that maximum machine<P>
readability will be achieved when <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> is nil. However, in<P>
analogy with issue <A HREF="iss089.htm">DATA-IO</A>, it is reasonable to <A REL=DEFINITION HREF="../Body/f_provid.htm#require"><B>require</B></A> that<P>
<A REL=DEFINITION HREF="../Body/f_ppr_di.htm#pprint-dispatch"><B>PPRINT-DISPATCH</B></A> functions must obey <A REL=DEFINITION HREF="../Body/v_pr_rda.htm#STprint-readablyST"><B>*PRINT-READABLY*</B></A>. Note that XP<P>
supports a number of features (e.g., automatic handling of malformed lists)<P>
that are explicitly designed to make it easier to write <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> functions<P>
that reliably produce machine readable output.<P>
<P>
---<P>
<P>
Steve Haflich comments that the macro <A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A> provides an opportunity at<P>
some later time to do something about making <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> control strings more<P>
readable. Specifically, when using <A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A>, one should not hesitate to<P>
insert lots of newlines, because they will not waste any space since the<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string will be converted into a function in any case. Second, it<P>
would be nice to add some feature to format strings that would allow<P>
comments to appear in a <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string. (This is what ~; probably should<P>
have been reserved to mean.)<P>
<P>
---<P>
<P>
Walter van Roggen notes that the automatic handling of <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A> by XP<P>
obsoletes the need for the third argument to print functions for<P>
structures. (This argument was very seldom used in any case.) It might be<P>
appropriate at some future time to get rid of the third argument to print<P>
functions for structures. However, this would not be an upward compatible<P>
change.<P>
<P>
---<P>
<P>
The pretty printer control interface is included in this proposal for two<P>
key reasons:<P>
<P>
(A) Something like the following is probably a key part of the argument<P>
against the pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface in the minds of those<P>
that oppose it. &quot;Including the pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface<P>
might be a gain or a loss for Common Lisp, but nothing could possibly be<P>
lost by not including it. You can always just use <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> as it is now, and<P>
you can get pretty printing control with the new functions.&quot; However, this<P>
argument is not quite true.<P>
<P>
As can be seen in the example below, pretty printer control information has<P>
to be highly intertwined with the rest of the output functions. As a<P>
practical matter, this means that if there is no pretty-printer-control<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface you cannot make much if any use of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> when specifying<P>
output that contains pretty-printer-control information. (For instance in<P>
the 20 line example below, there is not even one place where there are two<P>
printing operations in a row that could be combined into a call on <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A><P>
if there were no pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface. This means that<P>
there would be no benefit to using <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> anywhere in this example.)<P>
<P>
The consequence of the above is that, even though pretty printer control<P>
and <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> inherently have nothing to do with each other, adding pretty<P>
printer control facilities without adding a pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A><P>
interface, effectively requires people to choose between <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> and pretty<P>
printer control. In order to allow people to separately decide whether<P>
they do or do not want to user <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> and do or do not want to get involved<P>
with controlling the pretty printer, you have to <A REL=DEFINITION HREF="../Body/f_provid.htm#provide"><B>provide</B></A> a<P>
pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface.<P>
<P>
This issue is intensified given a pretty printer such as XP that is<P>
within epsilon of just as fast as the ordinary non-pretty printer,<P>
because many people choose to set <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> to T all of the time.<P>
They are therefore naturally led to wanting to specify at least some<P>
pretty printing control information whenever defining a print function<P>
for a <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A>, or an error message, or in fact essentially any kind<P>
of output. If there is no pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface,<P>
then this would effectively bar the use of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> for these users.<P>
<P>
In summary, rather than pushing <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> into new territory, the<P>
pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface is required to prevent <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> from<P>
sliding into obsolescence.<P>
<P>
<P>
(B) Although it probably is not convincing to those that do not like<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A>, a additional reason for having a pretty-printer-control <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A><P>
interface is exactly the same as the reason for having <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> at all:<P>
compactness. For example, as shown in the main proposal, the format string:<P>
<P>
&quot;~:&lt;~W~^ ~:&lt;~@{~:&lt;~@{~W~^ ~_~}~:&gt;~^ ~:_~}~:&gt;~1I~@{~^ ~_~W~}~:&gt;&quot;<P>
<P>
is the same as the expression:<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> :prefix &quot;(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>) :prefix &quot;(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>) :prefix &quot;(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :linear)))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :fill)))<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>pprint-indent</B></A> :block 1)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :linear)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>)))))<P>
<P>
It is of course also true that a line of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> control string is a<P>
lot harder to read than a line of Lisp code. However, <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> has<P>
become a permanent fixture of Common Lisp, because a line of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A><P>
control string is a lot easier to read and work with than 20 lines of<P>
Lisp code.<P>
<P>
<P>
(C) It should also be noted that the way the XP proposal was first written<P>
up made the <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> interface look a lot more complex than it is. Only six<P>
things are being added. Two of these just fix problems with <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> and do<P>
not have anything to do with pretty printing. Of the remaining four, three<P>
are very simple. Only ~&lt;...~:&gt; could be called complex.<P>
<P>
~A and ~S both force the value of <A REL=DEFINITION HREF="../Body/v_pr_esc.htm#STprint-escapeST"><B>*PRINT-ESCAPE*</B></A>. ~W is needed in<P>
order to write <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> strings that obey <A REL=DEFINITION HREF="../Body/v_pr_esc.htm#STprint-escapeST"><B>*PRINT-ESCAPE*</B></A>.<P>
<P>
~/.../ restores (in a simplified form) a feature of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> that was<P>
lost in the first version of Common Lisp. A number of people have<P>
commented that this is something that they like, having nothing to do<P>
with pretty printing. (Note that ~/PPRINT-LINEAR/, ~/PPRINT-FILL/,<P>
and ~/PPRINT-TABULAR/ are not new directives, they are just a<P>
consequence of the fact that ~/.../ can call the functions<P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-linear"><B>PPRINT-LINEAR</B></A>, <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>PPRINT-FILL</B></A>, and <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A>.)<P>
<P>
<P>
<P>
========================= ``Attached Document'' =========================<P>
<P>
<B>Proposal (PRETTY-PRINT-INTERFACE:XP):<P>
</B><P>
Full description of XP accompanying version 5 of the proposal<P>
<P>
--------------------<P>
<P>
Pretty Printing<P>
<P>
Richard C. Waters<P>
<P>
<P>
Pretty printing has traditionally been a black box process, displaying<P>
program code using a set of fixed layout rules. Its utility can be greatly<P>
enhanced by opening it up to user control.<P>
<P>
By providing direct access to the mechanisms within the pretty printer that<P>
make dynamic decisions about layout, the macros and functions<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>, <A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A>, and <A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> make it possible to<P>
specify pretty printing layout rules as a part of any function that<P>
produces output. They also make it very easy for the detection of<P>
circularity and sharing, and abbreviation based on length and nesting depth<P>
to be supported by the function. The function <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> makes it<P>
possible to associate a user-defined pretty printing function with any type<P>
of object. Together, these facilities enable users to redefine the way<P>
code is displayed and allow the full power of pretty printing to be applied<P>
to complex combinations of data structures.<P>
<P>
Pretty Printing Control Variables<P>
<P>
<A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A> [variable]<P>
<P>
A primary goal of pretty printing is to keep the output between a pair of<P>
margins. The left margin is set at the column where the output begins. If<P>
this cannot be determined, the left margin is set to zero.<P>
<P>
When <A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A> is not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, it specifies the right margin to use<P>
when making layout decisions. When <A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A> is <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> (the<P>
initial value), the right margin is set at the maximum line length that can<P>
be displayed by the output stream without wraparound or truncation. If<P>
this cannot be determined, the right margin is set to an implementation<P>
dependent value.<P>
<P>
To allow for the possibility of variable-width fonts, <A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A><P>
is interpreted in terms of ems---the length of an &quot;m&quot; in the font being<P>
used to display characters on the relevant output stream at the moment when<P>
the variables are consulted.<P>
<P>
<A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> [variable]<P>
<P>
If <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> is not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, the pretty printer switches to a compact<P>
style of output (called miser style) whenever the width available for<P>
printing a substructure is less than or equal to <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> ems.<P>
The initial value of <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> is implementation-dependent.<P>
<P>
<A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A> [variable]<P>
<P>
When given a value other than its initial value of <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A><P>
limits the number of output lines produced when something is pretty<P>
printed. If an attempt is made to go beyond <A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A> lines, &quot;<P>
..&quot; is printed at the end of the last line followed by all of the<P>
suffixes (closing delimiters) that are pending to be printed.<P>
<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A> ((<A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*print-right-margin*</B></A> 25) (<A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*print-lines*</B></A> 3))<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> '(<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>progn</B></A> (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> a 1 b 2 c 3 d 4))))<P>
<P>
(<A REL=DEFINITION HREF="../Body/s_progn.htm#progn"><B>PROGN</B></A> (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>SETQ</B></A> A 1<P>
B 2<P>
C 3 ..))<P>
<P>
(The <A REL=DEFINITION HREF="../Body/t_symbol.htm#symbol"><B>symbol</B></A> &quot;..&quot; is printed out to ensure that a reader <A REL=DEFINITION HREF="../Body/a_error.htm#error"><B>error</B></A> will occur<P>
<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> output is later <A REL=DEFINITION HREF="../Body/f_rd_rd.htm#read"><B>read</B></A>. A <A REL=DEFINITION HREF="../Body/t_symbol.htm#symbol"><B>symbol</B></A> different than &quot;...&quot; is used to<P>
indicate that a different kind of abbreviation has occurred.)<P>
<P>
<A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A> [variable]<P>
<P>
When <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> is not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, printing is controlled by the `<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A><P>
dispatch table' stored in the variable <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>. The<P>
initial value of <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A> is implementation dependent and<P>
causes traditional pretty printing of Lisp code. The last section of this<P>
proposal explains how the contents of this table can be changed.<P>
<P>
<P>
The function <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A> accepts keyword arguments :PPRINT-DISPATCH,<P>
:RIGHT-MARGIN, :LINES, and :MISER-WIDTH corresponding to<P>
<A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_rig.htm#STprint-right-marginST"><B>*PRINT-RIGHT-MARGIN*</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A>, and<P>
<A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A>.<P>
<P>
<P>
Dynamic Control of the Arrangement of Output<P>
<P>
The following functions and macros support precise control of what should<P>
be done when a piece of output is too large to fit in the space available.<P>
Three concepts underlie the way these operations work---`logical blocks',<P>
`conditional newlines', and `sections'. Before proceeding further, it is<P>
important to define these terms.<P>
<P>
The first line of Figure 1 shows a schematic piece of output. The<P>
characters in the output are represented by &quot;-&quot;s. The positions of<P>
conditional newlines are indicated by digits. The beginnings and ends of<P>
logical blocks are indicated by &quot;&lt;&quot; and &quot;&gt;&quot; respectively.<P>
<P>
The output as a whole is a logical block and the outermost section. This<P>
section is indicated by the 0's on the second line of Figure 1. Logical<P>
blocks nested within the output are specified by the macro<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>. Conditional newline positions are specified by calls<P>
on <A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A>. Each conditional newline defines two sections (one<P>
before it and one after it) and is associated with a third (the section<P>
immediately containing it).<P>
<P>
The section after a conditional newline consists of: all the output up to,<P>
but not including, (a) the next conditional newline immediately contained<P>
in the same logical block; or if (a) is not applicable, (b) the next<P>
newline that is at a lesser level of nesting in logical blocks; or if (b)<P>
is not applicable, (c) the end of the output.<P>
<P>
The section before a conditional newline consists of: all the output back<P>
to, but not including, (a) the previous conditional newline that is<P>
immediately contained in the same logical block; or if (a) is not<P>
applicable, (b) the beginning of the immediately containing logical block.<P>
The last four lines in Figure 1 indicate the sections before and after the<P>
four conditional newlines.<P>
<P>
The section immediately containing a conditional newline is the shortest<P>
section that contains the conditional newline in question. In Figure 1,<P>
the first conditional newline is immediately contained in the section<P>
marked with 0's, the second and third conditional newlines are immediately<P>
contained in the section before the fourth conditional newline, and the<P>
fourth conditional newline is immediately contained in the section after<P>
the first conditional newline.<P>
<P>
<P>
&lt;-1---&lt;--&lt;--2---3-&gt;--4--&gt;-&gt;<P>
000000000000000000000000000<P>
11 111111111111111111111111<P>
22 222<P>
333 3333<P>
44444444444444 44444<P>
<P>
Figure 1: Example of logical blocks, conditional newlines, and sections.<P>
<P>
Whenever possible, the pretty printer displays the entire contents of a<P>
section on a single line. However, if the section is too long to fit in<P>
the space available, line breaks are inserted at conditional newline<P>
positions within the section.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A> kind <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A> (stream <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A>) [Function]<P>
<P>
<A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> (which defaults to <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A>) follows the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A><P>
conventions for stream arguments to printing functions (i.e., <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> stands<P>
for <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A> and T stands for <A REL=DEFINITION HREF="../Body/v_termin.htm#STterminal-ioST"><B>*TERMINAL-IO*</B></A>). The KIND argument<P>
specifies the style of conditional newline. It must be one of :LINEAR,<P>
:FILL, :MISER, or :MANDATORY. An error is signalled if any other value is<P>
supplied. If <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> is a pretty printing stream created by<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>, a line break is inserted in the output when the<P>
appropriate condition below is satisfied. Otherwise, <A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A> has no<P>
effect. The value <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> is always returned.<P>
<P>
If KIND is :LINEAR, it specifies a `linear-style' conditional newline. A<P>
line break is inserted if and only if the immediately containing section<P>
cannot be printed on one line. The effect of this is that line breaks are<P>
either inserted at every linear-style conditional newline in a logical<P>
block or at none of them.<P>
<P>
If KIND is :MISER, it specifies a `miser-style' conditional newline. A<P>
line break is inserted if and only if the immediately containing section<P>
cannot be printed on one line and miser style is in effect in the<P>
immediately containing logical block. The effect of this is that<P>
miser-style conditional newlines act like linear-style conditional<P>
newlines, but only when miser style is in effect. Miser style is in effect<P>
for a logical block if and only if the starting position of the logical<P>
block is less than or equal to <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> from the right margin.<P>
<P>
If KIND is :FILL, it specifies a `fill-style' conditional newline. A line<P>
break is inserted if and only if either (a) the following section cannot be<P>
printed on the end of the current line, (b) the preceding section was not<P>
printed on a single line, or (c) the immediately containing section cannot<P>
be printed on one line and miser style is in effect in the immediately<P>
containing logical block. If a logical block is broken up into a number of<P>
subsections by fill-style conditional newlines, the basic effect is that<P>
the logical block is printed with as many subsections as possible on each<P>
line. However, if miser style is in effect, fill-style conditional<P>
newlines act like linear-style conditional newlines.<P>
<P>
If KIND is :MANDATORY, it specifies a `mandatory-style' conditional<P>
newline. A line break is always inserted. This implies that none of the<P>
containing sections can be printed on a single line and will therefore<P>
trigger the insertion of line breaks at linear-style conditional newlines<P>
in these sections.<P>
<P>
When a line break is inserted by any type of conditional newline, any<P>
blanks that immediately precede the conditional newline are omitted from<P>
the output and indentation is introduced at the beginning of the next line.<P>
By default, the indentation causes the following line to begin in the same<P>
horizontal position as the first character in the immediately containing<P>
logical block. (The indentation can be changed via <A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A>.)<P>
<P>
There are a variety of ways unconditional newlines can be introduced into<P>
the output (e.g., via <A REL=DEFINITION HREF="../Body/f_terpri.htm#terpri"><B>TERPRI</B></A> or by printing a string containing a newline<P>
character). As with mandatory conditional newlines, this prevents any of<P>
the containing sections from being printed on one line. In general, when<P>
an unconditional newline is encountered, it is printed out without<P>
suppression of the preceding blanks and without any indentation following<P>
it. However, if a per-line prefix has been specified (see<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>), this prefix will always be printed no matter how a<P>
newline originates.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> (stream-symbol list [Macro]<P>
<A REL=DEFINITION HREF="../Body/03_da.htm#AMkey"><B>&amp;KEY</B></A> :prefix :per-line-prefix :suffix)<P>
<A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;BODY</B></A> body<P>
<P>
This macro causes printing to be grouped into a logical block. The value<P>
<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> is always returned.<P>
<P>
STREAM-SYMBOL must be a symbol. If it is <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, it is treated the same as<P>
if it were <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A>. If it is T, it is treated the same as if<P>
it were <A REL=DEFINITION HREF="../Body/v_termin.htm#STterminal-ioST"><B>*TERMINAL-IO*</B></A>. The run-time value of STREAM-SYMBOL must be a<P>
stream (or <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> standing for <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A> or T standing for <A REL=DEFINITION HREF="../Body/v_termin.htm#STterminal-ioST"><B>*TERMINAL-IO*</B></A>).<P>
The logical block is printed into this destination stream.<P>
<P>
The BODY can contain any arbitrary Lisp forms. Within the BODY,<P>
STREAM-SYMBOL (or <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A> if STREAM-SYMBOL is <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, or<P>
<A REL=DEFINITION HREF="../Body/v_termin.htm#STterminal-ioST"><B>*TERMINAL-IO*</B></A> if STREAM-SYMBOL is T) is bound to a `pretty printing' stream<P>
that supports decisions about the arrangement of output and then forwards<P>
the output to the destination stream. All the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> printing functions<P>
(e.g., <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A>, <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#princ"><B>PRINC</B></A>, <A REL=DEFINITION HREF="../Body/f_terpri.htm#terpri"><B>TERPRI</B></A>) can be used to print output the pretty<P>
printing stream created by <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>. All and only the output<P>
sent to this pretty printing stream is treated as being in the logical<P>
block.<P>
<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> and the pretty printing stream it creates have dynamic<P>
extent. It is undefined what happens if output is attempted outside of<P>
this extent to the pretty printing stream created. It is unspecified what<P>
happens if, within this extent, any output is sent directly to the<P>
underlying destination stream.<P>
<P>
The :SUFFIX, :PREFIX, and :PER-LINE-PREFIX must all be expressions that (at<P>
run time) evaluate to strings. :SUFFIX (which defaults to the null string)<P>
specifies a suffix that is printed just after the logical block. The<P>
:PREFIX and :PRE-LINE-PREFIX arguments are mutually exclusive. If neither<P>
:PREFIX or :PER-LINE-PREFIX is specified, a :PREFIX of the null string is<P>
assumed. :PREFIX specifies a prefix to be printed before the beginning of<P>
the logical block. :PER-LINE-PREFIX specifies a prefix that is printed<P>
before the block and at the beginning of each new line in the block. An<P>
error is signalled if :PREFIX and :PRE-LINE-PREFIX are both used or if the<P>
:SUFFIX, :PREFIX, or :PER-LINE-PREFIX do not evaluate to strings.<P>
<P>
<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> is interpreted as being a list that BODY is responsible for<P>
printing. (See <A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A> and <A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A>.) If<P>
<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> does not (at run time) evaluate to a list, it is printed using<P>
<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A>. (This makes it easier to write printing functions that are<P>
robust in the face of malformed arguments.) If <A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A> (and<P>
possibly *PRINT-SHARED*) is not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> and <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> is a circular (or shared)<P>
reference to a cons, then an appropriate #n# marker is printed. (This<P>
makes it easy to write printing functions that <A REL=DEFINITION HREF="../Body/f_provid.htm#provide"><B>provide</B></A> full support<P>
for circularity and sharing abbreviation.) If <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A> is not<P>
<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> and the logical block is at a dynamic nesting depth of greater<P>
than <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A> in logical blocks, # is printed. (This makes easy<P>
to write printing functions that <A REL=DEFINITION HREF="../Body/f_provid.htm#provide"><B>provide</B></A> full support for depth<P>
abbreviation.)<P>
<P>
If either of the three conditions above occurs, the indicated output is<P>
printed on STREAM-SYMBOL and the BODY is skipped along with the printing of<P>
the :PREFIX and :SUFFIX. (If the BODY is not responsible for printing a<P>
list, then the first two tests above can be turned off by supplying <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> for<P>
the <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> argument.)<P>
<P>
In addition to the <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> argument of <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>, the arguments of<P>
the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> printing functions such as <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A>, <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#print"><B>PRINT</B></A>, <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>PPRINT</B></A>, PRINT1, and<P>
<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>PPRINT</B></A>, as well as the arguments of the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> directives such as<P>
~A, ~S, (and ~W) are all checked (when necessary) for circularity and<P>
sharing. However, such checking is not applied to the arguments of the<P>
functions <A REL=DEFINITION HREF="../Body/f_wr_stg.htm#write-line"><B>WRITE-LINE</B></A>, <A REL=DEFINITION HREF="../Body/f_wr_stg.htm#write-string"><B>WRITE-STRING</B></A>, and <A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>WRITE-CHAR</B></A> or to the literal text<P>
output by <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A>. A consequence of this is that you must use one of the<P>
latter functions if you want to print some literal text in the output that<P>
is not supposed to be checked for circularity or sharing. (See the<P>
examples below.)<P>
<P>
----------------------------------------<P>
<P>
Implementation note: detection of circularity and sharing is supported by<P>
the pretty printer by in essence performing requested output twice.<P>
On the first pass, circularities and sharing are detected and the<P>
actual outputting of characters is suppressed. On the second pass, the<P>
appropriate #n= and #n# markers are inserted and characters are output.<P>
<P>
A consequence of this two-pass approach to the detection of circularity and<P>
sharing is that the BODY of a <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> must not perform any<P>
side-effects on the surrounding environment. This includes not modifying<P>
any variables that are bound outside of its scope. Obeying this<P>
restriction is facilitated by using <A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A>, instead of an ordinary <A REL=DEFINITION HREF="../Body/m_pop.htm#pop"><B>POP</B></A><P>
when traversing a list being printed by the BODY of a<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>.)<P>
<P>
----------------------------------------<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A> [Macro] <P>
<P>
<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A> tests whether or not the <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> passed to<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> has been exhausted (see <A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A>). If this list has<P>
been reduced to <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, <A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A> terminates the execution<P>
of the immediately containing <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> except for the printing<P>
of the suffix. Otherwise <A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A> returns <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>. An<P>
error message is issued if <A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A> is used anywhere<P>
other than syntactically nested within a call on <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>. It<P>
is undefined what happens if PPRINT-IF-LIST-EXHAUSTED is executed outside<P>
of the dynamic extent of this <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A> [Macro] <P>
<P>
<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A> pops elements one at a time off the <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> passed to<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> obeying <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A>, and<P>
*PRINT-SHARED*. An error message is issued if it is used anywhere<P>
other than syntactically nested within a call on <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>.<P>
It is undefined what happens if <A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A> is executed outside of the<P>
dynamic extent of this <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>.<P>
<P>
Each time <A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A> is called, it pops the next value off the <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A><P>
passed to <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> and returns it. However, before doing<P>
this, it performs three tests. If the remaining list is not a list<P>
(i.e., a cons or <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>), &quot;. &quot; is printed followed by the remaining list.<P>
(This makes it easier to <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> printing functions that are robust in<P>
the face of malformed arguments.) If <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A> is <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> and<P>
<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A> has already been called <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A> times within the<P>
immediately containing logical block, &quot;...&quot; is printed. (This makes<P>
it easy to write printing functions that properly handle<P>
<A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A>.) If <A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A> (and possibly *PRINT-SHARED*) is<P>
not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, and the remaining list is a circular (or shared) reference,<P>
then &quot;. &quot; is printed followed by an appropriate #n# marker. (This<P>
catches instances of <A REL=DEFINITION HREF="../Body/f_car_c.htm#cdr"><B>cdr</B></A> circularity and sharing in lists.)<P>
<P>
If either of the three conditions above occurs, the indicated output is<P>
printed on the pretty printing stream created by the immediately containing<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> and the execution of the immediately containing<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> is terminated except for the printing of the suffix.<P>
<P>
If <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> is given a <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> argument of NIL---because it is not<P>
processing a list---PPRINT-POP can still be used to obtain support for<P>
<A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A> (see the example function PPRINT-VECTOR below). In this<P>
situation, the first and third tests above are disabled and<P>
<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A> always returns <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> relative-to n <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A> (stream <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A>) [Function]<P>
<P>
<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> specifies the indentation to use in a logical block. <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A><P>
(which defaults to <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A>) follows the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> conventions for<P>
stream arguments to printing functions. N specifies the indentation in<P>
ems. If RELATIVE-TO is :BLOCK, the indentation is set to the horizontal<P>
position of the first character in the block plus N ems. If RELATIVE-TO is<P>
:CURRENT, the indentation is set to the current output position plus N ems.<P>
(For robustness in <A REL=DEFINITION HREF="../Body/s_the.htm#the"><B>the</B></A> face of variable-width fonts, it is advisable to use<P>
:CURRENT with an N of zero whenever possible.)<P>
<P>
N can be negative; however, the total indentation cannot be moved left of<P>
the beginning of the line or left of the end of the rightmost per-line<P>
prefix. Changes in indentation caused by <A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> do not take<P>
effect until after the next line break. In addition, in miser mode all<P>
calls on <A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> are ignored, forcing the lines corresponding to the<P>
logical block to line up under the first character in the block.<P>
<P>
An error is signalled if a value other than :BLOCK or :CURRENT is supplied<P>
for RELATIVE-TO. If <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> is a pretty printing stream created by<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>, <A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> sets the indentation in the innermost<P>
dynamically enclosing logical block. Otherwise, <A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> has no<P>
effect. The value <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> is always returned.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>PPRINT-TAB</B></A> kind colnum colinc <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A> (stream <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A>) [function]<P>
<P>
<A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>PPRINT-TAB</B></A> specifies tabbing as performed by the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> directive<P>
~T. <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> (which defaults to <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*STANDARD-OUTPUT*</B></A>) follows the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A><P>
conventions for stream arguments to printing functions. The arguments<P>
COLNUM and COLINC correspond to the two parameters to ~T and are in terms<P>
of ems. The KIND argument specifies the style of tabbing. It must be one<P>
of :LINE (tab as by ~T) :SECTION (tab as by ~T, but measuring horizontal<P>
positions relative to the start of the dynamically enclosing section),<P>
:LINE-RELATIVE (tab as by ~@T), or :SECTION-RELATIVE (tab as by ~@T, but<P>
measuring horizontal positions relative to the start of the dynamically<P>
enclosing section). An error is signalled if any other value is supplied<P>
for KIND. If <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> is a pretty printing stream created by<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>, tabbing is performed. Otherwise, <A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>PPRINT-TAB</B></A> has no<P>
effect. The value <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> is always returned.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>PPRINT-FILL</B></A> <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A> (COLON? T) ATSIGN? [function]<P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-linear"><B>PPRINT-LINEAR</B></A> <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A> (COLON? T) ATSIGN? [function]<P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A> <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A> (COLON? T) ATSIGN? (TABSIZE 16) [function]<P>
<P>
These three functions specify particular ways of pretty printing lists.<P>
<A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> follows the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> conventions for stream arguments to printing<P>
functions. Each function prints parentheses around the output if and only<P>
if COLON? (default T) is not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>. Each function ignores its ATSIGN?<P>
argument and returns <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>. (These two arguments are included in this way so<P>
that these functions can be used via ~/.../ and as <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A><P>
functions as well as directly.) Each function handles abbreviation and the<P>
detection of circularity and sharing correctly, and uses <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A> to print<P>
<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> when given a non-list argument.<P>
<P>
The function <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-linear"><B>PPRINT-LINEAR</B></A> prints a list either all on one line, or with<P>
each element on a separate line. The function <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>PPRINT-FILL</B></A> prints a list<P>
with as many elements as possible on each line. The function<P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A> is the same as <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>PPRINT-FILL</B></A> except that it prints the<P>
elements so that they line up in columns. This function takes an<P>
additional argument TABSIZE (default 16) that specifies the column<P>
spacing in ems.<P>
<P>
---<P>
<P>
As an example of the interaction of logical blocks, conditional newlines,<P>
and indentation, consider the function SIMPLE-PPRINT-DEFUN below. This<P>
function prints out lists whose cars are <A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> in the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> way assuming<P>
that the list has exactly length 4.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> simple-pprint-defun (<A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> :prefix &quot;(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/f_firstc.htm#first"><B>first</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :miser)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>pprint-indent</B></A> :current 0)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/f_firstc.htm#second"><B>second</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :fill)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/f_firstc.htm#third"><B>third</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>pprint-indent</B></A> :block 1)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :linear)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/f_firstc.htm#fourth"><B>fourth</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>))))<P>
<P>
Suppose that one evaluates the following:<P>
<P>
(simple-pprint-defun <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> '(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> prod (x y) (* x y)))<P>
<P>
If the line width available is greater than or equal to 26, then all of the<P>
output appears on one line. If the line width available is reduced to 25,<P>
a line break is inserted at the linear-style conditional newline before the<P>
expression (* X Y), producing the output shown. The (<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> :BLOCK 1)<P>
causes (* X Y) to be printed at a relative indentation of 1 in the logical block.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> PROD (X Y) <P>
(* X Y))<P>
<P>
If the line width available is 15, a line break is also inserted at the<P>
fill style conditional newline before the argument list. The call on<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> :CURRENT 0) causes the argument list to line up under the<P>
function name.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> PROD<P>
(X Y)<P>
(* X Y))<P>
<P>
If <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A> were greater than or equal to 14, the example output<P>
above would have been as follows, because all indentation changes are<P>
ignored in miser mode and line breaks are inserted at miser-style<P>
conditional newlines.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A><P>
PROD<P>
(X Y)<P>
(* X Y))<P>
<P>
---<P>
<P>
As an example of a per-line prefix, consider that evaluating the following<P>
produces the output shown with a line width of 20 and <A REL=DEFINITION HREF="../Body/v_pr_mis.htm#STprint-miser-widthST"><B>*PRINT-MISER-WIDTH*</B></A><P>
of <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> :per-line-prefix &quot;;;; &quot;)<P>
(simple-pprint-defun <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> '(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> prod (x y) (* x y))))<P>
<P>
;;; (<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> PROD<P>
;;; (X Y)<P>
;;; (* X Y))<P>
<P>
---<P>
<P>
As a more complex (and realistic) example, consider the function PPRINT-LET<P>
below. This specifies how to print a <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> in the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> style. It is more<P>
complex than the example above, because it has to deal with nested <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A>.<P>
Also, unlike the example above it contains complete code to readably print any<P>
possible list that begins with the symbol <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A>. The outermost<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> handles the printing of the input list as a whole and<P>
specifies that parentheses should be printed in the output. The second<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> handles the list of binding pairs. Each pair in the list<P>
is itself printed by the innermost <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>. (A <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> is used<P>
instead of merely decomposing the pair into two elements so that readable<P>
output will be produced no matter whether the list corresponding to the pair<P>
has one element, two elements, or (being malformed) has more than two<P>
elements.) A space and a fill-style conditional newline are placed after<P>
each pair except the last. The loop at the end of the topmost<P>
<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A> prints out the forms in the body of the <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> separated by<P>
spaces and linear-style conditional newlines.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> pprint-let (<A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> :prefix &quot;(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>) :prefix &quot;(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>) :prefix &quot;(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :linear)))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :fill)))<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>pprint-indent</B></A> :block 1)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :linear)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>)))))<P>
<P>
Suppose that one evaluates the following with <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A> 4, and<P>
<A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A> T.<P>
<P>
(pprint-let <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A><P>
'#1=(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A> (x (<A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*print-length*</B></A> (f (g 3))) <P>
(z . 2) (k (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A> y)))<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> x (<A REL=DEFINITION HREF="../Body/f_sqrt_.htm#sqrt"><B>sqrt</B></A> z)) #1#))<P>
<P>
If the line length is greater than or equal to 77, the output produced<P>
appears on one line. However, if the line length is 76, line breaks are<P>
inserted at the linear-style conditional newlines separating the forms in<P>
the body and the output below is produced. Note that, the degenerate<P>
binding pair X is printed readably even though it fails to be a list; a<P>
depth abbreviation marker is printed in place of (G 3); the binding pair<P>
(Z . 2) is printed readably even though it is not a proper list; and<P>
appropriate circularity markers are printed.<P>
<P>
#1=(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> (X (<A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A> (F #)) (Z . 2) (K (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> Y))) <P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>SETQ</B></A> X (<A REL=DEFINITION HREF="../Body/f_sqrt_.htm#sqrt"><B>SQRT</B></A> Z))<P>
#1#)<P>
<P>
If the line length is reduced to 35, a line break is inserted at one of the<P>
fill-style conditional newlines separating the binding pairs.<P>
<P>
#1=(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> (X (<A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> (F #))<P>
(Z . 2) (K (<A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>CAR</B></A> Y)))<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>SETQ</B></A> X (<A REL=DEFINITION HREF="../Body/f_sqrt_.htm#sqrt"><B>SQRT</B></A> Z))<P>
#1#)<P>
<P>
Suppose that the line length is further reduced to 22 and <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A> is<P>
set to 3. In this situation, line breaks are inserted after both the first<P>
and second binding pairs. In addition, the second binding pair is itself<P>
broken across two lines. Clause (b) of the description of fill-style<P>
conditional newlines prevents the binding pair (Z . 2) from being printed<P>
at the end of the third line. Note that the length abbreviation hides the<P>
circularity from view and therefore the printing of circularity markers<P>
disappears.<P>
<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> (X<P>
(<A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A><P>
(F #))<P>
(Z . 2) ...)<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>SETQ</B></A> X (<A REL=DEFINITION HREF="../Body/f_sqrt_.htm#sqrt"><B>SQRT</B></A> Z))<P>
...)<P>
<P>
---<P>
<P>
The function <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A> could be defined as follows.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>pprint-tabular</B></A> (s <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;optional</B></A> (colon? T) atsign? (tabsize <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/s_declar.htm#declare"><B>declare</B></A> (<A REL=DEFINITION HREF="../Body/d_ignore.htm#ignore"><B>ignore</B></A> atsign?))<P>
(<A REL=DEFINITION HREF="../Body/m_when_.htm#when"><B>when</B></A> (<A REL=DEFINITION HREF="../Body/a_null.htm#null"><B>null</B></A> tabsize) (<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> tabsize 16))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (s <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> :prefix (<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> colon? &quot;(&quot; &quot;&quot;)<P>
:suffix (<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> colon? &quot;)&quot; &quot;&quot;))<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>) :stream s)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>pprint-exit-if-list-exhausted</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space s)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>pprint-tab</B></A> :section-relative 0 tabsize s)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :fill s))))<P>
<P>
Evaluating the following with a line length of 25 produces the output shown.<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#princ"><B>princ</B></A> &quot;Roads &quot;) <P>
(<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>pprint-tabular</B></A> <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> '(elm main maple center) <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> 8)<P>
<P>
Roads ELM MAIN<P>
MAPLE CENTER<P>
<P>
---<P>
<P>
The function below prints a vector using #(...) notation.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> pprint-vector (<A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> v)<P>
(<A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> :prefix &quot;#(&quot; :suffix &quot;)&quot;)<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A> ((end (<A REL=DEFINITION HREF="../Body/f_length.htm#length"><B>length</B></A> v)) (i 0))<P>
(<A REL=DEFINITION HREF="../Body/m_when_.htm#when"><B>when</B></A> (<A REL=DEFINITION HREF="../Body/f_minusp.htm#plusp"><B>plusp</B></A> end)<P>
(<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>loop</B></A> (<A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>pprint-pop</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/f_aref.htm#aref"><B>aref</B></A> v i))<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> (= (<A REL=DEFINITION HREF="../Body/m_incf_.htm#incf"><B>incf</B></A> i) end) (<A REL=DEFINITION HREF="../Body/m_return.htm#return"><B>return</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/f_wr_cha.htm#write-char"><B>write-char</B></A> #\space)<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A> :fill))))))<P>
<P>
Evaluating the following with a line length of 15 produces the output shown.<P>
<P>
(pprint-vector <A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> '#(12 34 567 8 9012 34 567 89 0 1 23))<P>
<P>
#(12 34 567 8 <P>
9012 34 567 <P>
89 0 1 23)<P>
<P>
Format Directive Interface<P>
<P>
The primary interface to operations for dynamically determining the<P>
arrangement of output is provided through the functions above. However, an<P>
additional interface is provided via a set of new format directives.<P>
This is done, because as shown by the examples in this section and the<P>
next, <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> strings are typically a much more compact way to specify<P>
pretty printing. In addition, without such an interface, one would have to<P>
abandon the use of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> when interacting with the pretty printer.<P>
<P>
~W [format directive]<P>
<P>
<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A> -- An arg, any Lisp object, is printed obeying every printer control<P>
variable (as by <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A>). In addition, ~W interacts correctly with depth<P>
abbreviation, by not resetting the depth counter to zero. ~W does not<P>
accept parameters. If given the colon modifier, ~W binds <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> to<P>
T. If given the atsign modifier, ~W binds <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A> and <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A><P>
to <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>.<P>
<P>
~W provides automatic support for the detection of circularity and<P>
sharing. If <A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A> (and possibly *PRINT-SHARED*) is not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A><P>
and ~W is applied to an argument that is a circular (or shared)<P>
reference, an appropriate #n# marker is inserted in the output instead<P>
of printing the argument.<P>
<P>
~_ [format directive]<P>
<P>
CONDITIONAL-NEWLINE -- Without any modifiers, ~_ is the same as<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A> :LINEAR). ~@_ is the same as (<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A> :MISER).<P>
~:_ is the same as (<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A> :FILL). ~:@_ is the same as<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_nl.htm#pprint-newline"><B>PPRINT-NEWLINE</B></A> :MANDATORY).<P>
<P>
~&lt;...~:&gt; [format directive]<P>
<P>
LOGICAL <A REL=DEFINITION HREF="../Body/s_block.htm#block"><B>BLOCK</B></A> -- If ~:&gt; is used to terminate a ~&lt;...~&gt;, the directive<P>
is equivalent to a call on <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>. The <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> argument<P>
corresponding to the ~&lt;...~:&gt; directive is treated in the same way as<P>
the <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> argument to <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>, thereby providing automatic<P>
support for non-list arguments and the detection of circularity,<P>
sharing, and depth abbreviation. The portion of the <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> control<P>
string nested within the ~&lt;...~:&gt; specifies the :PREFIX (or<P>
:PER-LINE-PREFIX), :suffix}, and body of the <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>.<P>
<P>
The <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string portion enclosed by ~&lt;...~:&gt; can be divided into<P>
segments ~&lt;prefix~;body~;suffix~:&gt; by ~; directives. If the first<P>
section is terminated by ~@;, it specifies a per-line prefix rather<P>
than a simple prefix. The prefix and suffix cannot contain <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A><P>
directives. An error is signalled if either the prefix or suffix<P>
fails to be a constant string or if the enclosed portion is divided<P>
into more than three segments.<P>
<P>
If the enclosed portion is divided into only two segments, the suffix<P>
defaults to the null string. If the enclosed portion consists of only<P>
a single segment, both the prefix and the suffix default to the null<P>
string. If the colon modifier is used (i.e., ~:&lt;...~:&gt;), the prefix<P>
and suffix default to &quot;(&quot; and &quot;)&quot; (respectively) instead of the null<P>
string.<P>
<P>
The body segment can be any arbitrary <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> control string. This<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> control string is applied to the elements of the list<P>
corresponding to the ~&lt;...~:&gt; directive as a whole. Elements are<P>
extracted from this list using <A REL=DEFINITION HREF="../Body/m_ppr_po.htm#pprint-pop"><B>PPRINT-POP</B></A>, thereby providing automatic<P>
support for malformed lists, and the detection of circularity,<P>
sharing, and length abbreviation. Within the body segment, ~^ acts<P>
like <A REL=DEFINITION HREF="../Body/m_ppr_ex.htm#pprint-exit-if-list-exhausted"><B>PPRINT-EXIT-IF-LIST-EXHAUSTED</B></A>.<P>
<P>
~&lt;...~:&gt; supports a feature not supported by <A REL=DEFINITION HREF="../Body/m_ppr_lo.htm#pprint-logical-block"><B>PPRINT-LOGICAL-BLOCK</B></A>. If<P>
~:@&gt; is used to terminate the directive (i.e., ~&lt;...~:@&gt;), then a<P>
fill-style conditional newline is automatically inserted after each<P>
group of blanks immediately contained in the body (except for blanks<P>
after a ~&lt;newline&gt; directive). This makes it easy to achieve the<P>
equivalent of paragraph filling.<P>
<P>
If the atsign modifier is used with ~&lt;...~:&gt;, the entire remaining argument<P>
list is passed to the directive as its argument. All of the remaining<P>
arguments are always consumed by ~@&lt;...~:&gt;, even if they are not all used<P>
by the <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string nested in the directive. Other than the difference in<P>
its argument, ~@&lt;...~:&gt; is exactly the same as ~&lt;...~:&gt; except that<P>
circularity detection is not applied if ~@&lt;...~:&gt; is encountered at top<P>
level in a {\cd format} string. This ensures that circularity detection is<P>
applied only to data lists, not to {\cd format} argument lists.<P>
<P>
&quot; . #n#&quot; is printed if circularity or sharing has<P>
to be indicated for its argument as a whole.<P>
<P>
To a considerable extent, the basic form of the directive ~&lt;...~&gt; is<P>
incompatible with the dynamic control of the arrangement of output by<P>
~W, ~_, ~&lt;...~:&gt;, ~I, and ~:T. As a result, an error is signalled if<P>
any of these directives is nested within ~&lt;...~&gt;. Beyond this, an<P>
error is also signalled if the ~&lt;...~:;...~&gt; form of ~&lt;...~&gt; is used<P>
in the same <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string with ~W, ~_, ~&lt;...~:&gt;, ~I, or ~:T.<P>
<P>
~I [format directive]<P>
<P>
INDENT -- ~nI is the same as (<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> :BLOCK N).<P>
~n:I is the same as (<A REL=DEFINITION HREF="../Body/f_ppr_in.htm#pprint-indent"><B>PPRINT-INDENT</B></A> :CURRENT N). In both cases, N defaults<P>
to zero, if it is omitted.<P>
<P>
~:T [format directive]<P>
<P>
TABULATE -- If the colon modifier is used with the ~T directive, the<P>
tabbing computation is done relative to the horizontal position where the<P>
section immediately containing the directive begins, rather than with<P>
respect to a horizontal position of zero. The numerical parameters are<P>
both interpreted as being in units of ems and both default to 1.<P>
~n,m:T is the same as (<A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>PPRINT-TAB</B></A> :SECTION N M).<P>
~n,m:@T is the same as (<A REL=DEFINITION HREF="../Body/f_ppr_ta.htm#pprint-tab"><B>PPRINT-TAB</B></A> :SECTION-RELATIVE N M).<P>
<P>
~/name/ [format directive]<P>
<P>
CALL <A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> -- User defined functions can be called from within a <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A><P>
string by using the directive ~/name/. The colon modifier, the atsign<P>
modifier, and arbitrarily many parameters can be specified with the ~/name/<P>
directive. NAME can be any arbitrary string that does not contain a &quot;/&quot;.<P>
All of the characters in NAME are treated as if they were upper case. If<P>
NAME contains a &quot;:&quot; or &quot;::&quot;, then everything up to but not including the<P>
first &quot;:&quot; or &quot;::&quot; is taken to be a string that names a package. Everything<P>
after the first &quot;:&quot; or &quot;::&quot; (if any) is taken to be a string that names a<P>
symbol. The function corresponding to a ~/name/ directive is obtained by<P>
looking up the symbol that has the indicated name in the indicated package.<P>
If NAME does not contain a &quot;:&quot; or &quot;::&quot;, then the whole name string is<P>
looked up in the USER package.<P>
<P>
When a ~/name/ directive is encountered, the indicated function is called<P>
with four or more arguments. The first four arguments are: the output<P>
stream, the <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> argument corresponding to the directive, the value T if<P>
the colon modifier was used (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> otherwise), and the value T if the atsign<P>
modifier was used (<A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> otherwise). The remaining arguments consist of any<P>
parameters specified with the directive. The function should print the<P>
argument appropriately. Any values returned by the function are ignored.<P>
<P>
The three functions <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-linear"><B>PPRINT-LINEAR</B></A>, <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>PPRINT-FILL</B></A>, and <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A> are<P>
specifically designed so that they can be called by ~/.../ (i.e.,<P>
~/PPRINT-LINEAR/, ~/PPRINT-FILL/, and ~/PPRINT-TABULAR/). In particular<P>
they take colon and atsign arguments.<P>
<P>
---<P>
<P>
As examples of the convenience of specifying pretty printing with <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A><P>
strings, consider that the first two functions used as examples in the last<P>
section can be compactly defined as follows. The function PPRINT-VECTOR<P>
cannot be defined using <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A>, because the data <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A> it traverses is<P>
not a list. The function <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A> is inconvenient to define using<P>
<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A>, because of the need to pass its TABSIZE argument through to a ~:T<P>
directive nested within an iteration over a list.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> simple-pprint-defun (<A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>format</B></A> T &quot;~:&lt;~W ~@_~:I~W ~:_~W~1I ~_~W~:&gt;&quot; <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>))<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>defun</B></A> pprint-let (<A REL=DEFINITION HREF="../Body/v_debug_.htm#STstandard-outputST"><B>*standard-output*</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>format</B></A> T &quot;~:&lt;~W~^ ~:&lt;~@{~:&lt;~@{~W~^ ~_~}~:&gt;~^ ~:_~}~:&gt;~1I~@{~^ ~_~W~}~:&gt;&quot; <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)) <P>
<P>
Compiling Format Control Strings<P>
<P>
The control strings used by <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> are essentially programs that perform<P>
printing. The macro <A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A> provides the efficiency of using a compiled<P>
function for printing without losing the compactness of <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> control<P>
strings.<P>
<P>
<A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A> control-string [macro]<P>
<P>
CONTROL-STRING must be a literal string. An error is signalled if<P>
CONTROL-STRING is not a valid <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> control string. The macro <A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A><P>
expands into an expression of the form (<A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> (<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> (<A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>STREAM</B></A> <A REL=DEFINITION HREF="../Body/03_da.htm#AMrest"><B>&amp;REST</B></A><P>
ARGS) ...)) that does the printing specified by CONTROL-STRING. The<P>
<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> created accepts an output stream as its first argument and zero or<P>
more data values as its remaining arguments. The value returned by the<P>
<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>LAMBDA</B></A> is the tail (if any) of the data values that are not printed out by<P>
CONTROL-STRING. (E.g., if the CONTROL-STRING is &quot;~A~A&quot; the <A REL=DEFINITION HREF="../Body/f_car_c.htm#cddr"><B>CDDR</B></A> (if any)<P>
of the data values is returned.)<P>
<P>
For instance: (<A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>formatter</B></A> &quot;~%~2@{~S, ~}&quot;) is equivalent to<P>
<P>
#'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> (stream &amp;rest args)<P>
(<A REL=DEFINITION HREF="../Body/f_terpri.htm#terpri"><B>terpri</B></A> <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>stream</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/m_dotime.htm#dotimes"><B>dotimes</B></A> (n 2)<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> (<A REL=DEFINITION HREF="../Body/a_null.htm#null"><B>null</B></A> args) (<A REL=DEFINITION HREF="../Body/m_return.htm#return"><B>return</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#prin1"><B>prin1</B></A> (<A REL=DEFINITION HREF="../Body/m_pop.htm#pop"><B>pop</B></A> args) <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>stream</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/f_wr_stg.htm#write-string"><B>write-string</B></A> &quot;, &quot; <A REL=DEFINITION HREF="../Body/t_stream.htm#stream"><B>stream</B></A>))<P>
args)<P>
<P>
In support of the above, <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> is extended so that it accepts functions as<P>
its second argument as well as strings. When a function is provided, it<P>
must be a function of the form created by <A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>FORMATTER</B></A>. The function is called<P>
with the appropriate output stream as its first argument and the data<P>
arguments to <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> as its remaining arguments. The function should<P>
perform whatever output is necessary and return the unused tail of the<P>
arguments (if any). The directives ~? and ~{~} with no body are also<P>
extended so that they accept functions as well as control strings.<P>
Every other <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> function that takes a <A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>FORMAT</B></A> string as an argument<P>
(e.g., <A REL=DEFINITION HREF="../Body/a_error.htm#error"><B>ERROR</B></A> and <A REL=DEFINITION HREF="../Body/f_warn.htm#warn"><B>WARN</B></A>) are also extended so that they can accept functions<P>
of the form above instead.<P>
<P>
Pretty Print Dispatch Tables<P>
<P>
When <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> is not <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, the <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch table in the variable<P>
<A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A> controls how objects are printed. The information<P>
in this table takes precedence over all other mechanisms for specifying how<P>
to print objects. In particular, it overrides user-defined <A REL=DEFINITION HREF="../Body/f_pr_obj.htm#print-object"><B>PRINT-OBJECT</B></A><P>
methods and print functions for structures. However, if there is no<P>
specification for how to pretty print a particular kind of object, it is then<P>
printed using the <A REL=DEFINITION HREF="../Body/07_ffb.htm#standard"><B>standard</B></A> mechanisms as if <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> were <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>.<P>
<P>
Pprint dispatch tables are mappings from keys to pairs of values. The keys<P>
are type specifiers. The values are functions and numerical priorities.<P>
Basic insertion and retrieval is done based on the keys with the equality<P>
of keys being tested by <A REL=DEFINITION HREF="../Body/f_equal.htm#equal"><B>EQUAL</B></A>. The function to use when pretty printing an<P>
object is chosen by finding the highest priority function from<P>
<A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A> that is associated with a type specifier that<P>
matches the object.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/f_cp_ppr.htm#copy-pprint-dispatch"><B>COPY-PPRINT-DISPATCH</B></A> &amp;optional (table <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>) [function]<P>
<P>
A copy is made of TABLE, which defaults to the current <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch<P>
table. If TABLE is <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, a copy is returned of the initial value of<P>
<A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>.<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/f_ppr_di.htm#pprint-dispatch"><B>PPRINT-DISPATCH</B></A> object &amp;optional (table <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>) [function] <P>
<P>
This retrieves the highest priority function from a <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> table that is<P>
associated with a type specifier in the table that matches OBJECT. The<P>
function is chosen by finding all the type specifiers in TABLE that match<P>
the object and selecting the highest priority function associated with any<P>
of these type specifiers. If there is more than one highest priority<P>
function, an arbitrary choice is made. If no type specifiers match the<P>
object, a function is returned that prints object with <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> bound<P>
to <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>.<P>
<P>
As a second return value, <A REL=DEFINITION HREF="../Body/f_ppr_di.htm#pprint-dispatch"><B>PPRINT-DISPATCH</B></A> returns a flag that is T if a<P>
matching type specifier was found in TABLE and <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> if not.<P>
<P>
TABLE (which defaults to <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>) must be a <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch<P>
table. TABLE can be <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, in which case retrieval is done in the initial<P>
value of <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>.<P>
<P>
When <A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> is T, (<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>WRITE</B></A> OBJECT :STREAM S) is equivalent to<P>
(<A REL=DEFINITION HREF="../Body/f_funcal.htm#funcall"><B>FUNCALL</B></A> (<A REL=DEFINITION HREF="../Body/f_ppr_di.htm#pprint-dispatch"><B>PPRINT-DISPATCH</B></A> OBJECT) S OBJECT).<P>
<P>
<P>
<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> type-specifier function [function]<P>
&amp;optional (priority 0) (table <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>)<P>
<P>
This puts an entry into a <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch table and returns <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>.<P>
TYPE-SPECIFIER must be a valid type specifier and is the key of the entry.<P>
The first action of <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> is to remove any pre-existing entry<P>
associated with TYPE-SPECIFIER. This guarantees that there will never be<P>
two entries associated with the same type specifier in a given <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A><P>
dispatch table. Equality of type specifiers is tested by <A REL=DEFINITION HREF="../Body/f_equal.htm#equal"><B>EQUAL</B></A>.<P>
<P>
Two values are associated with each type specifier in a <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch<P>
table: a function and a priority. <A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> must accept two arguments: the<P>
stream to send output to and the object to be printed. <A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> should<P>
pretty print the object on the stream. <A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> can assume that object<P>
satisfies TYPE-SPECIFIER. Function must obey <A REL=DEFINITION HREF="../Body/v_pr_rda.htm#STprint-readablyST"><B>*PRINT-READABLY*</B></A> (see issue<P>
<A HREF="iss089.htm">DATA-IO</A>). Any values returned by <A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> are ignored.<P>
<P>
PRIORITY (which defaults to 0) must be a non-complex number. This<P>
number is used as a priority to resolve conflicts when an object<P>
matches more than one entry. An error is signalled if priority fails<P>
to be a non-complex number.<P>
<P>
TABLE (which defaults to <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>) must be a <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch<P>
table. The specified entry is placed in this table.<P>
<P>
It is permissible for <A REL=DEFINITION HREF="../Body/a_fn.htm#function"><B>FUNCTION</B></A> to be <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>. In this situation, there will be<P>
no TYPE-SPECIFIER entry in TABLE after <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> is evaluated.<P>
<P>
To facilitate the use of <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch tables for controlling the pretty<P>
printing of Lisp code, the TYPE-SPECIFIER argument of the function<P>
<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A> is allowed to contain constructs of the form <P>
<P>
(<A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>CONS</B></A> car-type cdr-type)<P>
<P>
This signifies that the corresponding object must be a cons cell whose <A REL=DEFINITION HREF="../Body/f_car_c.htm#car"><B>car</B></A><P>
matches the type specifier CAR-TYPE and whose <A REL=DEFINITION HREF="../Body/f_car_c.htm#cdr"><B>cdr</B></A> matches the type specifier<P>
CDR-TYPE. The CDR-TYPE can be omitted in which case it defaults to T.<P>
<P>
<P>
The initial value of <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A> is implementation dependent.<P>
However, the initial entries all use a special <A REL=DEFINITION HREF="../Body/t_class.htm#class"><B>class</B></A> of priorities that<P>
have the property that they are less than every priority that can be<P>
specified using <A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>SET-PPRINT-DISPATCH</B></A>. The benefit of this is that it<P>
guarantees that any pretty printing functions users specify will override<P>
everything in the initial value of <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A>.<P>
<P>
----------------------------------------------------------------------<P>
<P>
Implementation note: The restriction above is very useful to users<P>
without actually limiting what Common Lisp implementors can do. It is<P>
possible for implementors to set up any kind of pretty printing they<P>
desire using the range of priorities available to them.<P>
<P>
----------------------------------------------------------------------<P>
<P>
<P>
Consider the following examples. The first form restores<P>
<A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*PRINT-PPRINT-DISPATCH*</B></A> to its initial value. The next two forms then set<P>
up a special way to pretty print ratios. Note that the more specific type<P>
specifier has to be associated with a higher priority.<P>
<P>
(<A REL=DEFINITION HREF="../Body/s_setq.htm#setq"><B>setq</B></A> <A REL=DEFINITION HREF="../Body/v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*print-pprint-dispatch*</B></A> (<A REL=DEFINITION HREF="../Body/f_cp_ppr.htm#copy-pprint-dispatch"><B>copy-pprint-dispatch</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>))<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>set-pprint-dispatch</B></A> '<A REL=DEFINITION HREF="../Body/t_ratio.htm#ratio"><B>ratio</B></A><P>
#'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> (s obj)<P>
(<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>format</B></A> s &quot;#.(/ ~W ~W)&quot; (<A REL=DEFINITION HREF="../Body/f_numera.htm#numerator"><B>numerator</B></A> obj) (<A REL=DEFINITION HREF="../Body/f_numera.htm#denominator"><B>denominator</B></A> obj))))<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>set-pprint-dispatch</B></A> '(<A REL=DEFINITION HREF="../Body/a_and.htm#and"><B>and</B></A> <A REL=DEFINITION HREF="../Body/t_ratio.htm#ratio"><B>ratio</B></A> (<A REL=DEFINITION HREF="../Body/t_satisf.htm#satisfies"><B>satisfies</B></A> <A REL=DEFINITION HREF="../Body/f_minusp.htm#minusp"><B>minusp</B></A>))<P>
#'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> (s obj)<P>
(<A REL=DEFINITION HREF="../Body/f_format.htm#format"><B>format</B></A> s &quot;#.(- (/ ~W ~W))&quot; (- (<A REL=DEFINITION HREF="../Body/f_numera.htm#numerator"><B>numerator</B></A> obj)) (<A REL=DEFINITION HREF="../Body/f_numera.htm#denominator"><B>denominator</B></A> obj)))<P>
5)<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> '(1/3 -2/3)) prints: (#.(/ 1 3) #.(- (/ 2 3)))<P>
<P>
The following two forms illustrate the definition of pretty printing<P>
functions for types of Lisp code. The first form illustrates how to<P>
specify the traditional <A REL=DEFINITION HREF="../Body/t_method.htm#method"><B>method</B></A> for printing quoted objects using &quot;'&quot;<P>
syntax. Note the care taken to ensure that data lists that happen to begin<P>
with <A REL=DEFINITION HREF="../Body/s_quote.htm#quote"><B>QUOTE</B></A> will be printed readably. The second form specifies that lists<P>
beginning with the symbol MY-LET should print the same way that lists<P>
beginning with <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> print when the initial <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch table is in effect.<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>set-pprint-dispatch</B></A> '(<A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>cons</B></A> (<A REL=DEFINITION HREF="../Body/a_member.htm#member"><B>member</B></A> <A REL=DEFINITION HREF="../Body/s_quote.htm#quote"><B>quote</B></A>)) () <P>
#'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> (s <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)<P>
(<A REL=DEFINITION HREF="../Body/s_if.htm#if"><B>if</B></A> (<A REL=DEFINITION HREF="../Body/a_and.htm#and"><B>and</B></A> (<A REL=DEFINITION HREF="../Body/f_consp.htm#consp"><B>consp</B></A> (<A REL=DEFINITION HREF="../Body/f_car_c.htm#cdr"><B>cdr</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)) (<A REL=DEFINITION HREF="../Body/a_null.htm#null"><B>null</B></A> (<A REL=DEFINITION HREF="../Body/f_car_c.htm#cddr"><B>cddr</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)))<P>
(<A REL=DEFINITION HREF="../Body/f_funcal.htm#funcall"><B>funcall</B></A> (<A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>formatter</B></A> &quot;'~W&quot;) s (<A REL=DEFINITION HREF="../Body/f_car_c.htm#cadr"><B>cadr</B></A> <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>))<P>
(<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>pprint-fill</B></A> s <A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A>)))))<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>set-pprint-dispatch</B></A> '(<A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>cons</B></A> (<A REL=DEFINITION HREF="../Body/a_member.htm#member"><B>member</B></A> my-let)) (<A REL=DEFINITION HREF="../Body/f_ppr_di.htm#pprint-dispatch"><B>pprint-dispatch</B></A> '(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>let</B></A>) <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>))<P>
<P>
The next example specifies a default <A REL=DEFINITION HREF="../Body/t_method.htm#method"><B>method</B></A> for printing lists that do not<P>
correspond to function calls. Note that, as shown in the definition of<P>
<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A> above, <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-linear"><B>PPRINT-LINEAR</B></A>, <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>PPRINT-FILL</B></A>, and <A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-tabular"><B>PPRINT-TABULAR</B></A> are<P>
all defined with optional COLON? and ATSIGN? arguments so that they can be<P>
used as <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> dispatch functions as well as ~/.../ functions.<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>set-pprint-dispatch</B></A> '(<A REL=DEFINITION HREF="../Body/a_cons.htm#cons"><B>cons</B></A> (<A REL=DEFINITION HREF="../Body/a_not.htm#not"><B>not</B></A> (<A REL=DEFINITION HREF="../Body/a_and.htm#and"><B>and</B></A> <A REL=DEFINITION HREF="../Body/t_symbol.htm#symbol"><B>symbol</B></A> (<A REL=DEFINITION HREF="../Body/t_satisf.htm#satisfies"><B>satisfies</B></A> <A REL=DEFINITION HREF="../Body/f_fbound.htm#fboundp"><B>fboundp</B></A>))))<P>
#'<A REL=DEFINITION HREF="../Body/f_ppr_fi.htm#pprint-fill"><B>pprint-fill</B></A> -5)<P>
<P>
with a line length of 9, (<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A> '(0 b c d e f g h i j k)) prints: <P>
(0 b c d<P>
e f g h<P>
i j k)<P>
<P>
This final example shows how to define a pretty printing function for a<P>
user defined data <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A>.<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_defstr.htm#defstruct"><B>defstruct</B></A> family mom kids)<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_set_pp.htm#set-pprint-dispatch"><B>set-pprint-dispatch</B></A> 'family<P>
#'(<A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> (s f)<P>
(<A REL=DEFINITION HREF="../Body/f_funcal.htm#funcall"><B>funcall</B></A> (<A REL=DEFINITION HREF="../Body/m_format.htm#formatter"><B>formatter</B></A> &quot;~@&lt;#&lt;~;~W <A REL=DEFINITION HREF="../Body/a_and.htm#and"><B>and</B></A> ~2I~_~/pprint-fill/~;&gt;~:&gt;&quot;)<P>
s (family-mom f) (family-kids f))))<P>
<P>
The pretty printing function for the <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A> FAMILY specifies how to<P>
adjust the layout of the output so that it can fit aesthetically into<P>
a variety of line widths. In addition, it obeys the printer control<P>
variables <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-levelST"><B>*PRINT-LEVEL*</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_lev.htm#STprint-lengthST"><B>*PRINT-LENGTH*</B></A>, <A REL=DEFINITION HREF="../Body/v_pr_lin.htm#STprint-linesST"><B>*PRINT-LINES*</B></A>,<P>
<A REL=DEFINITION HREF="../Body/v_pr_cir.htm#STprint-circleST"><B>*PRINT-CIRCLE*</B></A>, *PRINT-SHARED* and <A REL=DEFINITION HREF="../Body/v_pr_esc.htm#STprint-escapeST"><B>*PRINT-ESCAPE*</B></A>, and can tolerate<P>
several different kinds of malformity in the data <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A>. The<P>
output below shows what is printed out with a right margin of 25,<P>
<A REL=DEFINITION HREF="../Body/v_pr_pre.htm#STprint-prettyST"><B>*PRINT-PRETTY*</B></A> T, <A REL=DEFINITION HREF="../Body/v_pr_esc.htm#STprint-escapeST"><B>*PRINT-ESCAPE*</B></A> <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A>, and a malformed KIDS list.<P>
<P>
(<A REL=DEFINITION HREF="../Body/f_wr_pr.htm#write"><B>write</B></A> (<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>list</B></A> 'principal-family<P>
(make-family :mom &quot;Lucy&quot;<P>
:kids '(&quot;Mark&quot; &quot;Bob&quot; . &quot;Dan&quot;)))<P>
:right-margin 25 :pretty T :escape <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A> :miser-width <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>nil</B></A>)<P>
<P>
(PRINCIPAL-FAMILY<P>
#&lt;Lucy <A REL=DEFINITION HREF="../Body/a_and.htm#and"><B>and</B></A><P>
Mark Bob . Dan&gt;)<P>
<P>
Note that a pretty printing function for a <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A> is different from the<P>
<A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A>'s print function. While print functions are permanently<P>
associated with a <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A>, pretty printing functions are stored in <A REL=DEFINITION HREF="../Body/f_wr_pr.htm#pprint"><B>pprint</B></A><P>
dispatch tables and can be rapidly changed to reflect different printing<P>
needs. If there is no pretty printing function for a <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A> in the<P>
current print dispatch table, the print function (if any) is used instead.<P>
</PRE>
<HR>
<A REL=NAVIGATOR HREF="../Front/StartPts.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Starting Points]" SRC="../Graphics/StartPts.gif" ALIGN=Bottom></A><A REL=TOC HREF="../Front/Contents.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Contents]" SRC="../Graphics/Contents.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Master.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Index]" SRC="../Graphics/Index.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Symbol.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Symbols]" SRC="../Graphics/Symbols.gif" ALIGN=Bottom></A><A REL=GLOSSARY HREF="../Body/26_a.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Glossary]" SRC="../Graphics/Glossary.gif" ALIGN=Bottom></A><A HREF="../Front/X3J13Iss.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Issues]" SRC="../Graphics/Issues.gif" ALIGN=Bottom></A><BR>
<A REL=COPYRIGHT HREF="../Front/Help.htm#Legal"><I>Copyright 1996-2005, LispWorks Ltd. All rights reserved.</I></A><P>
</BODY>
</HTML>