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