File: Printf

package info (click to toggle)
mlton 20130715-3
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 60,900 kB
  • ctags: 69,386
  • sloc: xml: 34,418; ansic: 17,399; lisp: 2,879; makefile: 1,605; sh: 1,254; pascal: 256; python: 143; asm: 97
file content (189 lines) | stat: -rw-r--r-- 22,915 bytes parent folder | download
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="generator" content="AsciiDoc 8.6.8">
<title>Printf</title>
<link rel="stylesheet" href="./asciidoc.css" type="text/css">
<link rel="stylesheet" href="./pygments.css" type="text/css">


<script type="text/javascript" src="./asciidoc.js"></script>
<script type="text/javascript">
/*<![CDATA[*/
asciidoc.install();
/*]]>*/
</script>
<link rel="stylesheet" href="./mlton.css" type="text/css"/>
</head>
<body class="article">
<div id="banner">
<div id="banner-home">
<a href="./Home">MLton 20130715</a>
</div>
</div>
<div id="header">
<h1>Printf</h1>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph"><p>Programmers coming from C or Java often ask if
<a href="StandardML">Standard ML</a> has a <span class="monospaced">printf</span> function.  It does not.
However, it is possible to implement your own version with only a few
lines of code.</p></div>
<div class="paragraph"><p>Here is a definition for <span class="monospaced">printf</span> and <span class="monospaced">fprintf</span>, along with format
specifiers for booleans, integers, and reals.</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">Printf</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">   </span><span class="k">struct</span><span class="w"></span>
<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="p">(_,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">())</span><span class="w"> </span><span class="n">ignore</span><span class="w"></span>
<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">fprintf</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="n">id</span><span class="p">)</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">printf</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">fprintf</span><span class="w"> </span><span class="n">TextIO</span><span class="p">.</span><span class="n">stdOut</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="p">((</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">),</span><span class="w"> </span><span class="n">make</span><span class="p">)</span><span class="w"> </span><span class="n">g</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">         </span><span class="n">g</span><span class="w"> </span><span class="p">(</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">            </span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">               </span><span class="n">make</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">                     </span><span class="n">r</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">p</span><span class="w"> </span><span class="p">();</span><span class="w"> </span><span class="n">TextIO</span><span class="p">.</span><span class="n">output</span><span class="w"> </span><span class="p">(</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">))))))</span><span class="w"></span>
<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">`</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">s</span><span class="p">)</span><span class="w"></span>
<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">to</span><span class="p">)</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">B</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">Bool</span><span class="p">.</span><span class="n">toString</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">Int</span><span class="p">.</span><span class="n">toString</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">R</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">toString</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>Here&#8217;s an example use.</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">printf</span><span class="w"> </span><span class="n">`</span><span class="s">&quot;Int=&quot;</span><span class="n">I`</span><span class="s">&quot;  Bool=&quot;</span><span class="n">B`</span><span class="s">&quot;  Real=&quot;</span><span class="n">R`</span><span class="s">&quot;</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">false</span><span class="w"> </span><span class="mf">2.0</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>This prints the following.</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>Int=1  Bool=false  Real=2.0</pre>
</div></div>
<div class="paragraph"><p>In general, a use of <span class="monospaced">printf</span> looks like</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>printf &lt;spec1&gt; ... &lt;specn&gt; $ &lt;arg1&gt; ... &lt;argm&gt;</pre>
</div></div>
<div class="paragraph"><p>where each <span class="monospaced">&lt;speci&gt;</span> is either a specifier like <span class="monospaced">B</span>, <span class="monospaced">I</span>, or <span class="monospaced">R</span>, or
is an inline string, like <span class="monospaced">&grave;"foo"</span>.  A backtick (<span class="monospaced">&grave;</span>)
must precede each inline string.  Each <span class="monospaced">&lt;argi&gt;</span> must be of the
appropriate type for the corresponding specifier.</p></div>
<div class="paragraph"><p>SML <span class="monospaced">printf</span> is more powerful than its C counterpart in a number of
ways.  In particular, the function produced by <span class="monospaced">printf</span> is a perfectly
ordinary SML function, and can be passed around, used multiple times,
etc.  For example:</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span class="k">val</span><span class="w"> </span><span class="n">f</span><span class="p">:</span><span class="w"> </span><span class="n">int</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">bool</span><span class="w"> </span><span class="p">-&gt;</span><span class="w"> </span><span class="n">unit</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">printf</span><span class="w"> </span><span class="n">`</span><span class="s">&quot;Int=&quot;</span><span class="n">I`</span><span class="s">&quot;  Bool=&quot;</span><span class="n">B`</span><span class="s">&quot;</span><span class="se">\n</span><span class="s">&quot;</span><span class="w"> </span><span class="n">$</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">true</span><span class="w"></span>
<span class="k">val</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">false</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>The definition of <span class="monospaced">printf</span> is even careful to not print anything until
it is fully applied.  So, examples like the following will work as
expected.</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>val f: int -&gt; bool -&gt; unit = printf `"Int="I`"  Bool="B`"\n" $ 13
val () = f true
val () = f false</pre>
</div></div>
<div class="paragraph"><p>It is also easy to define new format specifiers.  For example, suppose
we wanted format specifiers for characters and strings.</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>val C = fn z =&gt; spec Char.toString z
val S = fn z =&gt; spec (fn s =&gt; s) z</pre>
</div></div>
<div class="paragraph"><p>One can define format specifiers for more complex types, e.g. pairs of
integers.</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>val I2 =
   fn z =&gt;
   spec (fn (i, j) =&gt;
         concat ["(", Int.toString i, ", ", Int.toString j, ")"])
   z</pre>
