aboutsummaryrefslogtreecommitdiff
path: root/branch-master/doc/pprint/CommonLispFormat.html
blob: dfbcbe1b97f628896d1dab05355282eb00ba7460 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
<html>
  <head>
    <title>A Common Lisp-compatible Format Function</title>
    <link href="../../../static/favicon.png" rel="icon" />
    <link href="../../../static/favicon.png" rel="shortcut icon" />
    <link media="all" type="text/css" href="../../../static/clojure.css" rel="stylesheet" />
    <link media="all" type="text/css" href="../../../static/wiki.css" rel="stylesheet" />
    <link media="all" type="text/css" href="../../../static/internal.css" rel="stylesheet" />
    <!-- TODO: are we using these (from clojure.org)? If so, add the files -->
    <script src="file/view/code_highlighter.js" type="text/javascript"></script>
    <script src="file/view/clojure.js" type="text/javascript"></script>
    <style>.menuWrapper{height: 36px;}</style>
    <!--[if lte IE 6]>
    <link rel="stylesheet" href="http://www.wikispaces.com/_/2009051601/s/internal_ie.css" type="text/css" />
    <![endif]-->
  </head>
<!--
This document was auto-generated from the source by the clojure autodoc system.
To report errors or ask questions about the overall documentation structure, formatting,
etc., contact Tom Faulhaber (google mail name: tomfaulhaber).
For errors in the documentation of a particular namespace, contact the author of that
namespace.
-->
  <body>
    <div id="AllContentContainer">
      <div id="Header">
	<a id="Logo" href="index.html"><img alt="Clojure" height="100" width="100" src="../../../static/clojure-icon.gif" /></a>
	<h1><a title="page header title" id="page-header" href="index.html">Clojure-contrib API Reference</a></h1>
      </div>
      <div id="leftcolumn"><div style="text-align: center;"></div>
<div class="menu">
  <div class="WikiCustomNav WikiElement wiki">
    <span class="toc-header"><span id="project-name">clojure-contrib</span> <span id="version">next</span> API</span><br />
    <ul>
      <li><a class="wiki_link" href="../../../index.html">Overview</a></li>
      <li><a class="wiki_link" href="../../../api-index.html">API Index</a></li>
    </ul>
    <span class="toc-header">Namespaces</span>
    <ul id="left-sidebar-list">
      
    </ul>
    <div class="BranchTOC">
      <span class="toc-header">Other Versions</span>
      <ul id="left-sidebar-branch-list">
        <li><a href="../../../../index.html" class="wiki_link">v1.2 (beta 1)</a></li><li><a href="../../../../branch-1.1.x/index.html" class="wiki_link">v1.1 (stable)</a></li>
      </ul>
    </div>
    <a href="../../../http://clojure.org" class="wiki_link">Clojure Home</a>
  </div>
</div>
</div>
      <div id="rightcolumn">
	<div id="Content">
	  <div class="contentBox"><div class="innerContentBox">
              <div id="content_view" class="wiki wikiPage">
                <div id="right-sidebar"></div>
                <div id="content-tag"><html><body><h1>A Common Lisp-compatible Format Function</h1>

<p>cl-format is an implementation of the incredibly baroque Common Lisp format function as specified 
in <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/clm/node200.html#SECTION002633000000000000000">Common Lisp, the Language, 2nd edition, Chapter 22</a>.</p>

<p>Format gives you an easy and powerful way to format text and data for output. It supports rich 
formatting of strings and numbers, loops, conditionals, embedded formats, etc. It is really a 
domain-specific language for formatting.</p>

<p>This implementation for clojure has the following goals:</p>

<ul>
<li>Support the full feature set of the Common Lisp format function (including the X3J13 extensions) with the only exception being concepts that make no sense or are differently interpreted in Clojure.</li>
<li>Make porting code from Common Lisp easier.</li>
<li>Provide a more native feeling solution for Clojure programmers than the Java format method and its relatives.</li>
<li>Be fast. This includes the ability to precompile formats that are going to be used reptitively.</li>
<li>Include useful error handling and comprehensive documentation.</li>
</ul>

<h2>Why would I use cl-format?</h2>

<p>For some people the answer to this question is that they are used to
Common Lisp and, therefore, they already know the syntax of format
strings and all the directives.</p>

