236 lines
17 KiB
HTML
236 lines
17 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: Section 22.2.2</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="22_bae.htm">
|
|
<LINK REL=UP HREF="22_b.htm">
|
|
<LINK REL=NEXT HREF="22_bc.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="22_bae.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="22_b.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="22_bc.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
|
|
|
|
<HR>
|
|
|
|
<H2>
|
|
22.2.2 Examples of using the Pretty Printer</H2> <P>
|
|
As an example of the interaction of logical blocks, conditional newlines, and indentation, consider the function <TT>simple-pprint-defun</TT> below. This function prints out lists whose <A REL=DEFINITION HREF="26_glo_c.htm#car"><I>cars</I></A> are <A REL=DEFINITION HREF="m_defun.htm#defun"><B>defun</B></A> in the standard way assuming that the list has exactly length <TT>4</TT>. <P>
|
|
<PRE>
|
|
(defun simple-pprint-defun (*standard-output* list)
|
|
(pprint-logical-block (*standard-output* list :prefix "(" :suffix ")")
|
|
(write (first list))
|
|
(write-char #\Space)
|
|
(pprint-newline :miser)
|
|
(pprint-indent :current 0)
|
|
(write (second list))
|
|
(write-char #\Space)
|
|
(pprint-newline :fill)
|
|
(write (third list))
|
|
(pprint-indent :block 1)
|
|
(write-char #\Space)
|
|
(pprint-newline :linear)
|
|
(write (fourth list))))
|
|
</PRE>
|
|
</TT> <P>
|
|
Suppose that one evaluates the following: <P>
|
|
<PRE>
|
|
(simple-pprint-defun *standard-output* '(defun prod (x y) (* x y)))
|
|
</PRE>
|
|
</TT> <P>
|
|
If the line width available is greater than or equal to <TT>26</TT>, then all of the output appears on one line. If the line width available is reduced to <TT>25</TT>, a line break is inserted at the linear-style conditional newline before the <A REL=DEFINITION HREF="26_glo_e.htm#expression"><I>expression</I></A> <TT>(* x y)</TT>, producing the output shown. The <TT>(pprint-indent :block 1)</TT> causes <TT>(* x y)</TT> to be printed at a relative indentation of <TT>1</TT> in the logical block. <P>
|
|
<PRE>
|
|
(DEFUN PROD (X Y)
|
|
(* X Y))
|
|
</PRE>
|
|
</TT> <P>
|
|
If the line width available is <TT>15</TT>, a line break is also inserted at the fill style conditional newline before the argument list. The call on <TT>(pprint-indent :current 0)</TT> causes the argument list to line up under the function name. <P>
|
|
<PRE>
|
|
(DEFUN PROD
|
|
(X Y)
|
|
(* X Y))
|
|
</PRE>
|
|
</TT> <P>
|
|
If <A REL=DEFINITION HREF="v_pr_mis.htm#STprint-miser-widthST"><B>*print-miser-width*</B></A> were greater than or equal to 14, the example output above would have been as follows, because all indentation changes are ignored in miser mode and line breaks are inserted at miser-style conditional newlines. <P>
|
|
<PRE>
|
|
(DEFUN
|
|
PROD
|
|
(X Y)
|
|
(* X Y))
|
|
</PRE>
|
|
</TT> <P>
|
|
As an example of a per-line prefix, consider that evaluating the following produces the output shown with a line width of <TT>20</TT> and <A REL=DEFINITION HREF="v_pr_mis.htm#STprint-miser-widthST"><B>*print-miser-width*</B></A> of <A REL=DEFINITION HREF="a_nil.htm#nil"><B>nil</B></A>. <P>
|
|
<PRE>
|
|
(pprint-logical-block (*standard-output* nil :per-line-prefix ";;; ")
|
|
(simple-pprint-defun *standard-output* '(defun prod (x y) (* x y))))
|
|
|
|
;;; (DEFUN PROD
|
|
;;; (X Y)
|
|
;;; (* X Y))
|
|
</PRE>
|
|
</TT> <P>
|
|
As a more complex (and realistic) example, consider the function <TT>pprint-let</TT> below. This specifies how to print a <A REL=DEFINITION HREF="s_let_l.htm#let"><B>let</B></A> <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> in the traditional style. It is more complex than the example above, because it has to deal with nested structure. Also, unlike the example above it contains complete code to readably print any possible list that begins with the <A REL=DEFINITION HREF="26_glo_s.htm#symbol"><I>symbol</I></A> <A REL=DEFINITION HREF="s_let_l.htm#let"><B>let</B></A>. The outermost <A REL=DEFINITION HREF="m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> handles the printing of the input list as a whole and specifies that parentheses should be printed in the output. The second <A REL=DEFINITION HREF="m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> handles the list of binding pairs. Each pair in the list is itself printed by the innermost <A REL=DEFINITION HREF="m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A>. (A <A REL=DEFINITION HREF="m_loop.htm#loop"><B>loop</B></A> <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> is used instead of merely decomposing the pair into two <A REL=DEFINITION HREF="26_glo_o.htm#object"><I>objects</I></A> so that readable output will be produced no matter whether the list corresponding to the pair has one element, two elements, or (being malformed) has more than two elements.) A space and a fill-style conditional newline are placed after each pair except the last. The loop at the end of the topmost <A REL=DEFINITION HREF="m_ppr_lo.htm#pprint-logical-block"><B>pprint-logical-block</B></A> <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> prints out the forms in the body of the <A REL=DEFINITION HREF="s_let_l.htm#let"><B>let</B></A> <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> separated by spaces and linear-style conditional newlines. <P>
|
|
<PRE>
|
|
(defun pprint-let (*standard-output* list)
|
|
(pprint-logical-block (nil list :prefix "(" :suffix ")")
|
|
(write (pprint-pop))
|
|
(pprint-exit-if-list-exhausted)
|
|
(write-char #\Space)
|
|
(pprint-logical-block (nil (pprint-pop) :prefix "(" :suffix ")")
|
|
(pprint-exit-if-list-exhausted)
|
|
(loop (pprint-logical-block (nil (pprint-pop) :prefix "(" :suffix ")")
|
|
(pprint-exit-if-list-exhausted)
|
|
(loop (write (pprint-pop))
|
|
(pprint-exit-if-list-exhausted)
|
|
(write-char #\Space)
|
|
(pprint-newline :linear)))
|
|
(pprint-exit-if-list-exhausted)
|
|
(write-char #\Space)
|
|
(pprint-newline :fill)))
|
|
(pprint-indent :block 1)
|
|
(loop (pprint-exit-if-list-exhausted)
|
|
(write-char #\Space)
|
|
(pprint-newline :linear)
|
|
(write (pprint-pop)))))
|
|
</PRE>
|
|
</TT> <P>
|
|
Suppose that one evaluates the following with <A REL=DEFINITION HREF="v_pr_lev.htm#STprint-levelST"><B>*print-level*</B></A> being 4, and <A REL=DEFINITION HREF="v_pr_cir.htm#STprint-circleST"><B>*print-circle*</B></A> being <A REL=DEFINITION HREF="26_glo_t.htm#true"><I>true</I></A>. <P>
|
|
<PRE>
|
|
(pprint-let *standard-output*
|
|
'#1=(let (x (*print-length* (f (g 3)))
|
|
(z . 2) (k (car y)))
|
|
(setq x (sqrt z)) #1#))
|
|
</PRE>
|
|
</TT> <P>
|
|
If the line length is greater than or equal to <TT>77</TT>, the output produced appears on one line. However, if the line length is <TT>76</TT>, line breaks are inserted at the linear-style conditional newlines separating the forms in the body and the output below is produced. Note that, the degenerate binding pair <TT>x</TT> is printed readably even though it fails to be a list; a depth abbreviation marker is printed in place of <TT>(g 3)</TT>; the binding pair <TT>(z . 2)</TT> is printed readably even though it is not a proper list; and appropriate circularity markers are printed. <P>
|
|
<PRE>
|
|
#1=(LET (X (*PRINT-LENGTH* (F #)) (Z . 2) (K (CAR Y)))
|
|
(SETQ X (SQRT Z))
|
|
#1#)
|
|
</PRE>
|
|
</TT> <P>
|
|
If the line length is reduced to <TT>35</TT>, a line break is inserted at one of the fill-style conditional newlines separating the binding pairs. <P>
|
|
<PRE>
|
|
#1=(LET (X (*PRINT-PRETTY* (F #))
|
|
(Z . 2) (K (CAR Y)))
|
|
(SETQ X (SQRT Z))
|
|
#1#)
|
|
</PRE>
|
|
</TT> <P>
|
|
Suppose that the line length is further reduced to <TT>22</TT> and <A REL=DEFINITION HREF="v_pr_lev.htm#STprint-lengthST"><B>*print-length*</B></A> is set to <TT>3</TT>. In this situation, line breaks are inserted after both the first and second binding pairs. In addition, the second binding pair is itself broken across two lines. Clause (b) of the description of fill-style conditional newlines (see the <A REL=DEFINITION HREF="26_glo_f.htm#function"><I>function</I></A> <A REL=DEFINITION HREF="f_ppr_nl.htm#pprint-newline"><B>pprint-newline</B></A>) prevents the binding pair <TT>(z . 2)</TT> from being printed at the end of the third line. Note that the length abbreviation hides the circularity from view and therefore the printing of circularity markers disappears. <P>
|
|
<PRE>
|
|
(LET (X
|
|
(*PRINT-LENGTH*
|
|
(F #))
|
|
(Z . 2) ...)
|
|
(SETQ X (SQRT Z))
|
|
...)
|
|
</PRE>
|
|
</TT> <P>
|
|
The next function prints a vector using ``<TT>#(...)</TT>'' notation. <P>
|
|
<PRE>
|
|
(defun pprint-vector (*standard-output* v)
|
|
(pprint-logical-block (nil nil :prefix "#(" :suffix ")")
|
|
(let ((end (length v)) (i 0))
|
|
(when (plusp end)
|
|
(loop (pprint-pop)
|
|
(write (aref v i))
|
|
(if (= (incf i) end) (return nil))
|
|
(write-char #\Space)
|
|
(pprint-newline :fill))))))
|
|
</PRE>
|
|
</TT> <P>
|
|
Evaluating the following with a line length of 15 produces the output shown. <P>
|
|
<PRE>
|
|
(pprint-vector *standard-output* '#(12 34 567 8 9012 34 567 89 0 1 23))
|
|
|
|
#(12 34 567 8
|
|
9012 34 567
|
|
89 0 1 23)
|
|
</PRE>
|
|
</TT> <P>
|
|
As examples of the convenience of specifying pretty printing with <A REL=DEFINITION HREF="26_glo_f.htm#format_string"><I>format strings</I></A>, consider that the functions <TT>simple-pprint-defun</TT> and <TT>pprint-let</TT> used as examples above can be compactly defined as follows. (The function <TT>pprint-vector</TT> cannot be defined using <A REL=DEFINITION HREF="f_format.htm#format"><B>format</B></A> because the data structure it traverses is not a list.) <P>
|
|
<PRE>
|
|
(defun simple-pprint-defun (*standard-output* list)
|
|
(format T "~:<~W ~@_~:I~W ~:_~W~1I ~_~W~:>" list))
|
|
|
|
(defun pprint-let (*standard-output* list)
|
|
(format T "~:<~W~^~:<~@{~:<~@{~W~^~_~}~:>~^~:_~}~:>~1I~@{~^~_~W~}~:>" list))
|
|
</PRE>
|
|
</TT> <P>
|
|
In the following example, the first <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> restores <A REL=DEFINITION HREF="v_pr_ppr.htm#STprint-pprint-dispatchST"><B>*print-pprint-dispatch*</B></A> to the equivalent of its initial value. The next two forms then set up a special way to pretty print ratios. Note that the more specific <A REL=DEFINITION HREF="26_glo_t.htm#type_specifier"><I>type specifier</I></A> has to be associated with a higher priority. <P>
|
|
<PRE>
|
|
(setq *print-pprint-dispatch* (copy-pprint-dispatch nil))
|
|
|
|
(set-pprint-dispatch 'ratio
|
|
#'(lambda (s obj)
|
|
(format s "#.(/ ~W ~W)"
|
|
(numerator obj) (denominator obj))))
|
|
|
|
(set-pprint-dispatch '(and ratio (satisfies minusp))
|
|
#'(lambda (s obj)
|
|
(format s "#.(- (/ ~W ~W))"
|
|
(- (numerator obj)) (denominator obj)))
|
|
5)
|
|
|
|
(pprint '(1/3 -2/3))
|
|
(#.(/ 1 3) #.(- (/ 2 3)))
|
|
</PRE>
|
|
</TT> <P>
|
|
The following two <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>forms</I></A> illustrate the definition of pretty printing functions for types of <A REL=DEFINITION HREF="26_glo_c.htm#code"><I>code</I></A>. The first <A REL=DEFINITION HREF="26_glo_f.htm#form"><I>form</I></A> illustrates how to specify the traditional method for printing quoted objects using <A REL=DEFINITION HREF="26_glo_s.htm#single-quote"><I>single-quote</I></A>. Note the care taken to ensure that data lists that happen to begin with <A REL=DEFINITION HREF="s_quote.htm#quote"><B>quote</B></A> will be printed readably. The second form specifies that lists beginning with the symbol <TT>my-let</TT> should print the same way that lists beginning with <A REL=DEFINITION HREF="s_let_l.htm#let"><B>let</B></A> print when the initial <A REL=DEFINITION HREF="26_glo_p.htm#pprint_dispatch_table"><I>pprint dispatch table</I></A> is in effect. <P>
|
|
<PRE>
|
|
(set-pprint-dispatch '(cons (member quote)) ()
|
|
#'(lambda (s list)
|
|
(if (and (consp (cdr list)) (null (cddr list)))
|
|
(funcall (formatter "'~W") s (cadr list))
|
|
(pprint-fill s list))))
|
|
|
|
(set-pprint-dispatch '(cons (member my-let))
|
|
(pprint-dispatch '(let) nil))
|
|
</PRE>
|
|
</TT> <P>
|
|
The next example specifies a default method for printing lists that do not correspond to function calls. Note that the functions <A REL=DEFINITION HREF="f_ppr_fi.htm#pprint-linear"><B>pprint-linear</B></A>, <A REL=DEFINITION HREF="f_ppr_fi.htm#pprint-fill"><B>pprint-fill</B></A>, and <A REL=DEFINITION HREF="f_ppr_fi.htm#pprint-tabular"><B>pprint-tabular</B></A> are all defined with optional <I>colon-p</I> and <I>at-sign-p</I> arguments so that they can be used as <B>pprint dispatch functions</B> as well as <TT>~/.../</TT> functions. <P>
|
|
<PRE>
|
|
(set-pprint-dispatch '(cons (not (and symbol (satisfies fboundp))))
|
|
#'pprint-fill -5)
|
|
|
|
;; Assume a line length of 9
|
|
(pprint '(0 b c d e f g h i j k))
|
|
(0 b c d
|
|
e f g h
|
|
i j k)
|
|
</PRE>
|
|
</TT> <P>
|
|
This final example shows how to define a pretty printing function for a user defined data structure. <P>
|
|
<PRE>
|
|
(defstruct family mom kids)
|
|
|
|
(set-pprint-dispatch 'family
|
|
#'(lambda (s f)
|
|
(funcall (formatter "~@<#<~;~W and ~2I~_~/pprint-fill/~;>~:>")
|
|
s (family-mom f) (family-kids f))))
|
|
</PRE>
|
|
</TT> <P>
|
|
The pretty printing function for the structure <TT>family</TT> specifies how to adjust the layout of the output so that it can fit aesthetically into a variety of line widths. In addition, it obeys the printer control variables <A REL=DEFINITION HREF="v_pr_lev.htm#STprint-levelST"><B>*print-level*</B></A>, <A REL=DEFINITION HREF="v_pr_lev.htm#STprint-lengthST"><B>*print-length*</B></A>, <A REL=DEFINITION HREF="v_pr_lin.htm#STprint-linesST"><B>*print-lines*</B></A>, <A REL=DEFINITION HREF="v_pr_cir.htm#STprint-circleST"><B>*print-circle*</B></A> and <A REL=DEFINITION HREF="v_pr_esc.htm#STprint-escapeST"><B>*print-escape*</B></A>, and can tolerate several different kinds of malformity in the data structure. The output below shows what is printed out with a right margin of <TT>25</TT>, <A REL=DEFINITION HREF="v_pr_pre.htm#STprint-prettyST"><B>*print-pretty*</B></A> being <A REL=DEFINITION HREF="26_glo_t.htm#true"><I>true</I></A>, <A REL=DEFINITION HREF="v_pr_esc.htm#STprint-escapeST"><B>*print-escape*</B></A> being <A REL=DEFINITION HREF="26_glo_f.htm#false"><I>false</I></A>, and a malformed <TT>kids</TT> list. <P>
|
|
<PRE>
|
|
(write (list 'principal-family
|
|
(make-family :mom "Lucy"
|
|
:kids '("Mark" "Bob" . "Dan")))
|
|
:right-margin 25 :pretty T :escape nil :miser-width nil)
|
|
(PRINCIPAL-FAMILY
|
|
#<Lucy and
|
|
Mark Bob . Dan>)
|
|
</PRE>
|
|
</TT> <P>
|
|
Note that a pretty printing function for a structure is different from the structure's <A REL=DEFINITION HREF="f_pr_obj.htm#print-object"><B>print-object</B></A> <A REL=DEFINITION HREF="26_glo_m.htm#method"><I>method</I></A>. While <A REL=DEFINITION HREF="f_pr_obj.htm#print-object"><B>print-object</B></A> <A REL=DEFINITION HREF="26_glo_m.htm#method"><I>methods</I></A> are permanently associated with a structure, pretty printing functions are stored in <A REL=DEFINITION HREF="26_glo_p.htm#pprint_dispatch_table"><I>pprint dispatch tables</I></A> and can be rapidly changed to reflect different printing needs. If there is no pretty printing function for a structure in the current <A REL=DEFINITION HREF="26_glo_p.htm#pprint_dispatch_table"><I>pprint dispatch table</I></A>, its <A REL=DEFINITION HREF="f_pr_obj.htm#print-object"><B>print-object</B></A> <A REL=DEFINITION HREF="26_glo_m.htm#method"><I>method</I></A> is used instead. <P>
|
|
<P><HR>The following <A REL=META HREF="../Front/X3J13Iss.htm">X3J13 cleanup issue</A>, <I>not part of the specification</I>, applies to this section:<P><UL><LI> <A REL=CHILD HREF="../Issues/iss116.htm">DEFSTRUCT-PRINT-FUNCTION-AGAIN:X3J13-MAR-93</A><P></UL><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>
|