a monad transformer for Reader presented in this gist: https://gist.github.com/Mortimerp9/5400194
This is a companion code for the following post: https://coderwall.com/p/ibrhta
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.concurrent.Future | |
import scala.concurrent.ExecutionContext | |
/** | |
* a ReaderM is a tool for Readers containing other monads, such as Reader[_, Option[_]] or Reader[_, Future[_]] | |
*/ | |
case class ReaderM[-C, A, M[+A]](val read: Reader[C, M[A]])(implicit canMap: CanMap[A, _, M]) { | |
def apply(conn: C): M[A] = read(conn) | |
/** | |
* transform the value within the embedded monad | |
*/ | |
def map[B](f: A => B)(implicit canMap: CanMap[A, B, M]): Reader[C, M[B]] = read.map(in => canMap.map(in)(f)) | |
/** | |
* transform the value within the embedded monad, in the case where we get a ReaderM back | |
*/ | |
def flatMap[B, D <: C](f: A => ReaderM[D, B, M])(implicit canMap: CanMap[A, B, M], canMapB: CanMap[B, _, M]): ReaderM[D, B, M] = ReaderM[D, B, M](read.flatMap { in => | |
Reader.reader { (conn: D) => | |
canMap.flatMap(in) { a: A => | |
f(a)(conn) | |
} | |
} | |
}) | |
/** | |
* transform the value within the embedded monad, in the case where we get a Reader with a pure value inside | |
*/ | |
def flatMapMap[B, D <: C](f: A => Reader[D, B])(implicit canMap: CanMap[A, B, M], canMapB: CanMap[B, _, M]): ReaderM[D, B, M] = ReaderM[D, B, M](read.flatMap { in => | |
Reader.reader { (conn: D) => | |
canMap.map(in) { a: A => | |
f(a)(conn) | |
} | |
} | |
}) | |
/** | |
* Combine two readers | |
*/ | |
def zip[B, D <: C](other: ReaderM[D, B, M])(implicit canMapAB: CanMap[(A, B), _, M], canMap: CanMap[A, (A, B), M], canMapB: CanMap[B, (A, B), M]): ReaderM[D, (A, B), M] = ReaderM.readerM { conn: D => | |
val a = apply(conn) | |
val b = other(conn) | |
canMap.flatMap(a)(av => canMapB.map(b)((av, _))) | |
} | |
} | |
object ReaderM { | |
/** | |
* transforms a Future[Reader[A, B]] in a Reader[A, Future[B]] | |
*/ | |
implicit def moveFuture[A, B](future: Future[Reader[A, B]])(implicit context: ExecutionContext): Reader[A, Future[B]] = | |
Reader.sequence(future) | |
implicit def moveFutureFuture[A, B](future: Future[Reader[A, Future[B]]])(implicit context: ExecutionContext): Reader[A, Future[B]] = { | |
val future1 = moveFuture(future) | |
future1.map(f => f.flatMap(inf => inf)) | |
} | |
def pure[C, B, M[+_]](value: B)(implicit canMap: CanMap[B, B, M]): ReaderM[C, B, M] = | |
ReaderM[C, B, M](Reader.pure[C, M[B]](canMap.pure(value))) | |
/** | |
* implicit conversion back to a Reader. | |
*/ | |
implicit def toReader[C, M[_]](rm: ReaderM[C, _, M]): Reader[C, M[_]] = rm.read; | |
implicit def readerM[C, A, M[+A]](r: Reader[C, M[A]])(implicit canMap: CanMap[A, _, M]): ReaderM[C, A, M] = ReaderM[C, A, M](r) | |
/** | |
* provide a connection to read the content of a reader | |
*/ | |
def withConnection[C, R, M[+R]](connection: C)(r: ReaderM[C, R, M]): M[R] = r(connection) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment