Import Upstream version 20180207
[hcoop/debian/mlton.git] / doc / guide / localhost / InfixingOperators
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>InfixingOperators</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>InfixingOperators</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>Fixity specifications are not part of signatures in\r
32<a href="StandardML">Standard ML</a>. When one wants to use a module that\r
33provides functions designed to be used as infix operators there are\r
34several obvious alternatives:</p></div>\r
35<div class="ulist"><ul>\r
36<li>\r
37<p>\r
38Use only prefix applications. Unfortunately there are situations\r
39where infix applications lead to considerably more readable code.\r
40</p>\r
41</li>\r
42<li>\r
43<p>\r
44Make the fixity declarations at the top-level. This may lead to\r
45collisions and may be unsustainable in a large project. Pollution of\r
46the top-level should be avoided.\r
47</p>\r
48</li>\r
49<li>\r
50<p>\r
51Make the fixity declarations at each scope where you want to use\r
52infix applications. The duplication becomes inconvenient if the\r
53operators are widely used. Duplication of code should be avoided.\r
54</p>\r
55</li>\r
56<li>\r
57<p>\r
58Use non-standard extensions, such as the <a href="MLBasis"> ML Basis system</a>\r
59to control the scope of fixity declarations. This has the obvious\r
60drawback of reduced portability.\r
61</p>\r
62</li>\r
63<li>\r
64<p>\r
65Reuse existing infix operator symbols (<span class="monospaced">^</span>, <span class="monospaced">+</span>, <span class="monospaced">-</span>, &#8230;). This\r
66can be convenient when the standard operators aren&#8217;t needed in the\r
67same scope with the new operators. On the other hand, one is limited\r
68to the standard operator symbols and the code may appear confusing.\r
69</p>\r
70</li>\r
71</ul></div>\r
72<div class="paragraph"><p>None of the obvious alternatives is best in every case. The following\r
73describes a slightly less obvious alternative that can sometimes be\r
74useful. The idea is to approximate Haskell&#8217;s special syntax for\r
75treating any identifier enclosed in grave accents (backquotes) as an\r
76infix operator. In Haskell, instead of writing the prefix application\r
77<span class="monospaced">f x y</span> one can write the infix application <span class="monospaced">x &grave;f&grave; y</span>.</p></div>\r
78</div>\r
79</div>\r
80<div class="sect1">\r
81<h2 id="_infixing_operators">Infixing operators</h2>\r
82<div class="sectionbody">\r
83<div class="paragraph"><p>Let&#8217;s first take a look at the definitions of the operators:</p></div>\r
84<div class="listingblock">\r
85<div class="content"><div class="highlight"><pre><span class="k">infix</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="n">&lt;\</span><span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">&lt;\</span><span class="w"> </span><span class="n">f</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">y</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="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="cm">(* Left section *)</span><span class="w"></span>\r
86<span class="k">infix</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="n">\&gt;</span><span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">\&gt;</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="cm">(* Left application *)</span><span class="w"></span>\r
87<span class="k">infixr</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="n">/&gt;</span><span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">/&gt;</span><span class="w"> </span><span class="n">y</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">x</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="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="cm">(* Right section *)</span><span class="w"></span>\r
88<span class="k">infixr</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="n">&lt;/</span><span class="w"> </span><span class="k">fun</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">&lt;/</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="n">x</span><span class="w"> </span><span class="cm">(* Right application *)</span><span class="w"></span>\r
89\r
90<span class="k">infix</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="cm">(* See motivation below *)</span><span class="w"></span>\r
91<span class="k">infix</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">:=</span><span class="w"></span>\r
92</pre></div></div></div>\r
93<div class="paragraph"><p>The left and right sectioning operators, <span class="monospaced">&lt;\</span> and <span class="monospaced">/&gt;</span>, are useful in\r
94SML for partial application of infix operators.\r
95<a href="References#Paulson96"> ML For the Working Programmer</a> describes curried\r
96functions <span class="monospaced">secl</span> and <span class="monospaced">secr</span> for the same purpose on pages 179-181.\r
97For example,</p></div>\r
98<div class="listingblock">\r
99<div class="content"><div class="highlight"><pre><span class="n">List</span><span class="p">.</span><span class="n">map</span><span class="w"> </span><span class="p">(</span><span class="k">op</span><span class="n">-</span><span class="w"> </span><span class="n">/&gt;</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"></span>\r
100</pre></div></div></div>\r
101<div class="paragraph"><p>is a function for subtracting <span class="monospaced">y</span> from a list of integers and</p></div>\r
102<div class="listingblock">\r
103<div class="content"><div class="highlight"><pre><span class="n">List</span><span class="p">.</span><span class="n">exists</span><span class="w"> </span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="n">&lt;\</span><span class="w"> </span><span class="k">op</span><span class="p">=)</span><span class="w"></span>\r
104</pre></div></div></div>\r
105<div class="paragraph"><p>is a function for testing whether a list contains an <span class="monospaced">x</span>.</p></div>\r
106<div class="paragraph"><p>Together with the left and right application operators, <span class="monospaced">\&gt;</span> and <span class="monospaced">&lt;/</span>,\r
107the sectioning operators provide a way to treat any binary function\r
108(i.e. a function whose domain is a pair) as an infix operator. In\r
109general,</p></div>\r
110<div class="listingblock">\r
111<div class="content monospaced">\r
112<pre>x0 &lt;\f1\&gt; x1 &lt;\f2\&gt; x2 ... &lt;\fN\&gt; xN = fN (... f2 (f1 (x0, x1), x2) ..., xN)</pre>\r
113</div></div>\r
114<div class="paragraph"><p>and</p></div>\r
115<div class="listingblock">\r
116<div class="content monospaced">\r
117<pre>xN &lt;/fN/&gt; ... x2 &lt;/f2/&gt; x1 &lt;/f1/&gt; x0 = fN (xN, ... f2 (x2, f1 (x1, x0)) ...)</pre>\r
118</div></div>\r
119<div class="sect2">\r
120<h3 id="_examples">Examples</h3>\r
121<div class="paragraph"><p>As a fairly realistic example, consider providing a function for sequencing\r
122comparisons:</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">Order</span><span class="w"> </span><span class="cm">(* ... *)</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="cm">(* ... *)</span><span class="w"></span>\r
127<span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="n">orWhenEq</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">fn</span><span class="w"> </span><span class="p">(</span><span class="n">EQUAL</span><span class="p">,</span><span class="w"> </span><span class="n">th</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">th</span><span class="w"> </span><span class="p">()</span><span class="w"></span>\r
128<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">(</span><span class="n">other</span><span class="p">,</span><span class="w"> </span><span class="p">_)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="n">other</span><span class="w"></span>\r
129<span class="w"> </span><span class="cm">(* ... *)</span><span class="w"></span>\r
130<span class="w"> </span><span class="k">end</span><span class="w"></span>\r
131</pre></div></div></div>\r
132<div class="paragraph"><p>Using <span class="monospaced">orWhenEq</span> and the infixing operators, one can write a\r
133<span class="monospaced">compare</span> function for triples as</p></div>\r
134<div class="listingblock">\r
135<div class="content"><div class="highlight"><pre><span class="k">fun</span><span class="w"> </span><span class="n">compare</span><span class="w"> </span><span class="p">(</span><span class="n">fad</span><span class="p">,</span><span class="w"> </span><span class="n">fbe</span><span class="p">,</span><span class="w"> </span><span class="n">fcf</span><span class="p">)</span><span class="w"> </span><span class="p">((</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">c</span><span class="p">),</span><span class="w"> </span><span class="p">(</span><span class="n">d</span><span class="p">,</span><span class="w"> </span><span class="n">e</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>\r
136<span class="w"> </span><span class="n">fad</span><span class="w"> </span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">d</span><span class="p">)</span><span class="w"> </span><span class="n">&lt;\Order</span><span class="p">.</span><span class="n">orWhenEq\&gt;</span><span class="w"> </span><span class="n">`fbe</span><span class="w"> </span><span class="p">(</span><span class="n">b</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="n">&lt;\Order</span><span class="p">.</span><span class="n">orWhenEq\&gt;</span><span class="w"> </span><span class="n">`fcf</span><span class="w"> </span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w"></span>\r
137</pre></div></div></div>\r
138<div class="paragraph"><p>where <span class="monospaced">&grave;</span> is defined as</p></div>\r
139<div class="listingblock">\r
140<div class="content"><div class="highlight"><pre><span class="k">fun</span><span class="w"> </span><span class="n">`f</span><span class="w"> </span><span class="n">x</span><span class="w"> </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="p">=&gt;</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">x</span><span class="w"></span>\r
141</pre></div></div></div>\r
142<div class="paragraph"><p>Although <span class="monospaced">orWhenEq</span> can be convenient (try rewriting the above without\r
143it), it is probably not useful enough to be defined at the top level\r
144as an infix operator. Fortunately we can use the infixing operators\r
145and don&#8217;t have to.</p></div>\r
146<div class="paragraph"><p>Another fairly realistic example would be to use the infixing operators with\r
147the technique described on the <a href="Printf">Printf</a> page. Assuming that you would have\r
148a <span class="monospaced">Printf</span> module binding <span class="monospaced">printf</span>, <span class="monospaced">&grave;</span>, and formatting combinators\r
149named <span class="monospaced">int</span> and <span class="monospaced">string</span>, you could write</p></div>\r
150<div class="listingblock">\r
151<div class="content"><div class="highlight"><pre><span class="k">let</span><span class="w"> </span><span class="k">open</span><span class="w"> </span><span class="n">Printf</span><span class="w"> </span><span class="k">in</span><span class="w"></span>\r
152<span class="w"> </span><span class="n">printf</span><span class="w"> </span><span class="p">(</span><span class="n">`</span><span class="s">&quot;Here&#39;s an int &quot;</span><span class="n">&lt;\int\&gt;</span><span class="s">&quot; and a string &quot;</span><span class="n">&lt;\string\&gt;</span><span class="s">&quot;.&quot;</span><span class="p">)</span><span class="w"> </span><span class="mi">13</span><span class="w"> </span><span class="s">&quot;foo&quot;</span><span class="w"> </span><span class="k">end</span><span class="w"></span>\r
153</pre></div></div></div>\r
154<div class="paragraph"><p>without having to duplicate the fixity declarations. Alternatively, you could\r
155write</p></div>\r
156<div class="listingblock">\r
157<div class="content"><div class="highlight"><pre><span class="n">P</span><span class="p">.</span><span class="n">printf</span><span class="w"> </span><span class="p">(</span><span class="n">P</span><span class="p">.</span><span class="n">`</span><span class="s">&quot;Here&#39;s an int &quot;</span><span class="n">&lt;\P</span><span class="p">.</span><span class="n">int\&gt;</span><span class="s">&quot; and a string &quot;</span><span class="n">&lt;\P</span><span class="p">.</span><span class="n">string\&gt;</span><span class="s">&quot;.&quot;</span><span class="p">)</span><span class="w"> </span><span class="mi">13</span><span class="w"> </span><span class="s">&quot;foo&quot;</span><span class="w"></span>\r
158</pre></div></div></div>\r
159<div class="paragraph"><p>assuming you have the made the binding</p></div>\r
160<div class="listingblock">\r
161<div class="content"><div class="highlight"><pre><span class="k">structure</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">Printf</span><span class="w"></span>\r
162</pre></div></div></div>\r
163</div>\r
164</div>\r
165</div>\r
166<div class="sect1">\r
167<h2 id="_application_and_piping_operators">Application and piping operators</h2>\r
168<div class="sectionbody">\r
169<div class="paragraph"><p>The left and right application operators may also provide some notational\r
170convenience on their own. In general,</p></div>\r
171<div class="listingblock">\r
172<div class="content monospaced">\r
173<pre>f \&gt; x1 \&gt; ... \&gt; xN = f x1 ... xN</pre>\r
174</div></div>\r
175<div class="paragraph"><p>and</p></div>\r
176<div class="listingblock">\r
177<div class="content monospaced">\r
178<pre>xN &lt;/ ... &lt;/ x1 &lt;/ f = f x1 ... xN</pre>\r
179</div></div>\r
180<div class="paragraph"><p>If nothing else, both of them can eliminate parentheses. For example,</p></div>\r
181<div class="listingblock">\r
182<div class="content"><div class="highlight"><pre><span class="n">foo</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="w"> </span><span class="n">+</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="n">foo</span><span class="w"> </span><span class="n">\&gt;</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">+</span><span class="w"> </span><span class="mi">2</span><span class="w"></span>\r
183</pre></div></div></div>\r
184<div class="paragraph"><p>The left and right application operators are related to operators\r
185that could be described as the right and left piping operators:</p></div>\r
186<div class="listingblock">\r
187<div class="content"><div class="highlight"><pre><span class="k">infix</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">&gt;|</span><span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="k">op</span><span class="n">&gt;|</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">op</span><span class="n">&lt;/</span><span class="w"> </span><span class="cm">(* Left pipe *)</span><span class="w"></span>\r
188<span class="k">infixr</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">|&lt;</span><span class="w"> </span><span class="k">val</span><span class="w"> </span><span class="k">op</span><span class="n">|&lt;</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="k">op</span><span class="n">\&gt;</span><span class="w"> </span><span class="cm">(* Right pipe *)</span><span class="w"></span>\r
189</pre></div></div></div>\r
190<div class="paragraph"><p>As you can see, the left and right piping operators, <span class="monospaced">&gt;|</span> and <span class="monospaced">|&lt;</span>,\r
191are the same as the right and left application operators,\r
192respectively, except the associativities are reversed and the binding\r
193strength is lower. They are useful for piping data through a sequence\r
194of operations. In general,</p></div>\r
195<div class="listingblock">\r
196<div class="content monospaced">\r
197<pre>x &gt;| f1 &gt;| ... &gt;| fN = fN (... (f1 x) ...) = (fN o ... o f1) x</pre>\r
198</div></div>\r
199<div class="paragraph"><p>and</p></div>\r
200<div class="listingblock">\r
201<div class="content monospaced">\r
202<pre>fN |&lt; ... |&lt; f1 |&lt; x = fN (... (f1 x) ...) = (fN o ... o f1) x</pre>\r
203</div></div>\r
204<div class="paragraph"><p>The right piping operator, <span class="monospaced">|&lt;</span>, is provided by the Haskell prelude as\r
205<span class="monospaced">$</span>. It can be convenient in CPS or continuation passing style.</p></div>\r
206<div class="paragraph"><p>A use for the left piping operator is with parsing combinators. In a\r
207strict language, like SML, eta-reduction is generally unsafe. Using\r
208the left piping operator, parsing functions can be formatted\r
209conveniently as</p></div>\r
210<div class="listingblock">\r
211<div class="content"><div class="highlight"><pre><span class="k">fun</span><span class="w"> </span><span class="n">parsingFunc</span><span class="w"> </span><span class="n">input</span><span class="w"> </span><span class="p">=</span><span class="w"></span>\r
212<span class="w"> </span><span class="n">input</span><span class="w"> </span><span class="n">&gt;|</span><span class="w"> </span><span class="cm">(* ... *)</span><span class="w"></span>\r
213<span class="w"> </span><span class="n">||</span><span class="w"> </span><span class="cm">(* ... *)</span><span class="w"></span>\r
214<span class="w"> </span><span class="n">||</span><span class="w"> </span><span class="cm">(* ... *)</span><span class="w"></span>\r
215</pre></div></div></div>\r
216<div class="paragraph"><p>where <span class="monospaced">||</span> is supposed to be a combinator provided by the parsing combinator\r
217library.</p></div>\r
218</div>\r
219</div>\r
220<div class="sect1">\r
221<h2 id="_about_precedences">About precedences</h2>\r
222<div class="sectionbody">\r
223<div class="paragraph"><p>You probably noticed that we redefined the\r
224<a href="OperatorPrecedence">precedences</a> of the function composition operator\r
225<span class="monospaced">o</span> and the assignment operator <span class="monospaced">:=</span>. Doing so is not strictly\r
226necessary, but can be convenient and should be relatively\r
227safe. Consider the following motivating examples from\r
228<a href="WesleyTerpstra"> Wesley W. Terpstra</a> relying on the redefined\r
229precedences:</p></div>\r
230<div class="listingblock">\r
231<div class="content"><div class="highlight"><pre><span class="n">Word8</span><span class="p">.</span><span class="n">fromInt</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">Char</span><span class="p">.</span><span class="n">ord</span><span class="w"> </span><span class="n">o</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="n">&lt;\String</span><span class="p">.</span><span class="n">sub</span><span class="w"></span>\r
232<span class="cm">(* Combining sectioning and composition *)</span><span class="w"></span>\r
233\r
234<span class="n">x</span><span class="w"> </span><span class="n">:=</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="n">&lt;\String</span><span class="p">.</span><span class="n">sub\&gt;</span><span class="w"> </span><span class="n">i</span><span class="w"></span>\r
235<span class="cm">(* Assigning the result of an infixed application *)</span><span class="w"></span>\r
236</pre></div></div></div>\r
237<div class="paragraph"><p>In imperative languages, assignment usually has the lowest precedence\r
238(ignoring statement separators). The precedence of <span class="monospaced">:=</span> in the\r
239<a href="BasisLibrary"> Basis Library</a> is perhaps unnecessarily high, because\r
240an expression of the form <span class="monospaced">r := x</span> always returns a unit, which makes\r
241little sense to combine with anything. Dropping <span class="monospaced">:=</span> to the lowest\r
242precedence level makes it behave more like in other imperative\r
243languages.</p></div>\r
244<div class="paragraph"><p>The case for <span class="monospaced">o</span> is different. With the exception of <span class="monospaced">before</span> and\r
245<span class="monospaced">:=</span>, it doesn&#8217;t seem to make much sense to use <span class="monospaced">o</span> with any of the\r
246operators defined by the <a href="BasisLibrary"> Basis Library</a> in an\r
247unparenthesized expression. This is simply because none of the other\r
248operators deal with functions. It would seem that the precedence of\r
249<span class="monospaced">o</span> could be chosen completely arbitrarily from the set <span class="monospaced">{1, ..., 9}</span>\r
250without having any adverse effects with respect to other infix\r
251operators defined by the <a href="BasisLibrary"> Basis Library</a>.</p></div>\r
252</div>\r
253</div>\r
254<div class="sect1">\r
255<h2 id="_design_of_the_symbols">Design of the symbols</h2>\r
256<div class="sectionbody">\r
257<div class="paragraph"><p>The closest approximation of Haskell&#8217;s <span class="monospaced">x &grave;f&grave; y</span> syntax\r
258achievable in Standard ML would probably be something like\r
259<span class="monospaced">x &grave;f^ y</span>, but <span class="monospaced">^</span> is already used for string\r
260concatenation by the <a href="BasisLibrary"> Basis Library</a>. Other\r
261combinations of the characters <span class="monospaced">&grave;</span> and <span class="monospaced">^</span> would be\r
262possible, but none seems clearly the best visually. The symbols <span class="monospaced">&lt;\</span>,\r
263<span class="monospaced">\&gt;</span>, <span class="monospaced">&lt;/</span>, and <span class="monospaced">/&gt;</span> are reasonably concise and have a certain\r
264self-documenting appearance and symmetry, which can help to remember\r
265them. As the names suggest, the symbols of the piping operators <span class="monospaced">&gt;|</span>\r
266and <span class="monospaced">|&lt;</span> are inspired by Unix shell pipelines.</p></div>\r
267</div>\r
268</div>\r
269<div class="sect1">\r
270<h2 id="_also_see">Also see</h2>\r
271<div class="sectionbody">\r
272<div class="ulist"><ul>\r
273<li>\r
274<p>\r
275<a href="Utilities">Utilities</a>\r
276</p>\r
277</li>\r
278</ul></div>\r
279</div>\r
280</div>\r
281</div>\r
282<div id="footnotes"><hr></div>\r
283<div id="footer">\r
284<div id="footer-text">\r
285</div>\r
286<div id="footer-badges">\r
287</div>\r
288</div>\r
289</body>\r
290</html>\r