Import Upstream version 20180207
[hcoop/debian/mlton.git] / doc / guide / localhost / Printf
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <meta name="generator" content="AsciiDoc 8.6.9">
6 <title>Printf</title>
7 <link rel="stylesheet" href="./asciidoc.css" type="text/css">
8 <link rel="stylesheet" href="./pygments.css" type="text/css">
9
10
11 <script type="text/javascript" src="./asciidoc.js"></script>
12 <script type="text/javascript">
13 /*<![CDATA[*/
14 asciidoc.install();
15 /*]]>*/
16 </script>
17 <link rel="stylesheet" href="./mlton.css" type="text/css">
18 </head>
19 <body class="article">
20 <div id="banner">
21 <div id="banner-home">
22 <a href="./Home">MLton 20180207</a>
23 </div>
24 </div>
25 <div id="header">
26 <h1>Printf</h1>
27 </div>
28 <div id="content">
29 <div id="preamble">
30 <div class="sectionbody">
31 <div class="paragraph"><p>Programmers coming from C or Java often ask if
32 <a href="StandardML">Standard ML</a> has a <span class="monospaced">printf</span> function. It does not.
33 However, it is possible to implement your own version with only a few
34 lines of code.</p></div>
35 <div class="paragraph"><p>Here is a definition for <span class="monospaced">printf</span> and <span class="monospaced">fprintf</span>, along with format
36 specifiers for booleans, integers, and reals.</p></div>
37 <div class="listingblock">
38 <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>
39 <span class="w"> </span><span class="k">struct</span><span class="w"></span>
40 <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>
41 <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>
42 <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>
43 <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>
44 <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>
45 <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>
46 <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>
47 <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>
48 <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>
49 <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>
50 <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>
51 <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>
52 <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>
53 <span class="w"> </span><span class="k">end</span><span class="w"></span>
54 </pre></div></div></div>
55 <div class="paragraph"><p>Here&#8217;s an example use.</p></div>
56 <div class="listingblock">
57 <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>
58 </pre></div></div></div>
59 <div class="paragraph"><p>This prints the following.</p></div>
60 <div class="listingblock">
61 <div class="content monospaced">
62 <pre>Int=1 Bool=false Real=2.0</pre>
63 </div></div>
64 <div class="paragraph"><p>In general, a use of <span class="monospaced">printf</span> looks like</p></div>
65 <div class="listingblock">
66 <div class="content monospaced">
67 <pre>printf &lt;spec1&gt; ... &lt;specn&gt; $ &lt;arg1&gt; ... &lt;argm&gt;</pre>
68 </div></div>
69 <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
70 is an inline string, like <span class="monospaced">&grave;"foo"</span>. A backtick (<span class="monospaced">&grave;</span>)
71 must precede each inline string. Each <span class="monospaced">&lt;argi&gt;</span> must be of the
72 appropriate type for the corresponding specifier.</p></div>
73 <div class="paragraph"><p>SML <span class="monospaced">printf</span> is more powerful than its C counterpart in a number of
74 ways. In particular, the function produced by <span class="monospaced">printf</span> is a perfectly
75 ordinary SML function, and can be passed around, used multiple times,
76 etc. For example:</p></div>
77 <div class="listingblock">
78 <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>
79 <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>
80 <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>
81 </pre></div></div></div>
82 <div class="paragraph"><p>The definition of <span class="monospaced">printf</span> is even careful to not print anything until
83 it is fully applied. So, examples like the following will work as
84 expected.</p></div>
85 <div class="listingblock">
86 <div class="content monospaced">
87 <pre>val f: int -&gt; bool -&gt; unit = printf `"Int="I`" Bool="B`"\n" $ 13
88 val () = f true
89 val () = f false</pre>
90 </div></div>
91 <div class="paragraph"><p>It is also easy to define new format specifiers. For example, suppose
92 we wanted format specifiers for characters and strings.</p></div>
93 <div class="listingblock">
94 <div class="content monospaced">
95 <pre>val C = fn z =&gt; spec Char.toString z
96 val S = fn z =&gt; spec (fn s =&gt; s) z</pre>
97 </div></div>
98 <div class="paragraph"><p>One can define format specifiers for more complex types, e.g. pairs of
99 integers.</p></div>
100 <div class="listingblock">
101 <div class="content monospaced">
102 <pre>val I2 =
103 fn z =&gt;
104 spec (fn (i, j) =&gt;
105 concat ["(", Int.toString i, ", ", Int.toString j, ")"])
106 z</pre>
107 </div></div>
108 <div class="paragraph"><p>Here&#8217;s an example use.</p></div>
109 <div class="listingblock">
110 <div class="content monospaced">
111 <pre>val () = printf `"Test "I2`" a string "S`"\n" $ (1, 2) "hello"</pre>
112 </div></div>
113 </div>
114 </div>
115 <div class="sect1">
116 <h2 id="_printf_via_a_href_fold_fold_a">Printf via <a href="Fold">Fold</a></h2>
117 <div class="sectionbody">
118 <div class="paragraph"><p><span class="monospaced">printf</span> is best viewed as a special case of variable-argument
119 <a href="Fold">Fold</a> that inductively builds a function as it processes its
120 arguments. Here is the definition of a <span class="monospaced">Printf</span> structure in terms of
121 fold. The structure is equivalent to the above one, except that it
122 uses the standard <span class="monospaced">$</span> instead of a specialized one.</p></div>
123 <div class="listingblock">
124 <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>
125 <span class="w"> </span><span class="k">struct</span><span class="w"></span>
126 <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>
127 <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>
128
129 <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>
130
131 <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>
132 <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>
133 <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>
134 <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>
135 <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>
136
137 <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>
138 <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>
139
140 <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>
141
142 <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>
143 <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>
144 <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>
145 <span class="w"> </span><span class="k">end</span><span class="w"></span>
146 </pre></div></div></div>
147 <div class="paragraph"><p>Viewing <span class="monospaced">printf</span> as a fold opens up a number of possibilities. For
148 example, one can name parts of format strings using the fold idiom for
149 naming sequences of steps.</p></div>
150 <div class="listingblock">
151 <div class="content monospaced">
152 <pre>val IB = fn u =&gt; Fold.fold u `"Int="I`" Bool="B
153 val () = printf IB`" "IB`"\n" $ 1 true 3 false</pre>
154 </div></div>
155 <div class="paragraph"><p>One can even parametrize over partial format strings.</p></div>
156 <div class="listingblock">
157 <div class="content monospaced">
158 <pre>fun XB X = fn u =&gt; Fold.fold u `"X="X`" Bool="B
159 val () = printf (XB I)`" "(XB R)`"\n" $ 1 true 2.0 false</pre>
160 </div></div>
161 </div>
162 </div>
163 <div class="sect1">
164 <h2 id="_also_see">Also see</h2>
165 <div class="sectionbody">
166 <div class="ulist"><ul>
167 <li>
168 <p>
169 <a href="PrintfGentle">PrintfGentle</a>
170 </p>
171 </li>
172 <li>
173 <p>
174 <a href="References#Danvy98"> Functional Unparsing</a>
175 </p>
176 </li>
177 </ul></div>
178 </div>
179 </div>
180 </div>
181 <div id="footnotes"><hr></div>
182 <div id="footer">
183 <div id="footer-text">
184 </div>
185 <div id="footer-badges">
186 </div>
187 </div>
188 </body>
189 </html>