<p>A more interesting answer is that cl-format provides a way of
rendering strings that is much more suited to Lisp and its data
structures. </p>

<p>Because iteration and conditionals are built into the directive
structure of cl-format, it is possible to render sequences and other
complex data structures directly without having to loop over the data
structure. </p>

<p>For example, to print the elements of a sequence separated by commas,
you simply say:</p>

<pre><code>(cl-format true "~{~a~^, ~}" aseq)
</code></pre>

<p>(This example is taken from 
<a href="http://www.gigamonkeys.com/book/">Practical Common Lisp</a>
by Peter Seibel.)</p>

<p>The corresponding output using Clojure's Java-based <em>format</em> function
would involve a nasty loop/recur with some code to figure out about
the commas. Yuck!</p>

<h2>Current Status of cl-format</h2>

<p>cl-format is 100% compatible with the Common Lisp standard as
specified in CLtLv2.
This includes all of the functionality of Common
Lisp's format function including iteration, conditionals, 
text justification and rich
options for displaying real and integer values. It also includes the
directives to support pretty printing structured output.</p>

<p>If you find a bug in a directive, drop me a line
with a chunk of code that exhibits the bug and the version of
cl-format you found it in and I'll try to get it fixed.</p>

<p>I also intend to have good built-in documentation for the directives,
but I haven't built that yet.</p>

<p>The following directives are
not yet supported: ~:T and ~@:T (but all other forms of ~T work) 
and extensions with ~/. </p>

<p>The pretty printer interface is similar, but not identical to the 
interface in Common Lisp.</p>

<p>The custom dispatch table functionality is not fully fleshed out yet.</p>

<p>Next up: </p>

<ul>
<li>Support for ~/</li>
<li>Restructure unit tests into modular chunks.</li>
<li>Import tests from CLISP and SBCL.</li>
<li>Unit tests for exception conditions.</li>
<li>Interactive documentation</li>
</ul>

<h2>How to use cl-format</h2>

<h3>Loading cl-format in your program</h3>

<p>Once cl-format is in your path, adding it to your code is easy:</p>

<pre><code>(ns your-namespace-here
  (:use clojure.contrib.pprint))
</code></pre>

<p>If you want to refer to the cl-format function as "format" (rather
than using the clojure function of that name), you can use this idiom:</p>

<pre><code>(ns your-namespace-here
  (:refer-clojure :exclude [format])
  (:use clojure.contrib.pprint))

(def format cl-format)
</code></pre>

<p>You might want to do this in code that you've ported from Common Lisp,
for instance, or maybe just because old habits die hard.</p>

<p>From the REPL, you can grab it using (use):</p>

