or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-structures.mdfree-structures.mdindex.mdstd-instances.mdsyntax.mdtransformers.mdtype-classes.md

transformers.mddocs/

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

```