Skip to content

Instantly share code, notes, and snippets.

@d6y
Last active March 16, 2018 17:43
Show Gist options
  • Save d6y/ec78acb17d8bfee773bcc40d8151488a to your computer and use it in GitHub Desktop.
Save d6y/ec78acb17d8bfee773bcc40d8151488a to your computer and use it in GitHub Desktop.
Assuming you're stuck using Future somewhere, well...
package example
import scala.language.higherKinds
import cats.MonadError
import cats.syntax.functor._
// Both Try and Future are backed by Exceptions
// We can trade Future for Try in tests to avoid concurrency and execution context etc
case class Value(isPrime: Boolean)
abstract class Client[F[_]](implicit mE: MonadError[F, Throwable]) {
def checkPrimeness(n: Int): F[Value]
}
case class API[F[_]](client: Client[F])(implicit mE: MonadError[F, Throwable]) {
// The API uses a client, and does some computation with the result from the client.
// In this case the "computation" is a trivial _.isPrime
def isPrime(n: Int): F[Boolean] =
client.checkPrimeness(n).map(_.isPrime)
}
object Application extends App {
import scala.concurrent.Future
import cats.instances.future._
import scala.concurrent.ExecutionContext.Implicits.global
// Partial implementation: only knows how to deal with the number 7
object NetworkClient extends Client[Future] {
val mE = implicitly[MonadError[Future, Throwable]]
def checkPrimeness(n: Int): Future[Value] =
if (n == 7) mE.pure(Value(true))
else mE.raiseError(new IllegalArgumentException(s"Not implemented for $n"))
}
val f7: Future[Boolean] = API(NetworkClient).isPrime(7)
val f8: Future[Boolean] = API(NetworkClient).isPrime(8)
import scala.concurrent._
import scala.concurrent.duration._
println(Await.result(f7, 1.seconds))
// println(Await.result(f8, 1.seconds))
// But also...
Test.test()
}
object Test {
import scala.util.{Success, Try}
import cats.instances.try_._
case class ConstantClient(result: Try[Value]) extends Client[Try] {
def checkPrimeness(n: Int): Try[Value] = result
}
def test(): Unit = {
val client = ConstantClient(Success(Value(true)))
assert( API(client).isPrime(99) == Success(true) )
}
}
@arosien
Copy link

arosien commented Mar 16, 2018

You gain some minor flexibility if you move the MonadError implicit to the methods instead of the the class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment