-
Notifications
You must be signed in to change notification settings - Fork 2
/
MyOwnReaderT.html
410 lines (354 loc) · 46.6 KB
/
MyOwnReaderT.html
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
<meta charset="utf-8">
<head>
<link rel="stylesheet" type="text/css" href="bootstrap.css">
</head>
<p>
Note to self on constructing a monad transformer. In a way this follows on from the earlier post <a href="http://carlo-hamalainen.net/blog/2014/1/2/applicatives-compose-monads-do-not">Applicatives compose, monads do not</a>. Literate Haskell source for this post is available here: <a href="https://github.com/carlohamalainen/playground/tree/master/haskell/transformers">https://github.com/carlohamalainen/playground/tree/master/haskell/transformers</a>.
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: green;">{-# LANGUAGE ScopedTypeVariables, InstanceSigs, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}</span>
<span style="">></span>
<span style="">></span> <span style="color: blue; font-weight: bold;">module</span> <span style="">MyOwnReaderT</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span>
<span style="">></span> <span style="color: blue; font-weight: bold;">import</span> <span style="">Control</span><span style="">.</span><span style="">Monad</span>
<span style="">></span>
<span style="">></span> <span style="">hole</span> <span style="color: red;">=</span> <span style="">undefined</span>
<span style="">></span> <span style="color: blue; font-weight: bold;">data</span> <span style="">Hole</span> <span style="color: red;">=</span> <span style="">Hole</span>
</code></pre>
<h2>
The Reader Monad
</h2>
<p>
A <code>Reader</code> is a data type that encapsulates an environment. The <code>runReader</code> function takes an environment (a <code>Reader</code>) and runs it, producing the result of type <code>a</code>.
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">newtype</span> <span style="">Reader</span> <span style="">r</span> <span style="">a</span> <span style="color: red;">=</span> <span style="">Reader</span> <span style="color: red;">{</span> <span style="">runReader</span> <span style="color: red;">::</span> <span style="">r</span> <span style="color: red;">-></span> <span style="">a</span> <span style="color: red;">}</span>
</code></pre>
<p>
Note that with record syntax, the type of <code>runReader</code> is actually
</p>
<pre>
runReader :: Reader r a -> (r -> a)
</pre>
<p>
Reader that increments its environment value, returning the same type:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">reader1</span> <span style="color: red;">::</span> <span style="">Num</span> <span style="">r</span> <span style="color: red;">=></span> <span style="">Reader</span> <span style="">r</span> <span style="">r</span>
<span style="">></span> <span style="">reader1</span> <span style="color: red;">=</span> <span style="">Reader</span> <span style="">$</span> <span style="color: red;">\</span><span style="">r</span> <span style="color: red;">-></span> <span style="">r</span> <span style="">+</span> <span class="hs-num">1</span>
</code></pre>
<p>
Reader that converts its environment value into a string:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">reader2</span> <span style="color: red;">::</span> <span style="">Show</span> <span style="">r</span> <span style="color: red;">=></span> <span style="">Reader</span> <span style="">r</span> <span style="">String</span>
<span style="">></span> <span style="">reader2</span> <span style="color: red;">=</span> <span style="">Reader</span> <span style="">$</span> <span style="color: red;">\</span><span style="">r</span> <span style="color: red;">-></span> <span style="color: teal;">"reader2: "</span> <span style="">++</span> <span style="color: red;">(</span><span style="">show</span> <span style="">r</span><span style="color: red;">)</span>
</code></pre>
<p>
“Run” the reader using <code>runReader</code>:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">runReader</span> <span style="">reader1</span> <span class="hs-num">100</span>
<span style="">></span> <span class="hs-num">101</span>
<span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">runReader</span> <span style="">reader2</span> <span class="hs-num">100</span>
<span style="">></span> <span style="color: teal;">"reader2: 100"</span>
</code></pre>
<p>
There’s nothing magic about <code>runReader</code>; it is just taking the function out of the data type. We can do it manually ourselves:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">runReader'</span> <span style="color: red;">::</span> <span style="">Reader</span> <span style="">r</span> <span style="">a</span> <span style="color: red;">-></span> <span style="color: red;">(</span><span style="">r</span> <span style="color: red;">-></span> <span style="">a</span><span style="color: red;">)</span>
<span style="">></span> <span style="">runReader'</span> <span style="color: red;">(</span><span style="">Reader</span> <span style="">f</span><span style="color: red;">)</span> <span style="color: red;">=</span> <span style="">f</span>
</code></pre>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">runReader'</span> <span style="">reader1</span> <span class="hs-num">100</span>
<span style="">></span> <span class="hs-num">101</span>
</code></pre>
<p>
Next, make <code>Reader</code> an instance of <code>Monad</code>:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">instance</span> <span style="">Monad</span> <span style="color: red;">(</span><span style="">Reader</span> <span style="">r</span><span style="color: red;">)</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span> <span style="">return</span> <span style="color: red;">::</span> <span style="">a</span> <span style="color: red;">-></span> <span style="">Reader</span> <span style="">r</span> <span style="">a</span>
<span style="">></span> <span style="">return</span> <span style="">a</span> <span style="color: red;">=</span> <span style="">Reader</span> <span style="">$</span> <span style="color: red;">\</span><span style="color: blue; font-weight: bold;">_</span> <span style="color: red;">-></span> <span style="">a</span>
<span style="">></span>
<span style="">></span> <span style="color: red;">(</span><span style="">>>=</span><span style="color: red;">)</span> <span style="color: red;">::</span> <span style="color: blue; font-weight: bold;">forall</span> <span style="">a</span> <span style="">b</span><span style="">.</span> <span style="">Reader</span> <span style="">r</span> <span style="">a</span> <span style="color: red;">-></span> <span style="color: red;">(</span><span style="">a</span> <span style="color: red;">-></span> <span style="">Reader</span> <span style="">r</span> <span style="">b</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">Reader</span> <span style="">r</span> <span style="">b</span>
<span style="">></span> <span style="">m</span> <span style="">>>=</span> <span style="">k</span> <span style="color: red;">=</span> <span style="">Reader</span> <span style="">$</span> <span style="color: red;">\</span><span style="">r</span> <span style="color: red;">-></span> <span style="">runReader</span> <span style="color: red;">(</span><span style="">k</span> <span style="color: red;">(</span><span style="">runReader</span> <span style="">m</span> <span style="">r</span> <span style="color: red;">::</span> <span style="">a</span><span style="color: red;">)</span> <span style="color: red;">::</span> <span style="">Reader</span> <span style="">r</span> <span style="">b</span><span style="color: red;">)</span> <span style="">r</span>
</code></pre>
<p>
The definition of <code>>>=</code> is relatively easy to work out using <a href="http://matthew.brecknell.net/post/hole-driven-haskell/">hole driven development</a>.
</p>
<p>
Example usage:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">eg1</span> <span style="color: red;">::</span> <span style="">Reader</span> <span style="">Int</span> <span style="">String</span>
<span style="">></span> <span style="">eg1</span> <span style="color: red;">=</span> <span style="">Reader</span> <span style="">id</span> <span style="">>>=</span> <span style="color: red;">\</span><span style="">e</span> <span style="color: red;">-></span> <span style="">return</span> <span style="">$</span> <span style="color: teal;">"hey, "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
</code></pre>
<p>
Or in the more readable <code>do</code> notation:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">eg1'</span> <span style="color: red;">::</span> <span style="">Reader</span> <span style="">Int</span> <span style="">String</span>
<span style="">></span> <span style="">eg1'</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">Reader</span> <span style="">id</span>
<span style="">></span> <span style="">return</span> <span style="">$</span> <span style="color: teal;">"hey, "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
</code></pre>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">runReader</span> <span style="">eg1'</span> <span class="hs-num">100</span>
<span style="">></span> <span style="color: teal;">"hey, 100"</span>
</code></pre>
<p>
Note that we use <code>id</code> to produce a <code>Reader</code> that just passes its environment argument along as the output. See <code>readerAsk</code> later for the equivalent situation which uses <code>return</code> for <code>MonadReader</code>.
</p>
<p>
Since <code>[]</code> is an instance of <code>Monad</code> we can also do things like this:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">eg1''</span> <span style="color: red;">::</span> <span style="">Reader</span> <span style="">Int</span> <span style="">String</span>
<span style="">></span> <span style="">eg1''</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">Reader</span> <span style="color: red;">(</span><span style="">return</span> <span style="color: red;">::</span> <span style="">Int</span> <span style="color: red;">-></span> <span style="">[]</span> <span style="">Int</span><span style="color: red;">)</span>
<span style="">></span> <span style="">return</span> <span style="">$</span> <span style="color: teal;">"hey, "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
</code></pre>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">runReader</span> <span style="">eg1''</span> <span class="hs-num">100</span>
<span style="">></span> <span style="color: teal;">"hey, [100]"</span>
</code></pre>
<h2>
Reader Transformer
</h2>
<p>
<p>We’d like to use the <code>Reader</code> in conjunction with other monads, for example running <code>IO</code> actions but having access to the reader’s environment. To do this we create a transformer, which we’ll call <code>ReaderT</code>:</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">newtype</span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span> <span style="color: red;">=</span> <span style="">ReaderT</span> <span style="color: red;">{</span> <span style="">runReaderT</span> <span style="color: red;">::</span> <span style="">r</span> <span style="color: red;">-></span> <span style="">m</span> <span style="">a</span> <span style="color: red;">}</span>
</code></pre>
<p>
The <code>r</code> parameter is the reader environment as before, <code>m</code> is the monad (for example <code>IO</code>), and <code>a</code> is the result type, as before. Again, note the actual type of <code>runReaderT</code>:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">runReaderT</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span> <span style="color: red;">-></span> <span style="color: red;">(</span><span style="">r</span> <span style="color: red;">-></span> <span style="">m</span> <span style="">a</span><span style="color: red;">)</span>
</code></pre>
<p>
It takes a <code>ReaderT</code> and provides us with a function that takes a reader environment of type <code>r</code> and produces a monadic value. Following from the <code>Monad</code> instance declaration for <code>Reader</code> it is straightforward to write the definition for <code>ReaderT</code>.
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">instance</span> <span style="">Monad</span> <span style="">m</span> <span style="color: red;">=></span> <span style="">Monad</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">r</span> <span style="">m</span><span style="color: red;">)</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span> <span style="">return</span> <span style="">a</span> <span style="color: red;">=</span> <span style="">ReaderT</span> <span style="">$</span> <span style="color: red;">\</span><span style="">r</span> <span style="color: red;">-></span> <span style="">return</span> <span style="">a</span>
<span style="">></span>
<span style="">></span> <span style="color: red;">(</span><span style="">>>=</span><span style="color: red;">)</span> <span style="color: red;">::</span> <span style="color: blue; font-weight: bold;">forall</span> <span style="">a</span> <span style="">b</span><span style="">.</span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span> <span style="color: red;">-></span> <span style="color: red;">(</span><span style="">a</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">b</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">b</span>
<span style="">></span> <span style="">m</span> <span style="">>>=</span> <span style="">k</span> <span style="color: red;">=</span> <span style="">ReaderT</span> <span style="">$</span> <span style="color: red;">\</span><span style="">r</span> <span style="color: red;">-></span> <span style="color: blue; font-weight: bold;">do</span> <span style="color: blue; font-weight: bold;">let</span> <span style="">a'</span> <span style="color: red;">=</span> <span style="">runReaderT</span> <span style="">m</span> <span style="">r</span> <span style="color: red;">::</span> <span style="">m</span> <span style="">a</span>
<span style="">></span> <span style="">a''</span> <span style="color: red;"><-</span> <span style="">a'</span>
<span style="">></span> <span style="">runReaderT</span> <span style="color: red;">(</span><span style="">k</span> <span style="">a''</span><span style="color: red;">)</span> <span style="">r</span> <span style="color: red;">::</span> <span style="">m</span> <span style="">b</span>
</code></pre>
<p>
With a <code>ReaderT</code> as the outer monad, we would like to “lift” a monadic computation into the reader. A monadic action doesn’t know anything about the reader environment, so to lift the monadic value we just create a <code>ReaderT</code> with a function that ignores the environment:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">liftReaderT</span> <span style="color: red;">::</span> <span style="">m</span> <span style="">a</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span>
<span style="">></span> <span style="">liftReaderT</span> <span style="">m</span> <span style="color: red;">=</span> <span style="">ReaderT</span> <span style="color: red;">(</span><span style="color: red;">\</span><span style="color: blue; font-weight: bold;">_</span> <span style="color: red;">-></span> <span style="">m</span><span style="color: red;">)</span>
</code></pre>
<p>
Example usage:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">egLift</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">Int</span> <span style="">IO</span> <span style="">()</span>
<span style="">></span> <span style="">egLift</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">ReaderT</span> <span style="color: red;">(</span><span style="">return</span> <span style="color: red;">::</span> <span style="">Int</span> <span style="color: red;">-></span> <span style="">IO</span> <span style="">Int</span><span style="color: red;">)</span> <span style="color: green;">-- This is similar to "Reader id" earlier.</span>
<span style="">></span> <span style="">liftReaderT</span> <span style="">$</span> <span style="">print</span> <span style="color: teal;">"boo"</span>
<span style="">></span> <span style="">liftReaderT</span> <span style="">$</span> <span style="">print</span> <span style="">$</span> <span style="color: teal;">"value of e: "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
</code></pre>
<p>
<p>Note the type of <code>return</code> on the first line of <code>egLift</code>. In this context, <code>return :: a -> m a</code> is the equivalent of <code>id :: a -> a</code> from the earlier <code>Reader</code> example.</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">runReaderT</span> <span style="">egLift</span> <span class="hs-num">100</span>
<span style="">></span> <span style="color: teal;">"boo"</span>
<span style="">></span> <span style="color: teal;">"value of e: 100"</span>
</code></pre>
<p>
More generally, let’s name the “ask” function:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">readerAsk</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span style="">Monad</span> <span style="">m</span><span style="color: red;">)</span> <span style="color: red;">=></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">r</span>
<span style="">></span> <span style="">readerAsk</span> <span style="color: red;">=</span> <span style="">ReaderT</span> <span style="">return</span>
</code></pre>
<p>
If we want to modify the environment, we use <code>withReaderT</code> which takes as its first parameter a function to modify the environment. Note that the result is of type <code>ReaderT r’ m a</code> so the function is of type <code>r’ -> r</code> which modifies the supplied reader of type <code>ReaderT r m a</code>.
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">withReaderT</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span style="">r'</span> <span style="color: red;">-></span> <span style="">r</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r'</span> <span style="">m</span> <span style="">a</span>
<span style="">></span> <span style="">withReaderT</span> <span style="">f</span> <span style="">rt</span> <span style="color: red;">=</span> <span style="">ReaderT</span> <span style="">$</span> <span style="color: red;">(</span><span style="">runReaderT</span> <span style="">rt</span><span style="color: red;">)</span> <span style="">.</span> <span style="">f</span>
</code></pre>
<p>
Lastly, it is convenient to apply a function to the current environment.
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">readerReader</span> <span style="color: red;">::</span> <span style="">Monad</span> <span style="">m</span> <span style="color: red;">=></span> <span style="color: red;">(</span><span style="">r</span> <span style="color: red;">-></span> <span style="">a</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span>
<span style="">></span> <span style="">readerReader</span> <span style="">f</span> <span style="color: red;">=</span> <span style="">ReaderT</span> <span style="">$</span> <span style="color: red;">\</span><span style="">r</span> <span style="color: red;">-></span> <span style="">return</span> <span style="color: red;">(</span><span style="">f</span> <span style="">r</span><span style="color: red;">)</span>
</code></pre>
<p>
This is almost the same as <code>readerAsk</code> except that we create a reader that returns <code>f r</code> instead of <code>f</code>. In other words:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">readerAsk'</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span style="">Monad</span> <span style="">m</span><span style="color: red;">)</span> <span style="color: red;">=></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">r</span>
<span style="">></span> <span style="">readerAsk'</span> <span style="color: red;">=</span> <span style="">readerReader</span> <span style="">id</span>
</code></pre>
<p>
Finally, we collect the functions <code>readerAsk</code>, <code>withReader</code>, and <code>readerReader</code> in a type class <code>MonadReader</code> and give them more general names:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">class</span> <span style="color: red;">(</span><span style="">Monad</span> <span style="">m</span><span style="color: red;">)</span> <span style="color: red;">=></span> <span style="">MonadReader</span> <span style="">r</span> <span style="">m</span> <span style="color: red;">|</span> <span style="">m</span> <span style="color: red;">-></span> <span style="">r</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span> <span style="color: green;">-- Retrieve the monad environment.</span>
<span style="">></span> <span style="">ask</span> <span style="color: red;">::</span> <span style="">m</span> <span style="">r</span>
<span style="">></span>
<span style="">></span> <span style="color: green;">-- Execute the computation in the modified environment.</span>
<span style="">></span> <span style="">local</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span style="">r</span> <span style="color: red;">-></span> <span style="">r</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">m</span> <span style="">a</span> <span style="color: red;">-></span> <span style="">m</span> <span style="">a</span>
<span style="">></span>
<span style="">></span> <span style="color: green;">-- Retrieves a function of the current environment.</span>
<span style="">></span> <span style="">reader</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span style="">r</span> <span style="color: red;">-></span> <span style="">a</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">m</span> <span style="">a</span>
</code></pre>
<p>
An instance declaration for our <code>ReaderT</code> type:
<p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">instance</span> <span style="">Monad</span> <span style="">m</span> <span style="color: red;">=></span> <span style="">MonadReader</span> <span style="">r</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">r</span> <span style="">m</span><span style="color: red;">)</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span> <span style="">ask</span> <span style="color: red;">=</span> <span style="">readerAsk</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">r</span>
<span style="">></span> <span style="">local</span> <span style="color: red;">=</span> <span style="">withReaderT</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span style="">r</span> <span style="color: red;">-></span> <span style="">r</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span>
<span style="">></span> <span style="">reader</span> <span style="color: red;">=</span> <span style="">readerReader</span> <span style="color: red;">::</span> <span style="color: red;">(</span><span style="">r</span> <span style="color: red;">-></span> <span style="">a</span><span style="color: red;">)</span> <span style="color: red;">-></span> <span style="">ReaderT</span> <span style="">r</span> <span style="">m</span> <span style="">a</span>
</code></pre>
<p>
Now we can write fairly succinct code as follows. Use the <code>IO</code> monad as the inner monad in a <code>ReaderT</code>, with an <code>Int</code> environment and <code>String</code> result type.
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">eg2</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">Int</span> <span style="">IO</span> <span style="">String</span>
<span style="">></span> <span style="">eg2</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span>
<span style="">></span> <span style="color: green;">-- Get the reader environment.</span>
<span style="">></span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">ask</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">Int</span> <span style="">IO</span> <span style="">Int</span>
<span style="">></span>
<span style="">></span> <span style="color: green;">-- Run an IO action; we have to use liftReaderT since we are currently</span>
<span style="">></span> <span style="color: green;">-- in the ReaderT monad, not the IO monad.</span>
<span style="">></span> <span style="">liftReaderT</span> <span style="">$</span> <span style="">print</span> <span style="">$</span> <span style="color: teal;">"I'm in the eg2 function and the environment is: "</span> <span style="">++</span> <span style="color: red;">(</span><span style="">show</span> <span style="">e</span><span style="color: red;">)</span>
<span style="">></span>
<span style="">></span> <span style="color: green;">-- Final return value, a string.</span>
<span style="">></span> <span style="">return</span> <span style="">$</span> <span style="color: teal;">"returned value: "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
</code></pre>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">result</span> <span style="color: red;"><-</span> <span style="">runReaderT</span> <span style="">eg2</span> <span class="hs-num">100</span>
<span style="">></span> <span style="color: teal;">"I'm in the eg2 function and the environment is: 100"</span>
<span style="">></span>
<span style="">></span> <span style="">ghci</span><span style="">></span> <span style="">result</span>
<span style="">></span> <span style="color: teal;">"returned value: 100"</span>
</code></pre>
<p>
All of the above is available from <a href="http://hackage.haskell.org/package/mtl-2.1.2/docs/Control-Monad-Reader.html">Control.Monad.Reader</a> and <a href="http://hackage.haskell.org/package/mtl-2.1.2/docs/Control-Monad-Trans.html">Control.Monad.Trans</a>.
</p>
<h2>
StateT, ReaderT, and ask
</h2>
<p>
The <a href="http://www.haskell.org/haskellwiki/State_Monad">State</a> monad encapsulates a modifiable state. It has a transformer <code>StateT</code> as one would expect. Yet we are able to call <code>ask</code> inside a <code>StateT</code> monad. Here is an example (the raw code is <a href="https://github.com/carlohamalainen/playground/blob/master/haskell/transformers/Ask.hs">here</a>):
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">import</span> <span style="">Control</span><span style="">.</span><span style="">Monad</span><span style="">.</span><span style="">Reader</span>
<span style="">></span> <span style="color: blue; font-weight: bold;">import</span> <span style="">Control</span><span style="">.</span><span style="">Monad</span><span style="">.</span><span style="">State</span>
<span style="">></span>
<span style="">></span> <span style="">inside0</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span> <span style="">Float</span>
<span style="">></span> <span style="">inside0</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span>
<span style="">></span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">ask</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span> <span style="">String</span>
<span style="">></span>
<span style="">></span> <span style="">liftIO</span> <span style="">$</span> <span style="">putStrLn</span> <span style="">$</span> <span style="color: teal;">"inside0, e: "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
<span style="">></span>
<span style="">></span> <span style="">return</span> <span class="hs-num">1.23</span>
<span style="">></span>
<span style="">></span> <span style="">inside1</span> <span style="color: red;">::</span> <span style="">StateT</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span><span style="color: red;">)</span> <span style="">Float</span>
<span style="">></span> <span style="">inside1</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span>
<span style="">></span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">ask</span> <span style="color: red;">::</span> <span style="">StateT</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span><span style="color: red;">)</span> <span style="">String</span>
<span style="">></span> <span style="">s</span> <span style="color: red;"><-</span> <span style="">get</span> <span style="color: red;">::</span> <span style="">StateT</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span><span style="color: red;">)</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span>
<span style="">></span>
<span style="">></span> <span style="">liftIO</span> <span style="">$</span> <span style="">putStrLn</span> <span style="">$</span> <span style="color: teal;">"inside1, e: "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
<span style="">></span> <span style="">liftIO</span> <span style="">$</span> <span style="">putStrLn</span> <span style="">$</span> <span style="color: teal;">"inside1, s: "</span> <span style="">++</span> <span style="">show</span> <span style="">s</span>
<span style="">></span>
<span style="">></span> <span style="">put</span> <span style="color: red;">[</span><span class="hs-num">1</span><span style="color: red;">,</span> <span class="hs-num">1</span><span style="color: red;">,</span> <span class="hs-num">1</span><span style="color: red;">]</span>
<span style="">></span>
<span style="">></span> <span style="">return</span> <span class="hs-num">1.23</span>
<span style="">></span>
<span style="">></span> <span style="">run0</span> <span style="color: red;">::</span> <span style="">IO</span> <span style="">()</span>
<span style="">></span> <span style="">run0</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span> <span style="color: blue; font-weight: bold;">let</span> <span style="">layer1</span> <span style="color: red;">=</span> <span style="">runReaderT</span> <span style="">inside0</span> <span style="color: teal;">"reader environment, hi"</span>
<span style="">></span>
<span style="">></span> <span style="">result</span> <span style="color: red;"><-</span> <span style="">layer1</span>
<span style="">></span>
<span style="">></span> <span style="">print</span> <span style="">$</span> <span style="color: teal;">"result: "</span> <span style="">++</span> <span style="">show</span> <span style="">result</span>
<span style="">></span>
<span style="">></span> <span style="">run1</span> <span style="color: red;">::</span> <span style="">IO</span> <span style="">()</span>
<span style="">></span> <span style="">run1</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span> <span style="color: blue; font-weight: bold;">let</span> <span style="">layer1</span> <span style="color: red;">=</span> <span style="">runStateT</span> <span style="">inside1</span> <span style="color: red;">[</span><span class="hs-num">0</span><span style="color: red;">]</span>
<span style="">></span> <span style="">layer2</span> <span style="color: red;">=</span> <span style="">runReaderT</span> <span style="">layer1</span> <span style="color: teal;">"reader environment, hi"</span>
<span style="">></span>
<span style="">></span> <span style="color: red;">(</span><span style="">result</span><span style="color: red;">,</span> <span style="">finalState</span><span style="color: red;">)</span> <span style="color: red;"><-</span> <span style="">layer2</span>
<span style="">></span>
<span style="">></span> <span style="">print</span> <span style="">$</span> <span style="color: teal;">"final state: "</span> <span style="">++</span> <span style="">show</span> <span style="">finalState</span>
<span style="">></span>
<span style="">></span> <span style="">print</span> <span style="">$</span> <span style="color: teal;">"result: "</span> <span style="">++</span> <span style="">show</span> <span style="">result</span>
</code></pre>
<p>
The function <code>inside0</code> has the <code>IO</code> monad nested inside a <code>Reader</code>, while </code>inside1</code> has a <code>StateT</code> with the <code>ReaderT</code> inside. Yet in both we can write <code>e <- ask</code>.
</p>
<p>
Inspecting the types using <a href="https://github.com/eagletmt/ghcmod-vim">ghcmod-vim</a> we find that
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: green;">-- in inside0</span>
<span style="">></span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">ask</span> <span style="color: red;">::</span> <span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span> <span style="">String</span>
<span style="">></span>
<span style="">></span> <span style="color: green;">-- in inside1</span>
<span style="">></span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">ask</span> <span style="color: red;">::</span> <span style="">StateT</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span><span style="color: red;">)</span> <span style="">String</span>
</code></pre>
<p>
<p>so there must be a type class that provides the <code>ask</code> function for <code>StateT</code>.</p>
<p>
First, inspect the type of <code>ask</code> using ghci (here we are using the definitions from <code>Control.Monad.Reader</code> and <code>Control.Monad.State</code>, not the implementation in this file).
</p>
<pre>
ghci> :t ask
ask :: MonadReader r m => m r
</pre>
<p>
So <code>StateT</code> must have a <code>MonadReader</code> instance. Confirm this with <code>:i</code>:
</p>
<pre>
ghci> :i StateT
(lots of stuff)
instance MonadReader r m => MonadReader r (StateT s m)
-- Defined in `Control.Monad.Reader.Class'
(lots of stuff)
</pre>
<p>
Looking in <a href="http://hackage.haskell.org/package/mtl-2.1.2/docs/Control-Monad-Reader-Class.html">Control.Monad.Reader.Class</a> we find:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">instance</span> <span style="">MonadReader</span> <span style="">r</span> <span style="">m</span> <span style="color: red;">=></span> <span style="">MonadReader</span> <span style="">r</span> <span style="color: red;">(</span><span style="">Lazy</span><span style="">.</span><span style="">StateT</span> <span style="">s</span> <span style="">m</span><span style="color: red;">)</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span> <span style="">ask</span> <span style="color: red;">=</span> <span style="">lift</span> <span style="">ask</span>
<span style="">></span> <span style="">local</span> <span style="color: red;">=</span> <span style="">Lazy</span><span style="">.</span><span style="">mapStateT</span> <span style="">.</span> <span style="">local</span>
<span style="">></span> <span style="">reader</span> <span style="color: red;">=</span> <span style="">lift</span> <span style="">.</span> <span style="">reader</span>
</code></pre>
<p>
The <code>lift</code> function comes from <a href="https://hackage.haskell.org/package/transformers-0.3.0.0/docs/Control-Monad-Trans-Class.html">Monad.Trans.Class</a>, and looking there we see:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">class</span> <span style="">MonadTrans</span> <span style="">t</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span> <span style="color: green;">-- | Lift a computation from the argument monad to the constructed monad.</span>
<span style="">></span> <span style="">lift</span> <span style="color: red;">::</span> <span style="">Monad</span> <span style="">m</span> <span style="color: red;">=></span> <span style="">m</span> <span style="">a</span> <span style="color: red;">-></span> <span style="">t</span> <span style="">m</span> <span style="">a</span>
</code></pre>
<p>
So actually we are after the <code>MonaTrans</code> type class. Again looking at <code>:i</code> on <code>StateT</code> we see:
</p>
<pre>
ghci> :i StateT
instance MonadTrans (StateT s)
(lots of stuff)
-- Defined in `Control.Monad.Trans.State.Lazy'
(lots of stuff)
</pre>
<p>
So off we go to <a href="https://hackage.haskell.org/package/transformers-0.3.0.0/docs/Control-Monad-Trans-State-Lazy.html">Control.Monad.Trans.State.Lazy</a> where we finally get the answer:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="color: blue; font-weight: bold;">instance</span> <span style="">MonadTrans</span> <span style="color: red;">(</span><span style="">StateT</span> <span style="">s</span><span style="color: red;">)</span> <span style="color: blue; font-weight: bold;">where</span>
<span style="">></span> <span style="">lift</span> <span style="">m</span> <span style="color: red;">=</span> <span style="">StateT</span> <span style="">$</span> <span style="color: red;">\</span><span style="">s</span> <span style="color: red;">-></span> <span style="color: blue; font-weight: bold;">do</span>
<span style="">></span> <span style="">a</span> <span style="color: red;"><-</span> <span style="">m</span>
<span style="">></span> <span style="">return</span> <span style="color: red;">(</span><span style="">a</span><span style="color: red;">,</span> <span style="">s</span><span style="color: red;">)</span>
</code></pre>
<p>
This shows that for <code>StateT</code>, the <code>lift</code> function takes a monadic action and produces a state transformer that takes the current state, runs the action, and returns the result of the action along with the unmodified state. This makes sense in that the underlying action should not modify the state. (There are some <a href="https://hackage.haskell.org/package/transformers-0.3.0.0/docs/Control-Monad-Trans-Class.html">laws</a> that monad transformers must satisfy.)
</p>
<p>
If we did not have the <code>MonadTrans</code> type class then we would have to embed the <code>ask</code> call manually:
</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span style="">></span> <span style="">inside1'</span> <span style="color: red;">::</span> <span style="">StateT</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span><span style="color: red;">)</span> <span style="">Float</span>
<span style="">></span> <span style="">inside1'</span> <span style="color: red;">=</span> <span style="color: blue; font-weight: bold;">do</span>
<span style="">></span> <span style="">e</span> <span style="color: red;"><-</span> <span style="">StateT</span> <span style="">$</span> <span style="color: red;">\</span><span style="">s</span> <span style="color: red;">-></span> <span style="color: blue; font-weight: bold;">do</span> <span style="">a</span> <span style="color: red;"><-</span> <span style="">ask</span>
<span style="">></span> <span style="">return</span> <span style="color: red;">(</span><span style="">a</span><span style="color: red;">,</span> <span style="">s</span><span style="color: red;">)</span>
<span style="">></span>
<span style="">></span> <span style="">s</span> <span style="color: red;"><-</span> <span style="">get</span> <span style="color: red;">::</span> <span style="">StateT</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span> <span style="color: red;">(</span><span style="">ReaderT</span> <span style="">String</span> <span style="">IO</span><span style="color: red;">)</span> <span style="color: red;">[</span><span style="">Int</span><span style="color: red;">]</span>
<span style="">></span>
<span style="">></span> <span style="">liftIO</span> <span style="">$</span> <span style="">putStrLn</span> <span style="">$</span> <span style="color: teal;">"inside1, e: "</span> <span style="">++</span> <span style="">show</span> <span style="">e</span>
<span style="">></span> <span style="">liftIO</span> <span style="">$</span> <span style="">putStrLn</span> <span style="">$</span> <span style="color: teal;">"inside1, s: "</span> <span style="">++</span> <span style="">show</span> <span style="">s</span>
<span style="">></span>
<span style="">></span> <span style="">put</span> <span style="color: red;">[</span><span class="hs-num">1</span><span style="color: red;">,</span> <span class="hs-num">1</span><span style="color: red;">,</span> <span class="hs-num">1</span><span style="color: red;">]</span>
<span style="">></span>
<span style="">></span> <span style="">return</span> <span class="hs-num">1.23</span>
</code></pre>
<p>
Obviously this is laborious and error-prone. In this case, Haskell’s type class system lets us implement a few classes so that <code>ask</code>, <code>get</code>, <code>put</code>, etc, can be used seamlessly no matter which monad transformer we are in.
</p>
<p>
The downside is that reading Haskell code can be nontrivial. In our case we had to follow a trail through a few files to see where <code>ask</code> was actually implemented, and finding the right definition relied on us being able to infer the correct types of certain sub-expressions.
</p>
<p>
Personally I am finding more and more that plain vim and ghci does not cut it for Haskell development, and something richer like <a href="https://github.com/eagletmt/ghcmod-vim">ghcmod-vim</a> is a real necessity. Shameless self plug: <a href="https://github.com/carlohamalainen/ghc-imported-from">ghc-imported-from</a> is also very useful :-)
</p>
<div class="references">
</div>