Reader

case class Reader[E,A](run: E => A)

object Reader {

  implicit def readerMonad[E]: Monad[({ type λ[ɑ] = Reader[E,ɑ] })#λ] =
    new Monad[({ type λ[ɑ] = Reader[E,ɑ] })#λ] {

      def pure[A](a: A): Reader[E,A] =
        Reader(_ => a)

      def flatMap[A,B](ma: Reader[E,A])(f: A => Reader[E,B]): Reader[E,B] =
        Reader { e: E =>
          val a: A = ma.run(e)
          f(a).run(e)
        }
    }
}

Dependencies

Example

Services

trait LocationService {
  def getMyLocation: String
}

trait WeatherService {
  def getWeatherAt(location: String): String
}

Modules

trait LocationServiceIO {
  def locationService: LocationService
}

trait WeatherServiceIO {
  def weatherService: WeatherService
}

Effects

def getMyLocation[E <: LocationServiceIO]: Reader[E, String] =
  Reader(e => e.locationService.getMyLocation)

def getWeatherAt[E <: WeatherServiceIO](location: String): Reader[E, String] =
  Reader(e => e.weatherService.getWeatherAt(location))

Usage

import Monad._
import Reader._

type EnvIO = LocationServiceIO with WeatherServiceIO

val getMyWeather: Reader[EnvIO, String] =
  for {
    myLocation <- getMyLocation[EnvIO]
    weather    <- getWeatherAt[EnvIO](myLocation)
  } yield s"It is ${weather} in ${myLocation}."
val env: EnvIO =
  new LocationServiceIO with WeatherServiceIO {
    val locationService: LocationService =
      new LocationService {
    def getMyLocation: String = "Boulder"
      }
    val weatherService: WeatherService =
      new WeatherService {
    def getWeatherAt(location: String): String = "sunny"
      }
  }

val myWeather: String = getMyWeather.run(env)

println(myWeather) // It is sunny in Boulder.

Demo

This file is literate Scala, and can be run using Codedown:

$ curl -s \
    https://earldouglas.com/posts/scala-type-classes/applicative.md \
    https://earldouglas.com/posts/scala-type-classes/functor.md \
    https://earldouglas.com/posts/scala-type-classes/monad.md \
    https://earldouglas.com/posts/scala-type-classes/reader.md |
  codedown scala | xargs -0 scala -e
It is sunny in Boulder.