This file is indexed.

/usr/share/doc/libghc-pipes-parse-doc/html/src/Pipes-Parse-Tutorial.html is in libghc-pipes-parse-doc 3.0.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<!-- Generated by HsColour, http://code.haskell.org/~malcolm/hscolour/ -->
<title>src/Pipes/Parse/Tutorial.hs</title>
<link type='text/css' rel='stylesheet' href='hscolour.css' />
</head>
<body>
<pre><a name="line-1"></a><span class='hs-comment'>{-# OPTIONS_GHC -fno-warn-unused-imports #-}</span>
<a name="line-2"></a>
<a name="line-3"></a><span class='hs-comment'>{-| @pipes-parse@ builds upon @pipes@ to add several missing features necessary
<a name="line-4"></a>    to implement 'Parser's:
<a name="line-5"></a>
<a name="line-6"></a>    * End-of-input detection, so that 'Parser's can react to an exhausted input
<a name="line-7"></a>      stream
<a name="line-8"></a>
<a name="line-9"></a>    * Leftovers support, which simplifies several parsing problems
<a name="line-10"></a>
<a name="line-11"></a>    * Connect-and-resume, to connect a 'Producer' to a 'Parser' and retrieve
<a name="line-12"></a>      unused input
<a name="line-13"></a>-}</span>
<a name="line-14"></a>
<a name="line-15"></a><span class='hs-keyword'>module</span> <span class='hs-conid'>Pipes</span><span class='hs-varop'>.</span><span class='hs-conid'>Parse</span><span class='hs-varop'>.</span><span class='hs-conid'>Tutorial</span> <span class='hs-layout'>(</span>
<a name="line-16"></a>    <span class='hs-comment'>-- * Overview</span>
<a name="line-17"></a>    <span class='hs-comment'>-- $overview</span>
<a name="line-18"></a>
<a name="line-19"></a>    <span class='hs-comment'>-- * Parsers</span>
<a name="line-20"></a>    <span class='hs-comment'>-- $parsers</span>
<a name="line-21"></a>
<a name="line-22"></a>    <span class='hs-comment'>-- * Lenses</span>
<a name="line-23"></a>    <span class='hs-comment'>-- $lenses</span>
<a name="line-24"></a>
<a name="line-25"></a>    <span class='hs-comment'>-- * Getters</span>
<a name="line-26"></a>    <span class='hs-comment'>-- $getters</span>
<a name="line-27"></a>
<a name="line-28"></a>    <span class='hs-comment'>-- * Building Lenses</span>
<a name="line-29"></a>    <span class='hs-comment'>-- $buildlenses</span>
<a name="line-30"></a>
<a name="line-31"></a>    <span class='hs-comment'>-- * Conclusion</span>
<a name="line-32"></a>    <span class='hs-comment'>-- $conclusion</span>
<a name="line-33"></a>    <span class='hs-layout'>)</span> <span class='hs-keyword'>where</span>
<a name="line-34"></a>
<a name="line-35"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Pipes</span>
<a name="line-36"></a><span class='hs-keyword'>import</span> <span class='hs-conid'>Pipes</span><span class='hs-varop'>.</span><span class='hs-conid'>Parse</span>
<a name="line-37"></a>
<a name="line-38"></a><span class='hs-comment'>{- $overview
<a name="line-39"></a>    @pipes-parse@ centers on three abstractions:
<a name="line-40"></a>
<a name="line-41"></a>    * 'Producer's, unchanged from @pipes@
<a name="line-42"></a>
<a name="line-43"></a>    * 'Parser's, which play a role analogous to 'Consumer's
<a name="line-44"></a>
<a name="line-45"></a>    * 'Lens.Family2.Lens''es between 'Producer's, which play a role analogous to
<a name="line-46"></a>      'Pipe's
<a name="line-47"></a>
<a name="line-48"></a>    There are four ways to connect these three abstractions:
<a name="line-49"></a>
<a name="line-50"></a>    * Connect 'Parser's to 'Producer's using 'runStateT' \/ 'evalStateT' \/
<a name="line-51"></a>      'execStateT':
<a name="line-52"></a>
<a name="line-53"></a>&gt; runStateT  :: Parser a m r -&gt; Producer a m x -&gt; m (r, Producer a m x)
<a name="line-54"></a>&gt; evalStateT :: Parser a m r -&gt; Producer a m x -&gt; m  r
<a name="line-55"></a>&gt; execStateT :: Parser a m r -&gt; Producer a m x -&gt; m (   Producer a m x)
<a name="line-56"></a>
<a name="line-57"></a>
<a name="line-58"></a>    * Connect 'Lens.Family2.Lens''es to 'Parser's using
<a name="line-59"></a>      'Lens.Family.State.Strict.zoom'
<a name="line-60"></a>
<a name="line-61"></a>&gt; zoom :: Lens' (Producer a m x) (Producer b m y)
<a name="line-62"></a>&gt;      -&gt; Parser b m r
<a name="line-63"></a>&gt;      -&gt; Parser a m r
<a name="line-64"></a>
<a name="line-65"></a>    * Connect 'Producer's to 'Lens.Family2.Lens''es using ('Lens.Family.^.') or
<a name="line-66"></a>      'Lens.Family.view':
<a name="line-67"></a>
<a name="line-68"></a>&gt; (^.) :: Producer a m x
<a name="line-69"></a>&gt;      -&gt; Lens' (Producer a m x) (Producer b m y)
<a name="line-70"></a>&gt;      -&gt; Producer b m y
<a name="line-71"></a>
<a name="line-72"></a>    * Connect 'Lens.Family2.Lens''es to 'Lens.Family2.Lens''es using ('.') (i.e.
<a name="line-73"></a>      function composition):
<a name="line-74"></a>
<a name="line-75"></a>&gt; (.) :: Lens' (Producer a m x) (Producer b m y)
<a name="line-76"></a>&gt;     -&gt; Lens' (Producer b m y) (Producer c m z)
<a name="line-77"></a>&gt;     -&gt; Lens' (Producer a m x) (Producer c m z)
<a name="line-78"></a>
<a name="line-79"></a>    You can obtain the necessary lens utilities from either:
<a name="line-80"></a>    
<a name="line-81"></a>    * The @lens-family-core@ library, importing @Lens.Family@ (for
<a name="line-82"></a>      ('Lens.Family.^.') \/ 'Lens.Family.view' and 'Lens.Family.over') and
<a name="line-83"></a>      @Lens.Family.State.Strict@ (for 'Lens.Family.State.Strict.zoom'), or:
<a name="line-84"></a>
<a name="line-85"></a>    * The @lens@ library, importing @Control.Lens@ (for ('Control.Lens.^.') \/
<a name="line-86"></a>      'Control.Lens.view', 'Control.Lens.over' and 'Control.Lens.zoom')
<a name="line-87"></a>
<a name="line-88"></a>    This tutorial uses @Lens.Family@ since it has fewer dependencies and simpler
<a name="line-89"></a>    types.
<a name="line-90"></a>-}</span>
<a name="line-91"></a>
<a name="line-92"></a><span class='hs-comment'>{- $parsers
<a name="line-93"></a>    'Parser's handle end-of-input and pushback by storing a 'Producer' in a
<a name="line-94"></a>    'StateT' layer:
<a name="line-95"></a>
<a name="line-96"></a>&gt; type Parser a m r = forall x . StateT (Producer a m x) m r
<a name="line-97"></a>
<a name="line-98"></a>    To draw a single element from the underlying 'Producer', use the 'draw'
<a name="line-99"></a>    command:
<a name="line-100"></a>
<a name="line-101"></a>&gt; draw :: Monad m =&gt; Parser a m (Maybe a)
<a name="line-102"></a>
<a name="line-103"></a>    'draw' returns the next element from the 'Producer' wrapped in 'Just' or
<a name="line-104"></a>    returns 'Nothing' if the underlying 'Producer' is empty.  Here's an example
<a name="line-105"></a>    'Parser' written using 'draw' that retrieves the first two elements from a
<a name="line-106"></a>    stream:
<a name="line-107"></a>
<a name="line-108"></a>&gt; import Pipes.Parse
<a name="line-109"></a>&gt;
<a name="line-110"></a>&gt; drawTwo :: Monad m =&gt; Parser a m (Maybe a, Maybe a)
<a name="line-111"></a>&gt; drawTwo = do
<a name="line-112"></a>&gt;     mx &lt;- draw
<a name="line-113"></a>&gt;     my &lt;- draw
<a name="line-114"></a>&gt;     return (mx, my)
<a name="line-115"></a>&gt;
<a name="line-116"></a>&gt; -- or: drawTwo = liftM2 (,) draw draw
<a name="line-117"></a>
<a name="line-118"></a>    Since a 'Parser' is just a 'StateT' action, you run a 'Parser' using the
<a name="line-119"></a>    same run functions as 'StateT':
<a name="line-120"></a>
<a name="line-121"></a>&gt; -- Feed a 'Producer' to a 'Parser', returning the result and leftovers
<a name="line-122"></a>&gt; runStateT  :: Parser a m r -&gt; Producer a m x -&gt; m (r, Producer a m x)
<a name="line-123"></a>&gt;
<a name="line-124"></a>&gt; -- Feed a 'Producer' to a 'Parser', returning only the result
<a name="line-125"></a>&gt; evalStateT :: Parser a m r -&gt; Producer a m x -&gt; m  r
<a name="line-126"></a>&gt;
<a name="line-127"></a>&gt; -- Feed a 'Producer' to a 'Parser', returning only the leftovers
<a name="line-128"></a>&gt; execStateT :: Parser a m r -&gt; Producer a m x -&gt; m (   Producer a m x)
<a name="line-129"></a>
<a name="line-130"></a>    All three of these functions require a 'Producer' which we feed to the
<a name="line-131"></a>    'Parser'.  For example, we can feed standard input:
<a name="line-132"></a>
<a name="line-133"></a>&gt;&gt;&gt; evalStateT drawTwo Pipes.Prelude.stdinLn
<a name="line-134"></a>Pink&lt;Enter&gt;
<a name="line-135"></a>Elephants&lt;Enter&gt;
<a name="line-136"></a>(Just "Pink",Just "Elephants")
<a name="line-137"></a>
<a name="line-138"></a>    The result is wrapped in a 'Maybe' because 'draw' can fail if the 'Producer'
<a name="line-139"></a>    is empty:
<a name="line-140"></a>
<a name="line-141"></a>&gt;&gt;&gt; evalStateT drawTwo (yield 0)
<a name="line-142"></a>(Just 0,Nothing)
<a name="line-143"></a>
<a name="line-144"></a>    Parsing might not necessarily consume the entire stream.  We can use
<a name="line-145"></a>    'runStateT' or 'execStateT' to retrieve unused elements that our parser does
<a name="line-146"></a>    not consume:
<a name="line-147"></a>
<a name="line-148"></a>&gt;&gt;&gt; import Pipes
<a name="line-149"></a>&gt;&gt;&gt; (result, unused) &lt;- runStateT drawTwo (each [1..4])
<a name="line-150"></a>&gt;&gt;&gt; -- View the parsed result
<a name="line-151"></a>&gt;&gt;&gt; result
<a name="line-152"></a>(Just 1,Just 2)
<a name="line-153"></a>&gt;&gt;&gt; -- Now print the leftovers
<a name="line-154"></a>&gt;&gt;&gt; runEffect $ for unused (lift . print)
<a name="line-155"></a>3
<a name="line-156"></a>4
<a name="line-157"></a>
<a name="line-158"></a>-}</span>
<a name="line-159"></a>
<a name="line-160"></a><span class='hs-comment'>{- $lenses
<a name="line-161"></a>    @pipes-parse@ also provides a convenience function for testing purposes that
<a name="line-162"></a>    draws all remaining elements and returns them as a list:
<a name="line-163"></a>
<a name="line-164"></a>&gt; drawAll :: Monad m =&gt; Parser a m [a]
<a name="line-165"></a>
<a name="line-166"></a>    For example:
<a name="line-167"></a>
<a name="line-168"></a>&gt;&gt;&gt; import Pipes
<a name="line-169"></a>&gt;&gt;&gt; import Pipes.Parse
<a name="line-170"></a>&gt;&gt;&gt; evalStateT drawAll (each [1..10])
<a name="line-171"></a>[1,2,3,4,5,6,7,8,9,10]
<a name="line-172"></a>
<a name="line-173"></a>    However, this function is not recommended in general because it loads the
<a name="line-174"></a>    entire input into memory, which defeats the purpose of streaming parsing.
<a name="line-175"></a>
<a name="line-176"></a>    You can instead use 'foldAll' if you wish to fold all input elements into a
<a name="line-177"></a>    single result:
<a name="line-178"></a>
<a name="line-179"></a>&gt;&gt;&gt; evalStateT (foldAll (+) 0 id) (each [1..10])
<a name="line-180"></a>55
<a name="line-181"></a>
<a name="line-182"></a>    You can also use the @foldl@ package to simplify writing more complex folds:
<a name="line-183"></a>
<a name="line-184"></a>&gt;&gt;&gt; import Control.Applicative
<a name="line-185"></a>&gt;&gt;&gt; import Control.Foldl as L
<a name="line-186"></a>&gt;&gt;&gt; evalStateT (purely foldAll (liftA2 (,) L.sum L.maximum)) (each [1..10])
<a name="line-187"></a>(55,Just 10)
<a name="line-188"></a>
<a name="line-189"></a>    But what if you wanted to draw or fold just the first three elements from
<a name="line-190"></a>    an infinite stream instead of the entire input?  This is what lenses are
<a name="line-191"></a>    for:
<a name="line-192"></a>
<a name="line-193"></a>&gt; import Lens.Family
<a name="line-194"></a>&gt; import Lens.Family.State.Strict
<a name="line-195"></a>&gt; import Pipes
<a name="line-196"></a>&gt; import Pipes.Parse
<a name="line-197"></a>&gt;
<a name="line-198"></a>&gt; import Prelude hiding (splitAt, span)
<a name="line-199"></a>&gt;
<a name="line-200"></a>&gt; drawThree :: Monad m =&gt; Parser a m [a]
<a name="line-201"></a>&gt; drawThree = zoom (splitAt 3) drawAll
<a name="line-202"></a>
<a name="line-203"></a>    'Lens.Family.State.Strict.zoom' lets you delimit a 'Parser' using a
<a name="line-204"></a>    'Lens.Family2.Lens''.  The above code says to limit 'drawAll' to a subset of
<a name="line-205"></a>    the input, in this case the first three elements:
<a name="line-206"></a>
<a name="line-207"></a>&gt;&gt;&gt; evalStateT drawThree (each [1..])
<a name="line-208"></a>[1,2,3]
<a name="line-209"></a>
<a name="line-210"></a>    'splitAt' is a 'Lens.Family2.Lens'' with the following type:
<a name="line-211"></a>
<a name="line-212"></a>&gt; splitAt
<a name="line-213"></a>&gt;     :: Monad m
<a name="line-214"></a>&gt;     =&gt; Int -&gt; Lens' (Producer a m x) (Producer a m (Producer a m x))
<a name="line-215"></a>
<a name="line-216"></a>    The easiest way to understand 'splitAt' is to study what happens when you
<a name="line-217"></a>    use it as a getter:
<a name="line-218"></a>
<a name="line-219"></a>&gt; view (splitAt 3) :: Producer a m x -&gt; Producer a m (Producer a m x) 
<a name="line-220"></a>
<a name="line-221"></a>    In this context, @(splitAt 3)@ behaves like 'splitAt' from the Prelude,
<a name="line-222"></a>    except instead of splitting a list it splits a 'Producer'.  Here's an
<a name="line-223"></a>    example of how you can use 'splitAt':
<a name="line-224"></a>
<a name="line-225"></a>&gt; outer :: Monad m =&gt; Producer Int m (Producer Int m ())
<a name="line-226"></a>&gt; outer = each [1..6] ^. splitAt 3
<a name="line-227"></a>
<a name="line-228"></a>    The above definition of @outer@ is exactly equivalent to:
<a name="line-229"></a>
<a name="line-230"></a>&gt; outer = do
<a name="line-231"></a>&gt;     each [1..3]
<a name="line-232"></a>&gt;     return (each [4..6])
<a name="line-233"></a>
<a name="line-234"></a>    We can prove this by successively running the outer and inner 'Producer'
<a name="line-235"></a>    layers:
<a name="line-236"></a>
<a name="line-237"></a>&gt;&gt;&gt; -- Print all the elements in the outer layer and return the inner layer
<a name="line-238"></a>&gt;&gt;&gt; inner &lt;- runEffect $ for outer (lift . print)
<a name="line-239"></a>1
<a name="line-240"></a>2
<a name="line-241"></a>3
<a name="line-242"></a>&gt;&gt;&gt; -- Now print the elements in the inner layer
<a name="line-243"></a>&gt;&gt;&gt; runEffect $ for inner (lift . print)
<a name="line-244"></a>4
<a name="line-245"></a>5
<a name="line-246"></a>6
<a name="line-247"></a>
<a name="line-248"></a>    We can also uses lenses to modify 'Parser's, using
<a name="line-249"></a>    'Lens.Family.State.Strict.zoom'.  When we combine
<a name="line-250"></a>    'Lens.Family.State.Strict.zoom' with @(splitAt 3)@ we limit a parser to the
<a name="line-251"></a>    the first three elements of the stream.  When the parser is done
<a name="line-252"></a>    'Lens.Family.State.Strict.zoom' also returns unused elements back to the
<a name="line-253"></a>    original stream.  We can demonstrate this using the following example
<a name="line-254"></a>    parser:
<a name="line-255"></a>
<a name="line-256"></a>&gt; splitExample :: Monad m =&gt; Parser a m ([a], Maybe a, [a])
<a name="line-257"></a>&gt; splitExample = do
<a name="line-258"></a>&gt;     x &lt;- zoom (splitAt 3) drawAll
<a name="line-259"></a>&gt;     y &lt;- zoom (splitAt 3) draw
<a name="line-260"></a>&gt;     z &lt;- zoom (splitAt 3) drawAll
<a name="line-261"></a>&gt;     return (x, y, z)
<a name="line-262"></a>
<a name="line-263"></a>    The second parser begins where the first parser left off:
<a name="line-264"></a>
<a name="line-265"></a>&gt;&gt;&gt; evalStateT splitExample (each [1..])
<a name="line-266"></a>([1,2,3],Just 4,[5,6,7])
<a name="line-267"></a>
<a name="line-268"></a>    'span' behaves the same way, except that it uses a predicate and takes as
<a name="line-269"></a>    many consecutive elements as possible that satisfy the predicate:
<a name="line-270"></a>
<a name="line-271"></a>&gt; spanExample :: Monad m =&gt; Parser Int m (Maybe Int, [Int], Maybe Int)
<a name="line-272"></a>&gt; spanExample = do
<a name="line-273"></a>&gt;     x &lt;- zoom (span (&gt;= 4)) draw
<a name="line-274"></a>&gt;     y &lt;- zoom (span (&lt;  4)) drawAll
<a name="line-275"></a>&gt;     z &lt;- zoom (span (&gt;= 4)) draw
<a name="line-276"></a>&gt;     return (x, y, z)
<a name="line-277"></a>
<a name="line-278"></a>    Note that even if the first parser fails, subsequent parsers can still
<a name="line-279"></a>    succeed because they operate under a different lens:
<a name="line-280"></a>
<a name="line-281"></a>&gt;&gt;&gt; evalStateT spanExample (each [1..])
<a name="line-282"></a>(Nothing,[1,2,3],Just 4)
<a name="line-283"></a>
<a name="line-284"></a>    You can even nest 'Lens.Family.State.Strict.zoom's, too:
<a name="line-285"></a>
<a name="line-286"></a>&gt; nestExample :: Monad m =&gt; Parser Int m (Maybe Int, [Int], Maybe Int)
<a name="line-287"></a>&gt; nestExample = zoom (splitAt 2) spanExample
<a name="line-288"></a>
<a name="line-289"></a>    All the parsers from @spanExample@ now only see a subset of the input,
<a name="line-290"></a>    namely the first two elements:
<a name="line-291"></a>
<a name="line-292"></a>&gt;&gt;&gt; evalStateT nestExample (each [1..])
<a name="line-293"></a>(Nothing,[1,2],Nothing)
<a name="line-294"></a>
<a name="line-295"></a>-}</span>
<a name="line-296"></a>
<a name="line-297"></a><span class='hs-comment'>{- $getters
<a name="line-298"></a>    Not all transformations are reversible.  For example, consider the following
<a name="line-299"></a>    contrived function:
<a name="line-300"></a>
<a name="line-301"></a>&gt; import Pipes
<a name="line-302"></a>&gt; import qualified Pipes.Prelude as P
<a name="line-303"></a>&gt;
<a name="line-304"></a>&gt; map' :: Monad m =&gt; (a -&gt; b) -&gt; Producer a m r -&gt; Producer b m r
<a name="line-305"></a>&gt; map' f p = p &gt;-&gt; P.map f
<a name="line-306"></a>
<a name="line-307"></a>    Given a function of type @(a -&gt; b)@, we can transform a stream of @a@'s into
<a name="line-308"></a>    a stream of @b@'s, but not the other way around.  Transformations which are
<a name="line-309"></a>    not reversible and cannot be modeled as 'Pipe's can only be modeled as
<a name="line-310"></a>    functions between 'Producer's.  However, 'Pipe's are preferable to functions
<a name="line-311"></a>    between 'Producer's when possible because 'Pipe's can transform both
<a name="line-312"></a>    'Producer's and 'Consumer's.
<a name="line-313"></a>
<a name="line-314"></a>    If you prefer, you can use lens-like syntax for functions between
<a name="line-315"></a>    'Producer's by promoting them to @Getter@s using 'Lens.Family.to':
<a name="line-316"></a>
<a name="line-317"></a>&gt; import Lens.Family
<a name="line-318"></a>&gt;
<a name="line-319"></a>&gt; example :: Monad m =&gt; Producer Int m ()
<a name="line-320"></a>&gt; example = each [1..3] ^. to (map' (*2))
<a name="line-321"></a>
<a name="line-322"></a>    However, a function of 'Producer's (or the equivalent @Getter@) cannot be
<a name="line-323"></a>    used transform 'Parser's (using 'Lens.Family.State.Strict.zoom' or
<a name="line-324"></a>    otherwise) .  This reflects the fact that such a transformation cannot be
<a name="line-325"></a>    applied in reversed.
<a name="line-326"></a>-}</span>
<a name="line-327"></a>
<a name="line-328"></a><span class='hs-comment'>{- $buildlenses
<a name="line-329"></a>    Lenses are very easy to write if you are willing to depend on either the
<a name="line-330"></a>    @lens-family@ or @lens@ library.  Both of these libraries provide an
<a name="line-331"></a>    'Lens.Family2.Unchecked.iso' function that you can use to assemble your own
<a name="line-332"></a>    lenses.  You only need two functions which reversibly transform back and
<a name="line-333"></a>    forth between a stream of @a@s and a stream of @b@s:
<a name="line-334"></a>
<a name="line-335"></a>&gt; -- "Forward"
<a name="line-336"></a>&gt; fw :: Producer a m x -&gt; Producer b m y
<a name="line-337"></a>&gt;
<a name="line-338"></a>&gt; -- "Backward"
<a name="line-339"></a>&gt; bw :: Producer b m y -&gt; Producer a m x
<a name="line-340"></a>
<a name="line-341"></a>    ... such that:
<a name="line-342"></a>
<a name="line-343"></a>&gt; fw . bw = id
<a name="line-344"></a>&gt;
<a name="line-345"></a>&gt; bw . fw = id
<a name="line-346"></a>
<a name="line-347"></a>    You can then convert them to a 'Lens.Family2.Lens'' using
<a name="line-348"></a>    'Lens.Family2.Unchecked.iso':
<a name="line-349"></a>
<a name="line-350"></a>&gt; import Lens.Family2 (Lens')
<a name="line-351"></a>&gt; import Lens.Family2.Unchecked (iso)
<a name="line-352"></a>&gt;
<a name="line-353"></a>&gt; lens :: Lens' (Producer a m x) (Producer b m y)
<a name="line-354"></a>&gt; lens = iso fw bw
<a name="line-355"></a>
<a name="line-356"></a>    You can even do this without incurring any dependencies if you rewrite the
<a name="line-357"></a>    above code like this:
<a name="line-358"></a>
<a name="line-359"></a>&gt; -- This type synonym requires the 'RankNTypes' extension
<a name="line-360"></a>&gt; type Lens' a b = forall f . Functor f =&gt; (b -&gt; f b) -&gt; (a -&gt; f a)
<a name="line-361"></a>&gt;
<a name="line-362"></a>&gt; lens :: Lens' (Producer a m x) (Producer b m y)
<a name="line-363"></a>&gt; lens k p = fmap bw (k (fw p))
<a name="line-364"></a>
<a name="line-365"></a>    This is what @pipes-parse@ does internally, and you will find several
<a name="line-366"></a>    examples of this pattern in the source code of the "Pipes.Parse" module.
<a name="line-367"></a>
<a name="line-368"></a>    Lenses defined using either approach will work with both the @lens@ and
<a name="line-369"></a>    @lens-family@ libraries.
<a name="line-370"></a>-}</span>
<a name="line-371"></a>
<a name="line-372"></a><span class='hs-comment'>{- $conclusion
<a name="line-373"></a>    @pipes-parse@ introduces core idioms for @pipes@-based parsing.  These
<a name="line-374"></a>    idioms reuse 'Producer's, but introduce two new abstractions:
<a name="line-375"></a>    'Lens.Family2.Lens''es and 'Parser's.
<a name="line-376"></a>
<a name="line-377"></a>    This library is very minimal and only contains datatype-agnostic parsing
<a name="line-378"></a>    utilities, so this tutorial does not explore the full range of parsing
<a name="line-379"></a>    tricks using lenses.  For example, you can also use lenses to change the
<a name="line-380"></a>    element type.
<a name="line-381"></a>
<a name="line-382"></a>    Several downstream libraries provide more specific functionality, including:
<a name="line-383"></a>
<a name="line-384"></a>    * @pipes-binary@: Lenses and parsers for @binary@ values
<a name="line-385"></a>
<a name="line-386"></a>    * @pipes-attoparsec@: Converts @attoparsec@ parsers to @pipes@ parsers
<a name="line-387"></a>
<a name="line-388"></a>    * @pipes-aeson@: Lenses and parsers for JSON values
<a name="line-389"></a>
<a name="line-390"></a>    * @pipes-bytestring@: Lenses and parsers for byte streams
<a name="line-391"></a>
<a name="line-392"></a>    * @pipes-text@: Lenses and parsers for text encodings
<a name="line-393"></a>
<a name="line-394"></a>    To learn more about @pipes-parse@, ask questions, or follow development, you
<a name="line-395"></a>    can subscribe to the @haskell-pipes@ mailing list at:
<a name="line-396"></a>
<a name="line-397"></a>    &lt;https://groups.google.com/forum/#!forum/haskell-pipes&gt;
<a name="line-398"></a>
<a name="line-399"></a>    ... or you can mail the list directly at:
<a name="line-400"></a>
<a name="line-401"></a>    &lt;mailto:haskell-pipes@googlegroups.com&gt;
<a name="line-402"></a>-}</span>
</pre></body>
</html>