</div></div>
<div class="paragraph"><p>Here&#8217;s an example use.</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>val () = printf `"Test "I2`"  a string "S`"\n" $ (1, 2) "hello"</pre>
</div></div>
</div>
</div>
<div class="sect1">
<h2 id="_printf_via_a_href_fold_fold_a">Printf via <a href="Fold">Fold</a></h2>
<div class="sectionbody">
<div class="paragraph"><p><span class="monospaced">printf</span> is best viewed as a special case of variable-argument
<a href="Fold">Fold</a> that inductively builds a function as it processes its
arguments.  Here is the definition of a <span class="monospaced">Printf</span> structure in terms of
fold.  The structure is equivalent to the above one, except that it
uses the standard <span class="monospaced">$</span> instead of a specialized one.</p></div>
<div class="listingblock">
<div class="content"><div class="highlight"><pre><span class="k">structure</span><span class="w"> </span><span class="n">Printf</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">   </span><span class="k">struct</span><span class="w"></span>
<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">fprintf</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">         </span><span class="n">Fold</span><span class="p">.</span><span class="n">fold</span><span class="w"> </span><span class="p">((</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="n">id</span><span class="p">),</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="p">(_,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">())</span><span class="w"> </span><span class="n">ignore</span><span class="p">)</span><span class="w"></span>

<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">printf</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">fprintf</span><span class="w"> </span><span class="n">TextIO</span><span class="p">.</span><span class="n">stdOut</span><span class="w"> </span><span class="n">z</span><span class="w"></span>

<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="p">((</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">),</span><span class="w"> </span><span class="n">make</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">         </span><span class="p">(</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">          </span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">             </span><span class="n">make</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"></span>
<span class="w">                   </span><span class="n">r</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">p</span><span class="w"> </span><span class="p">();</span><span class="w"> </span><span class="n">TextIO</span><span class="p">.</span><span class="n">output</span><span class="w"> </span><span class="p">(</span><span class="n">out</span><span class="p">,</span><span class="w"> </span><span class="n">s</span><span class="p">))))))</span><span class="w"></span>

<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">`</span><span class="w"> </span><span class="p">=</span><span class="w"></span>
<span class="w">         </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">Fold</span><span class="p">.</span><span class="n">step1</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">s</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">s</span><span class="p">))</span><span class="w"> </span><span class="n">z</span><span class="w"></span>

<span class="w">      </span><span class="k">fun</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">Fold</span><span class="p">.</span><span class="n">step0</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">one</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">to</span><span class="p">))</span><span class="w"></span>

<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">B</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">Bool</span><span class="p">.</span><span class="n">toString</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">Int</span><span class="p">.</span><span class="n">toString</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
<span class="w">      </span><span class="k">val</span><span class="w"> </span><span class="n">R</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="n">z</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">spec</span><span class="w"> </span><span class="n">Real</span><span class="p">.</span><span class="n">toString</span><span class="w"> </span><span class="n">z</span><span class="w"></span>
<span class="w">   </span><span class="k">end</span><span class="w"></span>
</pre></div></div></div>
<div class="paragraph"><p>Viewing <span class="monospaced">printf</span> as a fold opens up a number of possibilities.  For
example, one can name parts of format strings using the fold idiom for
naming sequences of steps.</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>val IB = fn u =&gt; Fold.fold u `"Int="I`" Bool="B
val () = printf IB`"  "IB`"\n" $ 1 true 3 false</pre>
</div></div>
<div class="paragraph"><p>One can even parametrize over partial format strings.</p></div>
<div class="listingblock">
<div class="content monospaced">
<pre>fun XB X = fn u =&gt; Fold.fold u `"X="X`" Bool="B
val () = printf (XB I)`"  "(XB R)`"\n" $ 1 true 2.0 false</pre>
</div></div>
</div>
</div>
<div class="sect1">
<h2 id="_also_see">Also see</h2>
<div class="sectionbody">
<div class="ulist"><ul>
<li>
<p>
<a href="PrintfGentle">PrintfGentle</a>
</p>
</li>
<li>
<p>
<a href="References#Danvy98"> Functional Unparsing</a>
</p>
</li>
</ul></div>
</div>
</div>
</div>
<div id="footnotes"><hr></div>
<div id="footer">
<div id="footer-text">
</div>
<div id="footer-badges">
</div>
</div>
</body>
</html>