I have four types A,B, C and D, an initial value x of the type Future[Option[A]] and three functions: f1: A => Option[B] , f2: B => Future[Option[C]] and f3: C => D.
How can I write a for comprehension starting with x that results in a value of the type Future[Option[D]] that would be the "composition" of the three functions?
You can use monad transformers (from Scalaz) for this:
import scalaz.OptionT
import scalaz.std.option._
import scalaz.syntax.monad._
val result: Future[Option[D]] = (for {
a <- OptionT(x)
b <- OptionT(f1(a).point[Future])
c <- OptionT(f2(b))
} yield f3(c)).run
You'll need a monad instance for Future; there's one in scalaz-contrib.
This isn't necessarily the best solution, but it's what I've come up with.
I started by trying to find a common type to work with
type N[X, Y] = Option[X] => Future[Option[Y]]
...then converting f1, f2, and f3 to that common type.
val f1: (A => Option[B]) = ???
val f1N: N[A, B] = {
case None => Future.successful(None)
case Some(a) => Future.successful(f1(a))
}
val f2: (B => Future[Option[C]]) = ???
val f2N: N[B, C] = {
case None => Future.successful(None)
case Some(b) => f2(b)
}
val f3: C => D = ???
val f3N: N[C, D] = {
case None => Future.successful(None)
case Some(c) => Future.successful(Some(f3(c)))
}
Now that I've created f1N, f2N, and f3N, I can use them in a nice-looking for-comprehension.
val y: Future[Option[D]] = for {
aOpt <- x
bOpt <- f1N(aOpt)
cOpt <- f2N(bOpt)
dOpt <- f3N(cOpt)
} yield dOpt
Related
What I'm trying to do is apply a sequence of transformations to a dataset where each function takes the output of the previous step and transforms it for the next step. E.g.
val f1: Function1[Int, Double] = _ / 2d
val f2: Function1[Double, BigDecimal] = x=>BigDecimal(x - 2.1)
val f3: Function1[BigDecimal, String] = _.toString
val chained = (f1 andThen f2 andThen f3)(_)
println(chained(10))
What I want is a function f that takes an input a Seq(f1, f2, ...) and returns the chaining of them, where f1, f2, ...fn do not all have the same input and the same output types T. But they are composable, so for example:
f1: Function1[A,B]
f2: Function1[B,C]
f3: Function1[C,D]
then the chaining function will return a function
f: [A,D].
Thanks,
Z
Two solution proposals here:
A solution that requires a special kind of list that can keep track of all the types in the chain of functions.
An asInstanceOf-heavy solution which works on ordinary lists.
Keeping track of all the types of intermediate results
An ordinary list would lose track of the types of all the intermediate results. Here is a list of functions that keeps track of all those types:
sealed trait Func1List[-In, +Res] {
def ::[I, O <: In](h: I => O): Func1List[I, Res] = ConsFunc1(h, this)
}
object Func1List {
def last[In, Res](f: In => Res): Func1List[In, Res] = LastFunc1(f)
def nil[A]: Func1List[A, A] = LastFunc1(identity)
}
case class LastFunc1[-In, +Res](f: In => Res)
extends Func1List[In, Res]
case class ConsFunc1[-In, Out, +Res](head: In => Out, tail: Func1List[Out, Res])
extends Func1List[In, Res]
Now, for a Func1List, we can define a function that concatenates all the elements:
def andThenAll[A, Z](fs: Func1List[A, Z]): A => Z = fs match {
case LastFunc1(f) => f
case c: ConsFunc1[A, t, Z] => c.head andThen andThenAll[t, Z](c.tail)
}
A little test:
val f1: Function1[Int, Double] = _ / 2d
val f2: Function1[Double, BigDecimal] = x => BigDecimal(x - 2.1)
val f3: Function1[BigDecimal, String] = _.toString
val fs = f1 :: f2 :: Func1List.last(f3)
val f = andThenAll(fs)
println(f(42)) // prints 18.9
Just asInstanceOf all the things
A somewhat less refined, but much shorter solution:
def andThenAll[X, Y](fs: List[_ => _]): X => Y = fs match {
case Nil => (identity[X] _).asInstanceOf[X => Y]
case List(f) => f.asInstanceOf[X => Y]
case hd :: tl => hd match {
case f: Function1[X #unchecked, o] => f andThen andThenAll[o, Y](tl)
}
}
This here also results in 18.9:
println(andThenAll[Int, String](List(f1, f2, f3))(42))
I've been trying to learn functional programming in Scala, and I finally managed to understand how to use the for comprehension to work with state:
#!/usr/bin/env scala
case class State[A,S](run: S => (A,S)) {
def map[B](f: A => B): State[B,S] =
State(s => {
val (a, s1) = run(s)
(f(a), s1)
})
def flatMap[B](f: A => State[B,S]): State[B,S] =
State(s => {
val (a,s1) = run(s)
f(a).run(s1)
})
}
val increment = State[Unit,Int] {
x => ((),x+1)
}
val read = State[Int,Int] {
x => (x,x)
}
def prog = for {
_ <- increment
x <- read
_ <- increment
y <- read
} yield (x,y)
val ans = prog.run(0)._1
println(ans)
Although this runs fine, I did not manage to do something similar using a state monad, it is more complicated than, e.g., Option, because it takes an extra type. How do I do something similar to this code with a state monad?
EDIT: Apparently, my question was not clear. I want to run this using a monad trait, like this one, which I took from "Functional programming in Scala":
def stateMonad[S] = new Monad[({type lambda[x] = State[S,x]})#lambda] {
def unit[A](a: => A): State[S,A] = State(s => (a, s))
def flatMap[A,B](st: State[S,A])(f: A => State[S,B]): State[S,B] =
st flatMap f
}
And then perform the computation by instantiating this with something like val M = stateMonad[Int].
After trying around, I managed to get it working. So, I think I'll end up answering my own question. The solution is
trait Monad[M[_]] {
def unit[A](a: => A): M[A]
def flatMap[A,B](ma: M[A])(f: A => M[B]): M[B]
}
class StateMonad[S] extends Monad[({type lambda[x] = State[x,S]})#lambda] {
def unit[A](a: => A): State[A,S] = State(s => (a, s))
def flatMap[A,B](st: State[A,S])(f: A => State[B,S]): State[B,S] =
st flatMap f
def increment: State[Unit,Int] = State(x => ((),x+1))
def read: State[Int,Int] = State(x => (x,x))
}
val m = new StateMonad[Int]
def prog = for {
_ <- m.increment
x <- m.read
_ <- m.increment
y <- m.read
} yield (x,y)
The idea is to make the StateMonad class inherit from Monad, and include all the functions that manipulate state as methods of the StateMonad class. As was pointed out, my previous code could already be considered a monad, but I think doing it this way is better.
Suppose I have functions like this:
val fooXAB: X => A => Try[B] = ...
val fooXBC: X => B => Try[C] = ...
val fooXCD: X => C => Try[D] = ...
I'd like to compose them to make a new function fooXAD: X => A => Try[D], which calls fooXAB, fooXBC, and fooXCD sequentially and pass the X argument to all of them.
Suppose I use scalaz and have a monad instance for scala.util.Try. Now I can do it this way:
type AB = Kleisli[Try, A, B]
type BC = Kleilsi[Try, B, C]
type CD = Kleisli[Try, C, D]
type XReader[T] = Reader[X, T]
val fooXAB: XReader[AB] = ...
val fooXBC: XReader[BC] = ...
val fooXCD: XReader[CD] = ...
val fooXAC: XReader[AC] =
for {
ab <- fooXAB
bc <- fooXBC
cd <- fooXCD
} yield (ab andThen bc andThen cd)
Does it make sense? Is it possible to simplify it ?
So I don't think the Reader Monad on the outer function helps here. once you apply and X to your threee XReaders, you can use Kleisli composition on the results (assuming you have a Monad instance for Try). Here's your example reworked this way, and it compiles for me:
import scala.util.{Try,Success}
import scalaz._
import Scalaz._
object A
object B
object C
object D
trait X
object Main {
implicit val pretendTryIsAMonad: Monad[Try] = new Monad[Try] {
def point[A](a: => A): Try[A] = Success(a)
def bind[A,B](fa: Try[A])(f: A => Try[B]): Try[B] = fa flatMap f
}
type AB = Kleisli[Try, A.type, B.type]
type BC = Kleisli[Try, B.type, C.type]
type CD = Kleisli[Try, C.type, D.type]
type AD = Kleisli[Try, A.type, D.type]
type XReader[T] = X => T
val fooXAB: XReader[AB] = (x: X) => Kleisli((a: A.type) => Success(B))
val fooXBC: XReader[BC] = (x: X) => Kleisli((b: B.type) => Success(C))
val fooXCD: XReader[CD] = (x: X) => Kleisli((c: C.type) => Success(D))
val fooXAD: XReader[AD] = (x: X) =>
fooXAB(x) >=> fooXBC(x) >=> fooXCD(x)
}
Suppose I've got the following three functions:
val f1: Int => Option[String] = ???
val f2: String => Option[Int] = ???
val f3: Int => Option[Int] = ???
I can compose them as follows:
val f: Int => Option[Int] = x =>
for {
x1 <- f1(x)
x2 <- f2(x1)
x3 <- f3(x2)
} yield x3
Suppose now that I need to keep the intermediate results of execution f1, f2, f3 and pass them to the caller:
class Result(x: Int) {
val r1 = f1(x)
val r2 = r1 flatMap f2
val r3 = r2 flatMap f3
def apply = r3
}
val f: Int => Result = x => new Result(x)
Does it make sense ? How would you improve/simplify this solution ?
Homogenous List
It's pretty simple for single type, suppose
val g1: Int => Option[Int] = x => if (x % 2 == 1) None else Some(x / 2)
val g2: Int => Option[Int] = x => Some(x * 3 + 1)
val g3: Int => Option[Int] = x => if (x >= 4) Some(x - 4) else None
You can define
def bind[T]: (Option[T], T => Option[T]) => Option[T] = _ flatMap _
def chain[T](x: T, fs: List[T => Option[T]]) = fs.scanLeft(Some(x): Option[T])(bind)
And now
chain(4, g1 :: g2 :: g3 :: Nil)
will be
List(Some(4), Some(2), Some(7), Some(3))
preserving all intermediate values.
Heterogenous List
But we can do if there are multiple types involved?
Fortunately there is shapeless library for special structures named Heterogenous List which could handle list-like multi-typed sequences of values.
So suppose we have
import scala.util.Try
val f1: Int => Option[String] = x => Some(x.toString)
val f2: String => Option[Int] = x => Try(x.toInt).toOption
val f3: Int => Option[Int] = x => if (x % 2 == 1) None else Some(x / 2)
Lets define heterogenous analogues to previous functions:
import shapeless._
import ops.hlist.LeftScanner._
import shapeless.ops.hlist._
object hBind extends Poly2 {
implicit def bind[T, G] = at[T => Option[G], Option[T]]((f, o) => o flatMap f)
}
def hChain[Z, L <: HList](z: Z, fs: L)
(implicit lScan: LeftScanner[L, Option[Z], hBind.type]) =
lScan(fs, Some(z))
And now
hChain(4, f1 :: f2 :: f3 :: HNil)
Evaluates to
Some(4) :: Some("4") :: Some(4) :: Some(2) :: HNil
Class converter
Now if you urged to save your result in some class like
case class Result(init: Option[Int],
x1: Option[String],
x2: Option[Int],
x3: Option[Int])
You could easily use it's Generic representation
just ensure yourself that
Generic[Result].from(hChain(4, f1 :: f2 :: f3 :: HNil)) ==
Result(Some(4),Some("4"),Some(4),Some(2))
How can I change list of Eithers into two list of value Right and Left. When I use partition it returns two lists of Either's not values. What is the simplest way to do it?
foldLeft allows you to easily write your own method:
def separateEithers[T, U](list: List[Either[T, U]]) = {
val (ls, rs) = list.foldLeft(List[T](), List[U]()) {
case ((ls, rs), Left(x)) => (x :: ls, rs)
case ((ls, rs), Right(x)) => (ls, x :: rs)
}
(ls.reverse, rs.reverse)
}
You'll have to map the two resulting lists after partitioning.
val origin: List[Either[A, B]] = ???
val (lefts, rights) = origin.partition(_.isInstanceOf[Left[_]])
val leftValues = lefts.map(_.asInstanceOf[Left[A]].a)
val rightValues = rights.map(_.asInstanceOf[Right[B]].b)
If you are not happy with the casts and isInstanceOf's, you can also do it in two passes:
val leftValues = origin collect {
case Left(a) => a
}
val rightValues = origin collect {
case Right(b) => b
}
And if you are not happy with the two passes, you'll have to do it "by hand":
def myPartition[A, B](origin: List[Either[A, B]]): (List[A], List[B]) = {
val leftBuilder = List.newBuilder[A]
val rightBuilder = List.newBuilder[B]
origin foreach {
case Left(a) => leftBuilder += a
case Right(b) => rightBuilder += b
}
(leftBuilder.result(), rightBuilder.result())
}
Finally, if you don't like mutable state, you can do so:
def myPartition[A, B](origin: List[Either[A, B]]): (List[A], List[B]) = {
#tailrec
def loop(xs: List[Either[A, B]], accLeft: List[A],
accRight: List[B]): (List[A], List[B]) = {
xs match {
case Nil => (accLeft.reverse, accRight.reverse)
case Left(a) :: xr => loop(xr, a :: accLeft, accRight)
case Right(b) :: xr => loop(xr, accLeft, b :: accRight)
}
}
loop(origin, Nil, Nil)
}
If making two passes through the list is okay for you, you can use collect:
type E = Either[String, Int]
val xs: List[E] = List(Left("foo"), Right(1), Left("bar"), Right(2))
val rights = xs.collect { case Right(x) => x}
// rights: List[Int] = List(1, 2)
val lefts = xs.collect { case Left(x) => x}
// lefts: List[String] = List(foo, bar)
Using for comprehensions, like this,
for ( Left(v) <- xs ) yield v
and
for ( Right(v) <- xs ) yield v