<pre><code>(use 'clojure.contrib.pprint)
</code></pre>

<h3>Calling cl-format</h3>

<p>cl-format is a standard clojure function that takes a variable number
of arguments. You call it like this:</p>

<pre><code>(cl-format stream format args...)
</code></pre>

<p><em>stream</em> can be any Java Writer (that is java.io.Writer) or the values
<em>true</em>, <em>false</em>, or <em>nil</em>. The argument <em>true</em> is identical to using
<code>*</code>out<code>*</code> while <em>false</em> or <em>nil</em> indicate that cl-format should return
its result as a string rather than writing it to a stream.</p>

<p><em>format</em> is either a format string or a compiled format (see
below). The format string controls the output that's written in a way
that's similar to (but much more powerful than) the standard Clojure
API format function (which is based on Java's
java.lang.String.Format).</p>

<p>Format strings consist of characters that are to be written to the
output stream plus directives (which are marked by ~) as in "The
answer is ~,2f". Format strings are documented in detail in 
<a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/clm/node200.html#SECTION002633000000000000000"><em>Common Lisp the Language</em>, 2nd edition, Chapter 22</a>.</p>

<p><em>args</em> is a set of arguments whose use is defined by the format.</p>

<h3>Compiled formats</h3>

<p>When you use a format string many times (for example, when you're outputting
in a loop), you can improve your performance by compiling the format
with <em>compile-format</em>. The result of compile format can be passed to
<em>cl-format</em> just like a format string but it doesn't need to be
parsed.</p>

<p>For example:</p>

<pre><code>(def log-format (compile-format "~2,'0D/~2,'0D/~D ~2D:~2,'0D ~:[PM,AM]: ~A~%"))

(defn log [msg]
  (let [[m d y h min am?] (some-date-decomposition-fn)]
    (cl-format log-format m d y h min am? msg)))
</code></pre>

<h2>Using column aware streams across format invocations</h2>

<p>Writers in Java have no real idea of current column or device page width, so the format
directives that want to work relative to the current position on the
page have nothing to work with. To deal with this, cl-format contains
an extension to writer called PrettyWriter. PrettyWriter watches the
output and keeps track of what column the current output is going to.</p>

<p>When you call format and your format includes a directive that cares
about what column it's in (~T, ~&amp;, ~&lt;...~&gt;), cl-format will
automatically wrap the Writer you passed in with a PrettyWriter. This
means that by default all cl-format statements act like they begin on
a fresh line and have a page width of 72.</p>

<p>For many applications, these assumptions are fine and you need to do
nothing more. But sometimes you want to use multiple cl-format calls
that output partial lines. You may also want to mix cl-format calls
with the native clojure calls like print. If you want stay
column-aware while doingg this you need to create a PrettyWriter of
your own (and possibly bind it to <code>*</code>out<code>*</code>).</p>

<p>As an example of this, this function takes a nested list and prints it
as a table (returning the result as a string):</p>

<pre><code>(defn list-to-table [aseq column-width]
  (let [stream (PrettyWriter. (java.io.StringWriter.))]
    (binding [*out* stream]
     (doseq [row aseq]
       (doseq [col row]
         (cl-format true "~4D~7,vT" col column-width))
       (prn)))
    (.toString (.getWriter stream))))
</code></pre>

<p>(In reality, you'd probably do this as a single call to cl-format.)</p>

<p>The constructor to PrettyWriter takes the Writer it's wrapping and
(optionally) the page width (in columns) for use with ~&lt;...~&gt;. </p>

<h2>Examples</h2>

<p>The following function uses cl-format to dump a columnized table of the Java system properties:</p>

<pre><code>(defn show-props [stream]
  (let [p (mapcat 
           #(vector (key %) (val %)) 
           (sort-by key (System/getProperties)))]
    (cl-format stream "~30A~A~%~{~20,,,'-A~10A~}~%~{~30A~S~%~}" 
               "Property" "Value" ["" "" "" ""] p)))
</code></pre>

<p>There are some more examples in the clojure.contrib.pprint.examples
package:</p>

<ul>
<li>hexdump - a program that uses cl-format to create a standard formatted hexdump of the requested stream.</li>
<li>multiply - a function to show a formatted multipication table in a very "first-order" way.</li>
<li>props - the show-props example shown above.</li>
<li>show_doc - some utilities for showing documentation from various name spaces.</li>
</ul>

<h2>Differences from the Common Lisp format function</h2>

<p>The floating point directives that show exponents (~E, ~G) show E for
the exponent character in all cases (unless overridden with an
<em>exponentchar</em>).  Clojure does not distinguish between floats and
doubles in its printed representation and neither does cl-format.</p>

<p>The ~A and ~S directives accept the colon prefix, but ignore it since
() and nil are not equivalent in Clojure.</p>

<p>Clojure has 3 different reader syntaxes for characters. The ~@c
directive to cl-format has an argument extension to let you choose:</p>

<ul>
<li>~@c (with no argument) prints "\c" (backslash followed by the printed representation of the character or \newline, \space, \tab, \backspace, \return)</li>
<li>~'o@c prints "\oDDD" where DDD are the octal digits representing the character. </li>
<li>~'u@c prints "\uXXXX" prints the hex Unicode representation of the character.  </li>
</ul>
</body></html></div>
              </div>
            </div>
          </div>
	</div>
	<div id="foot">
	  <div style="text-align: center;" id="copyright">Copyright 2007-2010 by Rich Hickey and the various contributors</div>
	</div>
      </div>
      <div id="DesignedBy">Logo &amp; site design by <a title="Visit Tom Hickey's website." href="http://www.tomhickey.com">Tom Hickey</a>.<br />
      Clojure auto-documentation system by Tom Faulhaber.</div>
    </div>
    <!-- /AllContentContainer -->
  </body>

</html>