Skip to content

Instantly share code, notes, and snippets.

@justinhj
Last active January 27, 2021 23:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinhj/79f223bfb75791d40a6a5fd431ad86ea to your computer and use it in GitHub Desktop.
Save justinhj/79f223bfb75791d40a6a5fd431ad86ea to your computer and use it in GitHub Desktop.
Implementation of the WriterT monad transformer leveraging Cats for Monad and Monoid
package org.justinhj
object WriterTOldSchool extends App {
import cats.{Monad, Monoid}
case class WriterT[F[_]: Monad,W,A](val wrapped: F[(W,A)])
implicit def writerTMonad[F[_]: Monad,W: Monoid] = new Monad[WriterT[F,W,?]] {
override def pure[A](a: A): WriterT[F,W,A] = WriterT(Monad[F].pure((Monoid[W].empty,a)))
override def flatMap[A, B](fa: WriterT[F,W,A])(f: A => WriterT[F,W,B]): WriterT[F,W,B] = {
val ffa: F[(W,B)] = Monad[F].flatMap(fa.wrapped) {
case (wa,a) => {
val what = f(a).wrapped
Monad[F].map(what){
case (wb, b) =>
(Monoid[W].combine(wa,wb), b)
}
}
}
WriterT(ffa)
}
override def tailRecM[A, B](a: A)(f: A => WriterT[F,W,Either[A,B]]): WriterT[F,W,B] =
flatMap(f(a)) {
case Right(b) => pure(b)
case Left(nextA) => tailRecM(nextA)(f)
}
}
implicit class WriterTOps[F[_]: Monad, W: Monoid, A](fa: WriterT[F,W,A]) {
def flatMap[B](f: A => WriterT[F,W,B]): WriterT[F,W,B] =
Monad[WriterT[F,W,?]].flatMap(fa)(a => f(a))
}
def incrementEven(a: Int): WriterT[Either[String, ?],String,Int] = {
if(a % 2 == 1) WriterT(Left[String, (String, Int)]("Odd number provided"))
else WriterT(Right(("Inc even", a + 1)))
}
def doubleOdd(a: Int): WriterT[Either[String, ?], String, Int] = {
if(a % 2 == 0) WriterT(Left[String, (String, Int)]("Even number provided"))
else WriterT(Right(("Double odd", a + a)))
}
val writerExample = incrementEven(8).flatMap(doubleOdd)
println(writerExample)
}
@justinhj
Copy link
Author

Output is
WriterT(Right((Inc evenDouble odd,18)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment