The reader effect allows obtaining values from the environment. The initial seed for the environment value is provided at runtime interpretation.

The reader effect supports parametrization to any seed value type while remaining type safe throughout the program declaration.

There needs to be implicit evidence of cats.mtl.ApplicativeAsk[M, R] and Monad[M] for any runtime M[_] used in its interpretation due to the constraints placed by this effect. R represents the seed value type.

The reader effect comes with two operations ask and reader.


ask simply returns the entire environment in its current state.

// import

// import

// import

// import

import cats.implicits._
// import cats.implicits._

import cats.mtl.implicits._
// import cats.mtl.implicits._

case class Config(n: Int)
// defined class Config

type ConfigEnv[A] = Reader[Config, A]
// defined type alias ConfigEnv

val rd = reader[Config]
// rd:[Config] =$EnvironmentProvider@7a1c95b2

import rd.implicits._
// import rd.implicits._

def programAsk[F[_]: rd.ReaderM] =
  for {
    _ <- FreeS.pure(1)
    c <- rd.ReaderM[F].ask
    _ <- FreeS.pure(1)
  } yield c
// programAsk: [F[_]](implicit evidence$1: rd.ReaderM[F])[[β$0$][F,β$0$],Config]

programAsk[rd.ReaderM.Op].interpret[ConfigEnv].run(Config(n = 10))
// res0: cats.Id[Config] = Config(10)


reader allows extracting values of the environment and lifting them into the context of FreeS

def programReader[F[_]: rd.ReaderM] =
  for {
    a <- FreeS.pure(1)
    b <- rd.ReaderM[F].reader(_.n)
    c <- FreeS.pure(1)
  } yield a + b + c
// programReader: [F[_]](implicit evidence$1: rd.ReaderM[F])[[β$0$][F,β$0$],Int]

programReader[rd.ReaderM.Op].interpret[ConfigEnv].run(Config(n = 1))
// res1: cats.Id[Int] = 3