Functional Logging State in Scala

Posted on April 30, 2021

Just pass it as a parameter

How does that propagate out?

We’ve invented the State monad

Okay onto the StateT monad transformer

What happens when things go wrong?

What about if we swap to ReaderT with a cats-effect Ref

An aside on why our state should be a Monoid, and which instances this gets us

Looking forward to cats-effect-3 and IOLocal


On the topic of Dependency Injection in scala, there’s a picture that sticks in my mind that I saw from the scalar 2018 conference’s blog post:

Dependency Injection vote from Scalar 2018

As we can see, the winner by a large margin is constructors, and that makes sense from a functional point of view, make everything as simple as possible.

You can see that the other functional option that has some traction is the Reader Monad, and that’s what we’ll be looking at in this post.

So what’s Reader?

scala mdoc type ReaderT[F[_], I, O] = I => F[O]

Using the extremely simplistic defenition, ReaderT is just a function that has some input and creates some output inside an effect.

It has a Monad instance for ReaderT[F[_], I, *] so we can compose these together as long as they all take the same input type.

Maybe we’d write our program with something like:

```scala mdoc:reset import cats.effect.IO import

case class Config(host: String, port: Int) type MyMonad[O] = ReaderT[IO, Config, O]

So every action in my program takes a `Config` now, which makes sense, but it's not very nice to use:

```scala mdoc
def run() =
  for {
    _ <- ReaderT { (c: Config) => IO { println(s"Starting a server on ${}:${c.port}") } }
    _ <- ReaderT.liftF(IO { println("started") })
  } yield()

1 + 2