I have the following methods:
trait Tr[F[_]]{
def getSet(): F[Set[String]]
def checksum(): F[Long]
def value(): F[String]
def doRun(v: String, c: Long, s: Set[String]): F[Unit]
}
now I want to write the following for comprehension:
import cats._
import cats.data.OptionT
import cats.implicits._
def fcmprhn[F[_]: Monad](F: Tr[F]): OptionT[F, Unit] =
for {
set <- OptionT {
F.getSet() map { s =>
if(s.nonEmpty) Some(s) else None
}
}
checksum <- OptionT.liftF(F.checksum())
v <- OptionT.liftF(F.value())
_ <- OptionT.liftF(F.doRun(v, checksum, set))
//can be lots of OptionT.liftF here
} yield ()
As you can see there is too much of OptionT boilerplate. Is there a way to avoid it?
I think I can make use of F ~> OptionT[F, ?]. Can you suggest something?
One approach could be to nest the "F only" portion of the for-comprehension within a single liftF:
def fcmprhn[F[_]: Monad](F: Tr[F]): OptionT[F, Unit] =
for {
set <- OptionT {
F.getSet() map { s =>
if(s.nonEmpty) Some(s) else None
}
}
_ <- OptionT.liftF {
for {
checksum <- F.checksum()
v <- F.value()
_ <- F.doRun(v, checksum, set)
// rest of F monad for-comprehension
} yield ()
}
} yield ()
You can write it in "mtl-style" instead. mtl-style refers to mtl library in haskell but really it just means that instead of encoding effects as values (i.e. OptionT[F, ?]), we encode them as functions that take an abstract effect F[_] and give that F capabilities using type classes. That means instead of using OptionT[F, Unit] as our return type we can just use F[Unit] as our return type because F has to be able to handle errors.
This makes writing code like yours a small bit easier, but it's effect is amplified as you add monad transformers to the stack. Right now you only have to lift once, but what if you wanted a StateT[OptionT[F, ?], S, Unit] in the future. With mtl-style, all you need to do is add another type class constraint.
Here's what your code'd look like written in mtl-style:
def fcmprhn[F[_]](F: Tr[F])(implicit E: MonadError[F, Unit]): F[Unit] =
for {
set <- OptionT {
F.getSet() flatMap { s =>
if(s.nonEmpty) E.pure(s) else E.raiseError(())
}
}
checksum <- F.checksum()
v <- F.value()
_ <- F.doRun(v, checksum, set)
} yield ()
And now when you run the program you can specify the F[_] to be something like what you had before OptionT[F, ?]:
fcmprhn[OptionT[F, ?]](OptionT.liftF(yourOriginalTr))
Related
I have the following code:
override def getStandsByUser(email: String): Try[Seq[Stand]] =
(for {
user <- OptionT(userService.findOneByEmail(email)): Try[Option[User]]
stands <- OptionT.liftF(standService.list()):[Try[List[Stand]]]
filtered = stands.filter(stand => user.stands.contains(stand.id))
} yield filtered).getOrElse(Seq())
}
I want to add logging on each stage of the processing - so I need to introduce writer monad and stack it with monad transformer OptionT. Could you please suggest how to do that?
The best way to do this is to convert your service calls into using cats-mtl.
For representing Try or Option you can use MonadError and for logging you can use FunctorTell. Now I don't know what exactly you're doing inside your userService or standService, but I wrote some code to demonstrate what the result might look like:
type Log = List[String]
//inside UserService
def findOneByEmail[F[_]](email: String)
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[User] = ???
//inside StandService
def list[F[_]]()
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[List[Stand]] = ???
def getStandsByUser[F[_]](email: String)
(implicit F: MonadError[F, Error], W: FunctorTell[F, Log]): F[List[Stand]] =
for {
user <- userService.findOneByEmail(email)
stands <- standService.list()
} yield stands.filter(stand => user.stands.contains(stand.id))
//here we actually run the function
val result =
getStandsByUser[WriterT[OptionT[Try, ?], Log, ?] // yields WriterT[OptionT[Try, ?], Log, List[Stand]]
.run // yields OptionT[Try, (Log, List[Stand])]
.value // yields Try[Option[(Log, List[Stand])]]
This way we can avoid all of the calls to liftF and easily compose our different services even if they will use different monad transformers at runtime.
If you take a look at the definition of cats.data.Writer you will see that it is an alias to cats.data.WriterT with the effect fixed to Id.
What you want to do is use WriterT directly and instead of Id use OptionT[Try, YourType].
Here is a small code example of how that can be achieved:
object Example {
import cats.data._
import cats.implicits._
type MyType[A] = OptionT[Try, A]
def myFunction: MyType[Int] = OptionT(Try(Option(1)))
def main(args: Array[String]): Unit = {
val tmp: WriterT[MyType, List[String], Int] = for {
_ <- WriterT.tell[MyType, List[String]](List("Before first invocation"))
i <- WriterT.liftF[MyType, List[String], Int](myFunction)
_ <- WriterT.tell[MyType, List[String]](List("After second invocation"))
j <- WriterT.liftF[MyType, List[String], Int](myFunction)
_ <- WriterT.tell[MyType, List[String]](List(s"Result is ${i + j}"))
} yield i + j
val result: Try[Option[(List[String], Int)]] = tmp.run.value
println(result)
// Success(Some((List(Before first invocation, After second invocation, Result is 2),2)))
}
}
The type annotations make this a bit ugly, but depending on your use case you might be able to get rid of them. As you can see myFunction returns a result of type OptionT[Try, Int] and WriterT.lift will push that into a writer object that also has a List[String] for your logs.
I often find myself in a scenario where I have defined an interface like so:
trait FooInterface [T[_]] {
def barA (): T[Int]
def barB (): T[Int]
def barC (): T[Int]
}
I then write a few different implementations each typed on the Higher Kinded Type that makes the most sense for that particular implementation:
object FooImpl1 extends FooInterface[Option] { ... }
object FooImpl2 extends FooInterface[Future] { ... }
object FooImpl3 extends FooInterface[({type X[Y] = ReaderT[Future, Database, Y]})#X] { ... }
All implementations are perfectly valid, all return their results wrapped in a particular Higher Kinded Type.
I then often come to writing some business logic, let's say that in the block of logic I am working with is using Future as a context, I might write something like this:
val foo: FooInterface[Future] = ???
def fn (): Future[Int] = Future { 42 }
val result: Future[Int] = for {
x <- foo.barA ()
y <- foo.barB ()
z <- foo.barC ()
w <- fn ()
} yield x + y + z + w
The above code would work really well with FooImpl2 however the other implementations do not slot in directly. In this scenario I always wind up writing simple adapters:
object FooImpl1Adapter extends FooInterface[Future] {
val t = new Exception ("Foo impl 1 failed.")
def barA (): Future[Int] = FooImpl1.barA () match {
case Some (num) => Future.successful (num)
case None => Future.failed (t)
}
def barB (): Future[Int] = FooImpl1.barB () match {
case Some (num) => Future.successful (num)
case None => Future.failed (t)
}
def barC (): Future[Int] = FooImpl1.barC () match {
case Some (num) => Future.successful (num)
case None => Future.failed (t)
}
}
case class FooImpl3Adapter (db: Database) extends FooInterface[Future] {
def barA (): Future[Int] = FooImpl3.barA ().run (db)
def barB (): Future[Int] = FooImpl3.barB ().run (db)
def barC (): Future[Int] = FooImpl3.barC ().run (db)
}
Writing adapters is fine but it involves a lot of boilerplate, especially for interfaces with lots of functions; what's more is that each method gets the exactly same adaptation treatment for each method. What I really want to do is lift an adaptor implementation from an existing implementation, only specify in adaption mechanism once.
I guess I want to be able to write something like this:
def generateAdapterFn[X[_], Y[_]] (implx: FooInterface[X])(f: X[?] => Y[?]): FooInterface[Y] = ???
So I could use it like so:
val fooImpl1Adapter: FooInterface[Future] = generateAdapterFn [?, Future] () { z => z match {
case Some (obj) => Future.successful (obj)
case None => Future.failed (t)
}}
The question is: How could I write the generateAdapterFn function?
I'm not really sure how to approach solving this, or if there are other common patterns or solutions to my problem. I suspect that to write the generateAdapterFn function I desire I would need to write a macro? If so how might that be done?
What you are looking for is a natural transformation from X to Y (what you called X[?] => Y[?]). In Cats is called a FunctionK (with the popular type alias ~>).
You could define a natural transformation between Option and Future as :
import cats.arrow.FunctionK
import scala.concurrent.Future
val option2future = new FunctionK[Option, Future] {
def apply[A](opt: Option[A]): Future[A] = opt match {
case Some(obj) => Future.succesful(obj)
case None => Future.failed(new Exception("none")) // t ??
}
}
With the kind projector compiler plugin this could be written more concise as :
val opt2fut = λ[FunctionK[Option, Future]]{
case Some(obj) => Future.succesful(obj)
case None => Future.failed(new Exception("none")) // t ??
}
Your generateAdapter function could then look like :
import cats.~>
def generateAdapter[X[_], Y[_]](implx: FooInterface[X])(f: X ~> Y): FooInterface[Y] =
new FooInterface[Y] {
def barA: Y[Int] = f(implx.barA)
def barB: Y[Int] = f(implx.barB)
def barC: Y[Int] = f(implx.barC)
}
You should then be able to create a FooInterface[Future]] as :
val fooFuture = generateAdapter(FooImpl1)(opt2fut)
Unrelated, you might be interested to read something about the free monad, which is used to solve similar problems as the one you are facing now.
Keep the code polymorphic for as long as possible. Instead of
val result: Future[Int] = for {
x <- foo.barA ()
y <- foo.barB ()
z <- foo.barC ()
w <- fn ()
} yield x + y + z + w
write
import scalaz.Monad
import scalaz.syntax.monad._
// or
import cats.Monad
import cats.syntax.all._
def result[M[_]: Monad](foo: FooInterface[M], fn: () => M[Int]): M[Int] = for {
x <- foo.barA ()
y <- foo.barB ()
z <- foo.barC ()
w <- fn ()
} yield x + y + z + w
This way, you avoid writing adapters for FooInterface altogether and only transform the final value (via a natural transformation (see Peter Neyens' answer) or also quite easily directly).
Expanding on Peter Neyen's answer (which I've marked as correct as it answers the important part of my question), here's a proof of concept for how generate the adapter at runtime using reflection:
def generateAdapterR[X[_], Y[_]](implx: FooInterface[X])(implicit
f: X ~> Y): FooInterface[Y] = {
import java.lang.reflect.{InvocationHandler, Method, Proxy}
object ProxyInvocationHandler extends InvocationHandler {
def invoke (
proxy: scala.AnyRef,
method: Method,
args: Array[AnyRef]): AnyRef = {
val fn = implx.getClass.getMethod (
method.getName,
method.getParameterTypes: _*)
val x = fn.invoke (implx, args: _*)
val fx = f.getClass.getMethods ()(0)
fx.invoke (f, x)
}
}
Proxy.newProxyInstance(
classOf[FooInterface[Y]].getClassLoader,
Array(classOf[FooInterface[Y]]),
ProxyInvocationHandler
).asInstanceOf[FooInterface[Y]]
}
Ideally it would be possible to type this function on T[_] as well, T being the type of the interface, so the function could be use to generate adaptors for any higher kinded interfaces at runtime.
Something like:
def genericGenerateAdapterR[T[_], X[_], Y[_]](implx: T[X[_]])(implicit
f: X ~> Y): T[Y[_]] = ???
Not really sure if that would be how to write it though...
I think the ideal solution would be to have a compiler plugin that generates the code in Peter Neyen's solution, avoiding reflection and avoiding boilerplate.
Im trying to learn how to write more functional code in Scala, however im finding it difficult not to pull values out of the monadic structures but instead use map/flatmap etc to manipulate values. This is easy when working with a single monad but how do I scale this to work with structures as below.
For example what would be the idiomatic way to transforming the value inside JsResult?
Option[Future[JsResult[LoginResponse]]]
Nested monads of a different types can be tricky, since for comprehensions require the Monads in it to be the same type. You can either do:
Lots of nested for's
val mappedValue = for (fut <- deepMonad) yield {
for (opt <- fut) yield {
for (bool <- opt) yield {
//some logic
}
}
}
or you can make a util which hides it away for you.
If you're looking at a specific structure which you use commonly in your project, and you want to stick with pure Scala, you can make something like below to do maps / foreach.
E.g.
object MyUtils {
implicit class MyWrapper[A](deepMonad: Option[Future[Option[A]]]) {
def fmap[B](f: A => B) = {
for (fut: Future[Option[A]] <- deepMonad) yield {
for (opt: Option[A] <- fut) yield {
for (b: A <- opt) yield {
f(b)
}
}
}
}
def myForeach[U](f: A => U): Unit = {
for (future <- deepMonad) {
for (opt <- future) {
for (b <- opt) {
f(b)
}
}
}
}
}
}
object Test extends App {
import MyUtils._
val deepMonadExample:Option[Future[Option[Boolean]]] = Some(Future.successful(Some(true)))
val x: Option[Future[Option[String]]] = deepMonadExample.fmap {
case v:Boolean => "Result: "+v
}
x.myForeach{ v => println(v) }
}
If you are willing to use Scalaz you can make a more generic util by using the Monad class. There are some prebuilt implicits in Scalaz which will make Option, Future, and others work out the box. However classes like JsResult does not have a scalaz Monad instance, so you need to make one.
E.g.
import play.api.libs.json.{JsSuccess, JsError, JsResult}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scalaz.Monad
//this creates the fmap method
object HandleDeepMonads {
import scala.language.higherKinds
import scalaz.Monad
import scalaz.Scalaz._
implicit class ThreeMonadMap[M[_] : Monad, M2[_] : Monad, M3[_] : Monad, A](v: M[M2[M3[A]]]) {
def fmap[B](f: A => B): M[M2[M3[B]]] = {
for (a <- v) yield
for (b <- a) yield
for (c <- b) yield f(c)
}
}
}
//Since JsResult has no native Monad in scalaz - you can make your own one
object MyCustomMonads {
implicit object JsResultMonad extends Monad[JsResult] {
def point[A](a: => A): JsResult[A] = JsSuccess(a)
def bind[A, B](fa: JsResult[A])(f: A => JsResult[B]): JsResult[B] = fa match {
case JsSuccess(v, _) => f(v)
case e#JsError(_) => e
}
}
}
object Test extends App {
import HandleDeepMonads._
import MyCustomMonads._
import scala.language.higherKinds
import scalaz.Scalaz._
val deepMonadExample: Option[Future[JsResult[String]]] = Some(Future.successful(JsSuccess("Hello")))
val deepMonadExample2: Option[Future[JsResult[Boolean]]] = Some(Future.successful(JsError(Nil)))
val deepMonadExample3: Option[Future[Option[Boolean]]] = Some(Future.successful(Some(true)))
val deepMonadExample4: Option[Future[JsResult[Boolean]]] = None
// Some(successful(JsSuccess("Result: true")))
val x = deepMonadExample.fmap {
"Result: " + _
}
// Some(successful(JsError()))
val x3 = deepMonadExample3.fmap {
"Result: " + _
}
// Some(successful(Some("Result: Hello")))
val x2 = deepMonadExample2.fmap {
"Result: " + _
}
// None
val x4 = deepMonadExample4.fmap {
"Result: " + _
}
}
If you can simplify your monad to 2 deep, you may be able to use Scalaz's stock standard monad transformers (as suggested in the comments, E.g. OptionT). I've seen them working at 2 deep quite well, but I've never used them in a more nested state though.
Looking at an IO Monad example from Functional Programming in Scala:
def ReadLine: IO[String] = IO { readLine }
def PrintLine(msg: String): IO[Unit] = IO { println(msg) }
def converter: IO[Unit] = for {
_ <- PrintLine("enter a temperature in degrees fahrenheit")
d <- ReadLine.map(_.toDouble)
_ <- PrintLine((d + 32).toString)
} yield ()
I decided to re-write converter with a flatMap.
def converterFlatMap: IO[Unit] = PrintLine("enter a temperate in degrees F").
flatMap(x => ReadLine.map(_.toDouble)).
flatMap(y => PrintLine((y + 32).toString))
When I replaced the last flatMap with map, I did not see the result of the readLine printed out on the console.
With flatMap:
enter a temperate in degrees
37.0
With map:
enter a temperate in degrees
Why? Also, how is the signature (IO[Unit]) still the same with map or flatMap?
Here's the IO monad from this book.
sealed trait IO[A] { self =>
def run: A
def map[B](f: A => B): IO[B] =
new IO[B] { def run = f(self.run) }
def flatMap[B](f: A => IO[B]): IO[B] =
new IO[B] { def run = f(self.run).run }
}
I think Scala converts IO[IO[Unit]] into the IO[Unit] in the second case. Try to run both variants in scala console, and don't specify type for the def converterFlatMap: IO[Unit], and you'll see the difference.
As for why map doesn't work, it is clearly seen from the definition of IO:
when you map over IO[IO[T]], map inside will call run only on the outer IO, result will be IO[IO[T]], so only first two PrintLine and ReadLine will be executed.
flatMap will also execute inner IO, and result will be IO[T] where T is the type parameter A of the inner IO, so all three of the statements will be executed.
P.S.: I think you incorrectly expanded for-comprehension. according to rules, for loop that you have written should be expanded to:
PrintLine("enter a temperate in degrees F").flatMap { case _ =>
ReadLine.map(_.toDouble).flatMap { case d =>
PrintLine((d + 32).toString).map { case _ => ()}
}
}
Notice that in this version flatMaps/maps are nested.
P.P.S: In fact last for statement should be also flatMap, not map. If we assume that scala had a "return" operator that puts values into the monadic context,
(e.g. return(3) will create IO[Int] that does nothing and it's function run returns 3.), then we can rewrite for (x <- a; y <- b) yield y as a.flatMap(x => b.flatMap( y => return(y))),
but because b.flatMap( y => return(y)) works absolutely the same as b.map(y => y) last statement in the scala for comprehension is expanded into map.
If I want to narrow, say, an Iterable[A] for all elements of a particular type (e.g. String) I can do:
as filter { _.isInstanceOf[String] }
However, it's obviously desirable to use this as an Iterable[String] which can be done via a map:
as filter { _.isInstanceOf[String] } map { _.asInstanceOf[String] }
Which is pretty ugly. Of course I could use flatMap instead:
as flatMap[String] { a =>
if (a.isInstanceOf[String])
Some(a.asInstanceOf[String])
else
None
}
But I'm not sure that this is any more readable! I have written a function, narrow, which can be used via implicit conversions:
as.narrow(classOf[String])
But I was wondering if there was a better built-in mechanism which I have overlooked. Particularly as it would be nice to be able to narrow a List[A] to a List[String], rather than to an Iterable[String] as it will be with my function.
The Scala syntax sugar for isInstanceOf / asInstanceOf is pattern matching:
as flatMap { case x: String => Some(x); case _ => None }
Because that uses flatMap, it should usually return the same collection you had to begin with.
On Scala 2.8, there's an experimental function that does that kind of pattern, defined inside the object PartialFunction. So, on Scala 2.8 you can do:
as flatMap (PartialFunction.condOpt(_ : Any) { case x: String => x })
Which looks bigger mostly because I did not import that function first. But, then again, on Scala 2.8 there's a more direct way to do it:
as collect { case x: String => x }
For the record, here's a full implementation of narrow. Unlike the signature given in the question, it uses an implicit Manifest to avoid some characters:
implicit def itrToNarrowSyntax[A](itr: Iterable[A]) = new {
def narrow[B](implicit m: Manifest[B]) = {
itr flatMap { x =>
if (Manifest.singleType(x) <:< m)
Some(x)
else
None
}
}
}
val res = List("daniel", true, 42, "spiewak").narrow[String]
res == Iterable("daniel", "spiewak")
Unfortunately, narrowing to a specific type (e.g. List[String]) rather than Iterable[String] is a bit harder. It can be done with the new collections API in Scala 2.8.0 by exploiting higher-kinds, but not in the current framework.
You may use in future:
for(a :Type <- itr) yield a
But it doesn't work now.
For more information, go to the following links:
http://lampsvn.epfl.ch/trac/scala/ticket/1089
http://lampsvn.epfl.ch/trac/scala/ticket/900
Shape preserving: I'm a bit rushed right now so I'm leaving the cast in there, but I'm pretty sure it can be eliminated. This works in trunk:
import reflect.Manifest
import collection.Traversable
import collection.generic.CanBuildFrom
import collection.mutable.ListBuffer
object narrow {
class Narrower[T, CC[X] <: Traversable[X]](coll: CC[T])(implicit m1: Manifest[CC[T]], bf: CanBuildFrom[CC[T], T, CC[T]]) {
def narrow[B: Manifest]: CC[B] = {
val builder = bf(coll)
def isB(x: T): Option[T] = if (Manifest.singleType(x) <:< manifest[B]) Some(x) else None
coll flatMap isB foreach (builder += _)
builder mapResult (_.asInstanceOf[CC[B]]) result
}
}
implicit def toNarrow[T, CC[X] <: Traversable[X]](coll: CC[T])(implicit m1: Manifest[CC[T]], bf: CanBuildFrom[CC[T], T, CC[T]]) =
new Narrower[T,CC](coll)
def main(args: Array[String]): Unit = {
println(Set("abc", 5, 5.5f, "def").narrow[String])
println(List("abc", 5, 5.5f, "def").narrow[String])
}
}
Running it:
Set(abc, def)
List(abc, def)