0
# Monad Transformers
1
2
Monad transformers allow composition of different monadic effects, enabling complex computations that combine multiple computational contexts.
3
4
## Capabilities
5
6
### State Transformers
7
8
#### StateT
9
10
Stateful computations that can modify state while computing values.
11
12
```scala { .api }
13
case class StateT[S, F[_], A](runF: S => F[(S, A)]) {
14
/** Run the stateful computation */
15
def run(initial: S)(implicit F: Monad[F]): F[(S, A)]
16
17
/** Execute and return only the final state */
18
def exec(initial: S)(implicit F: Monad[F]): F[S]
19
20
/** Evaluate and return only the result */
21
def eval(initial: S)(implicit F: Monad[F]): F[A]
22
23
/** Map over the result value */
24
def map[B](f: A => B)(implicit F: Functor[F]): StateT[S, F, B]
25
26
/** FlatMap for sequencing stateful computations */
27
def flatMap[B](f: A => StateT[S, F, B])(implicit F: Monad[F]): StateT[S, F, B]
28
29
/** Transform the state type */
30
def mapState[S2](f: S => S2, g: (S2, S) => S2)(implicit F: Functor[F]): StateT[S2, F, A]
31
32
/** Transform the inner monad */
33
def mapT[G[_]](f: F[(S, A)] => G[(S, A)]): StateT[S, G, A]
34
35
/** Lift StateT into another monad transformer */
36
def liftM[G[_[_], _]](implicit G: MonadTrans[G], F: Monad[F]): G[StateT[S, F, ?], A]
37
}
38
39
type State[S, A] = StateT[S, Id, A]
40
41
object StateT {
42
/** Lift a value into StateT */
43
def point[S, F[_], A](a: A)(implicit F: Applicative[F]): StateT[S, F, A]
44
45
/** Lift an F[A] into StateT */
46
def lift[S, F[_], A](fa: F[A])(implicit F: Functor[F]): StateT[S, F, A]
47
48
/** Get the current state */
49
def get[S, F[_]](implicit F: Applicative[F]): StateT[S, F, S]
50
51
/** Set the state */
52
def put[S, F[_]](s: S)(implicit F: Applicative[F]): StateT[S, F, Unit]
53
54
/** Modify the state */
55
def modify[S, F[_]](f: S => S)(implicit F: Applicative[F]): StateT[S, F, Unit]
56
57
/** Inspect the state with a function */
58
def gets[S, F[_], A](f: S => A)(implicit F: Applicative[F]): StateT[S, F, A]
59
}
60
61
object State {
62
/** Create a State computation */
63
def apply[S, A](f: S => (S, A)): State[S, A] = StateT[S, Id, A](f)
64
65
/** Get the current state */
66
def get[S]: State[S, S] = StateT.get[S, Id]
67
68
/** Set the state */
69
def put[S](s: S): State[S, Unit] = StateT.put[S, Id](s)
70
71
/** Modify the state */
72
def modify[S](f: S => S): State[S, Unit] = StateT.modify[S, Id](f)
73
74
/** Get part of the state */
75
def gets[S, A](f: S => A): State[S, A] = StateT.gets[S, Id, A](f)
76
}
77
```
78
79
**Usage Examples:**
80
81
```scala
82
import scalaz._
83
import Scalaz._
84
85
// Simple counter state
86
val increment: State[Int, Int] = for {
87
current <- State.get[Int]
88
_ <- State.put(current + 1)
89
result <- State.get[Int]
90
} yield result
91
92
val (finalState, result) = increment.run(0) // (1, 1)
93
94
// Stack operations
95
def push[A](a: A): State[List[A], Unit] = State.modify(a :: _)
96
def pop[A]: State[List[A], Option[A]] = for {
97
stack <- State.get[List[A]]
98
_ <- State.put(stack.drop(1))
99
} yield stack.headOption
100
101
val stackOps = for {
102
_ <- push(1)
103
_ <- push(2)
104
top <- pop[Int]
105
} yield top
106
107
val (finalStack, result) = stackOps.run(List.empty[Int])
108
```
109
110
### Reader Transformers
111
112
#### ReaderT (Kleisli)
113
114
Computations that read from a shared environment.
115
116
```scala { .api }
117
case class Kleisli[M[_], -A, +B](run: A => M[B]) {
118
/** Apply the Kleisli arrow */
119
def apply(a: A): M[B] = run(a)
120
121
/** Map over the result */
122
def map[C](f: B => C)(implicit M: Functor[M]): Kleisli[M, A, C]
123
124
/** FlatMap for sequencing Reader computations */
125
def flatMap[C](f: B => Kleisli[M, A, C])(implicit M: Monad[M]): Kleisli[M, A, C]
126
127
/** Compose with another Kleisli */
128
def compose[C](k: Kleisli[M, C, A])(implicit M: Monad[M]): Kleisli[M, C, B]
129
130
/** AndThen composition */
131
def andThen[C](k: Kleisli[M, B, C])(implicit M: Monad[M]): Kleisli[M, A, C]
132
133
/** Transform the input type */
134
def local[AA](f: AA => A): Kleisli[M, AA, B]
135
136
/** Transform the inner monad */
137
def mapT[N[_]](f: M[B] => N[B]): Kleisli[N, A, B]
138
139
/** Lower to function if M is Id */
140
def lower(implicit M: M[B] <:< B): A => B
141
}
142
143
type ReaderT[E, F[_], A] = Kleisli[F, E, A]
144
type Reader[E, A] = ReaderT[E, Id, A]
145
146
object Kleisli {
147
/** Lift a value into Kleisli */
148
def point[M[_], A, B](b: B)(implicit M: Applicative[M]): Kleisli[M, A, B]
149
150
/** Lift an M[B] into Kleisli */
151
def lift[M[_], A, B](mb: M[B]): Kleisli[M, A, B]
152
153
/** Ask for the environment */
154
def ask[M[_], A](implicit M: Applicative[M]): Kleisli[M, A, A]
155
156
/** Apply a function to the environment */
157
def asks[M[_], A, B](f: A => B)(implicit M: Applicative[M]): Kleisli[M, A, B]
158
}
159
160
object Reader {
161
/** Create a Reader */
162
def apply[E, A](f: E => A): Reader[E, A] = Kleisli[Id, E, A](f)
163
164
/** Ask for the environment */
165
def ask[E]: Reader[E, E] = Kleisli.ask[Id, E]
166
167
/** Apply function to environment */
168
def asks[E, A](f: E => A): Reader[E, A] = Kleisli.asks[Id, E, A](f)
169
}
170
```
171
172
**Usage Examples:**
173
174
```scala
175
import scalaz._
176
import Scalaz._
177
178
case class Config(host: String, port: Int, database: String)
179
180
// Database operations that need config
181
def connectDb: Reader[Config, String] = Reader { config =>
182
s"Connected to ${config.database} at ${config.host}:${config.port}"
183
}
184
185
def queryUser(id: Int): Reader[Config, String] = for {
186
connection <- connectDb
187
config <- Reader.ask[Config]
188
} yield s"$connection - Queried user $id"
189
190
val config = Config("localhost", 5432, "myapp")
191
val result = queryUser(123).run(config)
192
```
193
194
### Writer Transformers
195
196
#### WriterT
197
198
Computations that accumulate log values alongside results.
199
200
```scala { .api }
201
case class WriterT[W, F[_], A](run: F[(W, A)]) {
202
/** Map over the result value */
203
def map[B](f: A => B)(implicit F: Functor[F]): WriterT[W, F, B]
204
205
/** FlatMap for sequencing Writer computations */
206
def flatMap[B](f: A => WriterT[W, F, B])(implicit F: Monad[F], W: Semigroup[W]): WriterT[W, F, B]
207
208
/** Get only the log */
209
def written(implicit F: Functor[F]): F[W]
210
211
/** Get only the value */
212
def value(implicit F: Functor[F]): F[A]
213
214
/** Transform the log */
215
def mapLog[W2](f: W => W2)(implicit F: Functor[F]): WriterT[W2, F, A]
216
217
/** Transform both log and value */
218
def bimap[W2, B](f: W => W2, g: A => B)(implicit F: Functor[F]): WriterT[W2, F, B]
219
220
/** Clear the log */
221
def reset(implicit F: Functor[F], W: Monoid[W]): WriterT[W, F, A]
222
223
/** Swap log and value */
224
def swap(implicit F: Functor[F]): WriterT[A, F, W]
225
}
226
227
type Writer[W, A] = WriterT[W, Id, A]
228
229
object WriterT {
230
/** Create WriterT with log and value */
231
def apply[W, F[_], A](log: W, value: A)(implicit F: Applicative[F]): WriterT[W, F, A]
232
233
/** Lift a value into WriterT */
234
def point[W, F[_], A](value: A)(implicit W: Monoid[W], F: Applicative[F]): WriterT[W, F, A]
235
236
/** Lift an F[A] into WriterT */
237
def lift[W, F[_], A](fa: F[A])(implicit W: Monoid[W], F: Functor[F]): WriterT[W, F, A]
238
239
/** Create with only log */
240
def tell[W, F[_]](log: W)(implicit F: Applicative[F]): WriterT[W, F, Unit]
241
242
/** Create from F[(W, A)] */
243
def writerT[W, F[_], A](fwa: F[(W, A)]): WriterT[W, F, A]
244
}
245
246
object Writer {
247
/** Create Writer with log and value */
248
def apply[W, A](log: W, value: A): Writer[W, A] = WriterT[W, Id, A]((log, value))
249
250
/** Create with only value */
251
def value[W: Monoid, A](value: A): Writer[W, A] = Writer(Monoid[W].zero, value)
252
253
/** Create with only log */
254
def tell[W](log: W): Writer[W, Unit] = Writer(log, ())
255
}
256
```
257
258
**Usage Examples:**
259
260
```scala
261
import scalaz._
262
import Scalaz._
263
264
// Computation with logging
265
def addWithLog(x: Int, y: Int): Writer[String, Int] =
266
Writer(s"Added $x and $y; ", x + y)
267
268
def multiplyWithLog(x: Int, y: Int): Writer[String, Int] =
269
Writer(s"Multiplied $x and $y; ", x * y)
270
271
val computation = for {
272
sum <- addWithLog(3, 4)
273
product <- multiplyWithLog(sum, 2)
274
} yield product
275
276
val (log, result) = computation.run // ("Added 3 and 4; Multiplied 7 and 2; ", 14)
277
```
278
279
### Option/Maybe Transformers
280
281
#### OptionT
282
283
Computations that may fail, combining Option with another monad.
284
285
```scala { .api }
286
case class OptionT[F[_], A](run: F[Option[A]]) {
287
/** Map over the contained value */
288
def map[B](f: A => B)(implicit F: Functor[F]): OptionT[F, B]
289
290
/** FlatMap for sequencing optional computations */
291
def flatMap[B](f: A => OptionT[F, B])(implicit F: Monad[F]): OptionT[F, B]
292
293
/** Get the value or a default */
294
def getOrElse[AA >: A](default: => AA)(implicit F: Functor[F]): F[AA]
295
296
/** Get the value or compute alternative */
297
def orElse(alternative: => OptionT[F, A])(implicit F: Monad[F]): OptionT[F, A]
298
299
/** Check if the value exists */
300
def isDefined(implicit F: Functor[F]): F[Boolean]
301
302
/** Check if the value is empty */
303
def isEmpty(implicit F: Functor[F]): F[Boolean]
304
305
/** Filter with predicate */
306
def filter(p: A => Boolean)(implicit F: Functor[F]): OptionT[F, A]
307
308
/** Fold with functions for both cases */
309
def fold[B](ifEmpty: => B)(f: A => B)(implicit F: Functor[F]): F[B]
310
311
/** Transform the inner monad */
312
def mapT[G[_]](f: F[Option[A]] => G[Option[A]]): OptionT[G, A]
313
}
314
315
object OptionT {
316
/** Create OptionT with Some value */
317
def some[F[_], A](a: A)(implicit F: Applicative[F]): OptionT[F, A]
318
319
/** Create OptionT with None */
320
def none[F[_], A](implicit F: Applicative[F]): OptionT[F, A]
321
322
/** Lift F[A] into OptionT */
323
def liftF[F[_], A](fa: F[A])(implicit F: Functor[F]): OptionT[F, A]
324
325
/** Create from F[Option[A]] */
326
def optionT[F[_], A](foa: F[Option[A]]): OptionT[F, A]
327
328
/** Create from Option[A] */
329
def fromOption[F[_], A](oa: Option[A])(implicit F: Applicative[F]): OptionT[F, A]
330
}
331
```
332
333
#### MaybeT
334
335
Similar to OptionT but using Scalaz's Maybe type.
336
337
```scala { .api }
338
case class MaybeT[F[_], A](run: F[Maybe[A]]) {
339
/** Map over the contained value */
340
def map[B](f: A => B)(implicit F: Functor[F]): MaybeT[F, B]
341
342
/** FlatMap for sequencing maybe computations */
343
def flatMap[B](f: A => MaybeT[F, B])(implicit F: Monad[F]): MaybeT[F, B]
344
345
/** Get the value or a default */
346
def getOrElse[AA >: A](default: => AA)(implicit F: Functor[F]): F[AA]
347
348
/** Get the value or compute alternative */
349
def orElse(alternative: => MaybeT[F, A])(implicit F: Monad[F]): MaybeT[F, A]
350
351
/** Check if the value exists */
352
def isDefined(implicit F: Functor[F]): F[Boolean]
353
354
/** Check if the value is empty */
355
def isEmpty(implicit F: Functor[F]): F[Boolean]
356
}
357
358
object MaybeT {
359
/** Create MaybeT with Just value */
360
def just[F[_], A](a: A)(implicit F: Applicative[F]): MaybeT[F, A]
361
362
/** Create MaybeT with Empty */
363
def empty[F[_], A](implicit F: Applicative[F]): MaybeT[F, A]
364
365
/** Lift F[A] into MaybeT */
366
def liftF[F[_], A](fa: F[A])(implicit F: Functor[F]): MaybeT[F, A]
367
}
368
```
369
370
### Either Transformers
371
372
#### EitherT
373
374
Computations that may fail with error values, combining Either with another monad.
375
376
```scala { .api }
377
case class EitherT[E, F[_], A](run: F[E \/ A]) {
378
/** Map over the right value */
379
def map[B](f: A => B)(implicit F: Functor[F]): EitherT[E, F, B]
380
381
/** FlatMap for sequencing Either computations */
382
def flatMap[B](f: A => EitherT[E, F, B])(implicit F: Monad[F]): EitherT[E, F, B]
383
384
/** Map over the left (error) value */
385
def leftMap[EE](f: E => EE)(implicit F: Functor[F]): EitherT[EE, F, A]
386
387
/** Bimap over both sides */
388
def bimap[EE, B](f: E => EE, g: A => B)(implicit F: Functor[F]): EitherT[EE, F, B]
389
390
/** Fold both sides */
391
def fold[B](left: E => B, right: A => B)(implicit F: Functor[F]): F[B]
392
393
/** Get right value or default */
394
def getOrElse[AA >: A](default: => AA)(implicit F: Functor[F]): F[AA]
395
396
/** Recover from error */
397
def recover[AA >: A](pf: PartialFunction[E, AA])(implicit F: Functor[F]): EitherT[E, F, AA]
398
399
/** Check if this is a right value */
400
def isRight(implicit F: Functor[F]): F[Boolean]
401
402
/** Check if this is a left value */
403
def isLeft(implicit F: Functor[F]): F[Boolean]
404
405
/** Swap left and right */
406
def swap(implicit F: Functor[F]): EitherT[A, F, E]
407
}
408
409
object EitherT {
410
/** Create EitherT with right value */
411
def right[E, F[_], A](a: A)(implicit F: Applicative[F]): EitherT[E, F, A]
412
413
/** Create EitherT with left value */
414
def left[E, F[_], A](e: E)(implicit F: Applicative[F]): EitherT[E, F, A]
415
416
/** Lift F[A] into EitherT as right */
417
def liftF[E, F[_], A](fa: F[A])(implicit F: Functor[F]): EitherT[E, F, A]
418
419
/** Create from F[E \/ A] */
420
def eitherT[E, F[_], A](fea: F[E \/ A]): EitherT[E, F, A]
421
422
/** Create from E \/ A */
423
def fromDisjunction[E, F[_], A](ea: E \/ A)(implicit F: Applicative[F]): EitherT[E, F, A]
424
}
425
```
426
427
**Usage Examples:**
428
429
```scala
430
import scalaz._
431
import Scalaz._
432
433
// Database operations that might fail
434
def findUser(id: Int): EitherT[String, Future, User] =
435
if (id > 0) EitherT.right(Future.successful(User(id, "John")))
436
else EitherT.left(Future.successful("Invalid user ID"))
437
438
def findProfile(user: User): EitherT[String, Future, Profile] =
439
EitherT.right(Future.successful(Profile(user.id, "Developer")))
440
441
val result = for {
442
user <- findUser(123)
443
profile <- findProfile(user)
444
} yield UserWithProfile(user, profile)
445
446
// result: EitherT[String, Future, UserWithProfile]
447
```
448
449
### List Transformers
450
451
#### ListT
452
453
Computations that produce multiple results, combining List with another monad.
454
455
```scala { .api }
456
case class ListT[M[_], A](run: M[List[A]]) {
457
/** Map over the elements */
458
def map[B](f: A => B)(implicit M: Functor[M]): ListT[M, B]
459
460
/** FlatMap for sequencing list computations */
461
def flatMap[B](f: A => ListT[M, B])(implicit M: Monad[M]): ListT[M, B]
462
463
/** Filter elements */
464
def filter(p: A => Boolean)(implicit M: Functor[M]): ListT[M, A]
465
466
/** Take first n elements */
467
def take(n: Int)(implicit M: Functor[M]): ListT[M, A]
468
469
/** Drop first n elements */
470
def drop(n: Int)(implicit M: Functor[M]): ListT[M, A]
471
472
/** Append another ListT */
473
def ++(other: ListT[M, A])(implicit M: Monad[M]): ListT[M, A]
474
475
/** Convert to List in the monad */
476
def toList: M[List[A]] = run
477
}
478
479
object ListT {
480
/** Create empty ListT */
481
def empty[M[_], A](implicit M: Applicative[M]): ListT[M, A]
482
483
/** Create ListT with single element */
484
def single[M[_], A](a: A)(implicit M: Applicative[M]): ListT[M, A]
485
486
/** Lift M[A] into ListT */
487
def liftF[M[_], A](ma: M[A])(implicit M: Functor[M]): ListT[M, A]
488
489
/** Create from M[List[A]] */
490
def listT[M[_], A](mla: M[List[A]]): ListT[M, A]
491
492
/** Create from List[A] */
493
def fromList[M[_], A](la: List[A])(implicit M: Applicative[M]): ListT[M, A]
494
}
495
```
496
497
### Combined Transformers
498
499
#### ReaderWriterStateT
500
501
Combination of Reader, Writer, and State transformers.
502
503
```scala { .api }
504
case class ReaderWriterStateT[R, W, S, F[_], A](run: (R, S) => F[(W, A, S)]) {
505
/** Map over the result value */
506
def map[B](f: A => B)(implicit F: Functor[F]): ReaderWriterStateT[R, W, S, F, B]
507
508
/** FlatMap for sequencing computations */
509
def flatMap[B](f: A => ReaderWriterStateT[R, W, S, F, B])(implicit F: Monad[F], W: Semigroup[W]): ReaderWriterStateT[R, W, S, F, B]
510
511
/** Execute the computation */
512
def runRWST(r: R, s: S): F[(W, A, S)] = run(r, s)
513
514
/** Execute and return only the result */
515
def eval(r: R, s: S)(implicit F: Functor[F]): F[A]
516
517
/** Execute and return only the final state */
518
def exec(r: R, s: S)(implicit F: Functor[F]): F[S]
519
520
/** Execute and return only the log */
521
def logged(r: R, s: S)(implicit F: Functor[F]): F[W]
522
}
523
524
type ReaderWriterState[R, W, S, A] = ReaderWriterStateT[R, W, S, Id, A]
525
type RWST[R, W, S, F[_], A] = ReaderWriterStateT[R, W, S, F, A]
526
type RWS[R, W, S, A] = ReaderWriterState[R, W, S, A]
527
528
object ReaderWriterStateT {
529
/** Ask for the environment */
530
def ask[R, W, S, F[_]](implicit W: Monoid[W], F: Applicative[F]): ReaderWriterStateT[R, W, S, F, R]
531
532
/** Tell (log) a value */
533
def tell[R, W, S, F[_]](w: W)(implicit F: Applicative[F]): ReaderWriterStateT[R, W, S, F, Unit]
534
535
/** Get the current state */
536
def get[R, W, S, F[_]](implicit W: Monoid[W], F: Applicative[F]): ReaderWriterStateT[R, W, S, F, S]
537
538
/** Set the state */
539
def put[R, W, S, F[_]](s: S)(implicit W: Monoid[W], F: Applicative[F]): ReaderWriterStateT[R, W, S, F, Unit]
540
541
/** Modify the state */
542
def modify[R, W, S, F[_]](f: S => S)(implicit W: Monoid[W], F: Applicative[F]): ReaderWriterStateT[R, W, S, F, Unit]
543
}
544
```
545
546
**Usage Examples:**
547
548
```scala
549
import scalaz._
550
import Scalaz._
551
552
case class Config(debug: Boolean)
553
type Log = List[String]
554
type Counter = Int
555
556
def increment: ReaderWriterState[Config, Log, Counter, Unit] = for {
557
config <- ReaderWriterStateT.ask[Config, Log, Counter, Id]
558
count <- ReaderWriterStateT.get[Config, Log, Counter, Id]
559
_ <- ReaderWriterStateT.put[Config, Log, Counter, Id](count + 1)
560
_ <- if (config.debug)
561
ReaderWriterStateT.tell[Config, Log, Counter, Id](List(s"Incremented to ${count + 1}"))
562
else
563
ReaderWriterStateT.point[Config, Log, Counter, Id, Unit](())
564
} yield ()
565
566
val config = Config(debug = true)
567
val (log, result, finalState) = increment.run(config, 0)
568
```