Local
Local[F, E]
extends Ask
and allows to us express local modifications of the environment.
In practice, this means, that whenever we use local
on a value of ask
, we can locally modify the environment with a function E => E
.
In this case, locally modifying means that the only place we can actually observe the modification is in the F[A]
value passed to the local
function.
The local
function has the following signature:
trait Local[F[_], E] extends Ask[F, E] {
def local(fa: F[A])(f: E => E): F[A]
}
Here's a quick example of how it works:
import cats._
import cats.data._
import cats.syntax.all._
import cats.mtl._
def calculateContentLength[F[_]: Applicative](implicit F: Ask[F, String]): F[Int] =
F.ask.map(_.length)
def calculateModifiedContentLength[F[_]: Applicative](implicit F: Local[F, String]): F[Int] =
F.local(calculateContentLength[F])("Prefix " + _)
val result = calculateModifiedContentLength[Reader[String, *]].run("Hello")
// result: Int = 12
We can see that the content length returned is 12, because the string "Prefix "
is prepended to the environment value.
To see that local
only applies to the passed parameter we can run both calculateContentLength
and
calculateModifiedContentLength
in one for-expression:
def both[F[_]: Monad](implicit F: Local[F, String]): F[(Int, Int)] = for {
length <- calculateContentLength[F]
modifiedLength <- calculateModifiedContentLength[F]
} yield (length, modifiedLength)
val res = both[Reader[String, *]].run("Hello")
// res: (Int, Int) = (5, 12)