I've started learning functional programming with Cats and I stuck with flatMapping (merging) applicatives F[List].
What is very simple in pure Scala is flatmapping list of lists like that:
val animals = List("Dog", "Cat", "Bird")
def getBreads(animal: String): List[String] = ...
val allAnimalsBreads = animals.flatMap(animal => getBread(animal)) // this will be just List[String]
How can I do the same if everything is wrapped with applicative?:
val animals = List("Dog", "Cat", "Bird").pure[F]
def getBreads(animal: String): F[List[String]] = ...
val allAnimalsBreads = ? // this should be F[List[String]]
Applicative provides ap and pure, but does not guarantee to provide flatMap, which is provided by Monad:
Monad extends the Applicative type class with a new function flatten.
If F was a monad, then at least in scalaz we might use ListT, for example,
import scalaz._
import ListT._
import scalaz.std.option._
val animals: Option[List[String]] = Some(List("Dog", "Cat", "Bird"))
def getBreeds(animal: String): Option[List[String]] = ???
(for {
animal <- listT(animals)
breed <- listT(getBreeds(animal))
} yield breed).run
However cats does not seem to provide ListT:
A naive implementation of ListT suffers from associativity issues; ... It’s possible to create a ListT that doesn’t
have these issues, but it tends to be pretty inefficient. For many
use-cases, Nested can be used to achieve the desired results.
Here is an attempt at a mad solution that you should not use. Consider Validated which only has Applicative instance. Let us provide a Monad instance even though Validated is not a Monad:
implicit def validatedMonad[E]: Monad[Validated[E, *]] =
new Monad[Validated[E, *]] {
def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
fa match {
case Valid(a) => f(a)
case i # Invalid(_) => i
}
def pure[A](x: A): Validated[E, A] = Valid(x)
def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]) = ???
}
The implementation of validatedMonad is taken from scala-exercises.org/cats/validated.
Next let us make scalaz's listT available within cats via shims interop layer
libraryDependencies += "com.codecommit" %% "shims" % "2.1.0"
Putting it all together, we have
import cats._
import cats.Monad
import cats.data.Validated.{Invalid, Valid}
import cats.data.{Nested, OptionT, Validated, ValidatedNec}
import cats.implicits._
import scalaz.ListT._
import shims._
implicit def validatedMonad[E]: Monad[Validated[E, *]] =
new Monad[Validated[E, *]] {
def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
fa match {
case Valid(a) => f(a)
case i # Invalid(_) => i
}
def pure[A](x: A): Validated[E, A] = Valid(x)
def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]) = ???
}
val animals: Validated[String, List[String]] = List("Dog", "Cat", "Bird").valid
def getBreeds(animal: String): Validated[String, List[String]] = ???
(for {
animal <- listT(animals)
breed <- listT(getBreeds(animal))
} yield breed).run
Note this "solution" breaks monadic laws, is not general, and is likely to cause confusion, so do not use it.
For Applicative this is impossible. For Monad if you don't want to use unconventional transformer ListT you can do
import cats.syntax.traverse._
import cats.syntax.applicative._
import cats.syntax.functor._
import cats.syntax.flatMap._
import cats.instances.list._
val allAnimalsBreads: F[List[String]] =
animals.map(_.map(getBreads)) // F[List[F[List[String]]]]
.map(_.sequence) // F[F[List[List[String]]]]
.flatten // F[List[List[String]]]
.map(_.flatten) // F[List[String]]
Related
I'm reading the scala-with-cats book and follow it's exercise. When I come to the case study: data validation, I encounter some problems.
Here is my entire code (just the same with the book):
package org.scala.ch10.final_recap
import cats.Semigroup
import cats.data.Validated
import cats.data.Validated._
import cats.data.Kleisli
import cats.data.NonEmptyList
import cats.instances.either._
import cats.syntax.apply._
import cats.syntax.semigroup._
import cats.syntax.validated._
sealed trait Predicate[E, A] {
import Predicate._
def and(that: Predicate[E, A]): Predicate[E, A] =
And(this, that)
def or(that: Predicate[E, A]): Predicate[E, A] =
Or(this, that)
/**
* This part is for Kleislis
* #return
*/
def run(implicit s: Semigroup[E]): A => Either[E, A] =
(a: A) => this(a).toEither
def apply(a: A)(implicit s: Semigroup[E]): Validated[E, A] =
this match {
case Pure(func) =>
func(a)
case And(left, right) => (left(a), right(a)).mapN((_, _) => a)
case Or(left, right) =>
left(a) match {
case Valid(_) => Valid(a)
case Invalid(e1) =>
right(a) match {
case Valid(_) => Invalid(e1)
case Invalid(e2) => Invalid(e1 |+| e2)
}
}
}
}
object Predicate {
final case class And[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
final case class Or[E, A](left: Predicate[E, A], right: Predicate[E, A]) extends Predicate[E, A]
final case class Pure[E, A](func: A => Validated[E, A]) extends Predicate[E, A]
def apply[E, A](f: A => Validated[E, A]): Predicate[E, A] = Pure(f)
def lift[E, A](err: E, fn: A => Boolean): Predicate[E, A] = Pure(a => if(fn(a)) a.valid else err.invalid)
}
object FinalRecapPredicate {
type Errors = NonEmptyList[String]
def error(s: String): NonEmptyList[String] = NonEmptyList(s, Nil)
type Result[A] = Either[Errors, A]
type Check[A, B] = Kleisli[Result, A, B]
def check[A, B](func: A => Result[B]): Check[A, B] = Kleisli(func)
def checkPred[A](pred: Predicate[Errors, A]): Check[A, A] =
Kleisli[Result, A, A](pred.run)
def longerThan(n: Int): Predicate[Errors, String] =
Predicate.lift(
error(s"Must be longer than $n characters"),
str => str.length > n
)
val alphanumeric: Predicate[Errors, String] =
Predicate.lift(
error(s"Must be all alphanumeric characters"),
str => str.forall(_.isLetterOrDigit)
)
def contains(char: Char): Predicate[Errors, String] =
Predicate.lift(
error(s"Must contain the character $char"),
str => str.contains(char)
)
def containsOnce(char: Char): Predicate[Errors, String] =
Predicate.lift(
error(s"Must contain the character $char only once"),
str => str.count(_ == char) == 1
)
val checkUsername: Check[String, String] = checkPred(longerThan(3) and alphanumeric)
val splitEmail: Check[String, (String, String)] = check(_.split('#') match {
case Array(name, domain) =>
Right((name, domain))
case _ =>
Left(error("Must contain a single # character"))
})
val checkLeft: Check[String, String] = checkPred(longerThan(0))
val checkRight: Check[String, String] = checkPred(longerThan(3) and contains('.'))
val joinEmail: Check[(String, String), String] =
check {
case (l, r) => (checkLeft(l), checkRight(r)).mapN(_ + "#" + _)
}
val checkEmail: Check[String, String] = splitEmail andThen joinEmail
final case class User(username: String, email: String)
def createUser(username: String, email: String): Either[Errors, User] =
(checkUsername.run(username),
checkEmail.run(email)).mapN(User)
def main(args: Array[String]): Unit = {
println(createUser("", "noel#underscore.io#io"))
}
}
It supposes the code should end up with the error message Left(NonEmptyList(Must be longer than 3 characters), Must contain a single # character) But what I actually is Left(NonEmptyList(Must be longer than 3 characters))
Obviously, it does not work as expected. It fails fast instead of accumulating errors... How to fix that plz? (I've spent hours now and can't get a workaround)
This is the "problematic" part:
def createUser(username: String, email: String): Either[Errors, User] =
(checkUsername.run(username),
checkEmail.run(email)).mapN(User)
You are combining a tuple of Results, where
type Result[A] = Either[Errors, A]
This means you are really doing a mapN on a pair of Eithers, an operation provided by the Semigroupal type class. This operation will not accumulate results.
There are several reasons for this, but one that I find particularly important is the preserving of behaviour if we find ourselves using a Semigroupal / Applicative which also happens to be a Monad. Why is that a problem? Because Monads are sequencing operations, making each step depend on the previous one, and having "fail early" semantics. When using some Monad, one might expect those semantics to be preserved when using constructs from the underlying Applicative (every Monad is also an Applicative). In that case, if the implementation of Applicative used "accumulation" semantics instead of "fail early" semantics, we would ruin some important laws like referential transparency.
You can use a parallel version of mapN, called parMapN, whose contract guarantees that the implementation will be evaluating all results in parallel. This means that it definitely cannot be expected to have the "fail early" semantics, and accumulating results is fine in that case.
Note that Validated accumulates results as well, usually in a NonEmptyList or a NonEmptyChain. This is probably why you expected to see your accumulated results; the only problem is, you were not using Validated values in the "problematic" part of your code, but raw Eithers instead.
Here's some simple code that demonstrates the above concepts:
import cats.data._
import cats.implicits._
val l1: Either[String, Int] = Left("foo")
val l2: Either[String, Int] = Left("bar")
(l1, l2).mapN(_ + _)
// Left(foo)
(l1, l2).parMapN(_ + _)
// Left(foobar)
val v1: ValidatedNel[String, Int] = l1.toValidatedNel
val v2: ValidatedNel[String, Int] = l2.toValidatedNel
(v1, v2).mapN(_ + _)
// Invalid(NonEmptyList(foo, bar))
Given:
import cats.syntax.cartesian._
type M[X] = Future[Either[Error, X]]
val ma: M[A] = ???
val mb: M[B] = ???
I know I can do that:
def doStuff(a: A, b: B): C = ???
val result: M[C] = (ma |#| mb).map(doStuff)
But how do I flatMap? There's no flatMap in the CartesianBuilders.
def doFancyStuff(a: A, b: B): M[C] = ???
val result: M[C] = (ma |#| mb).flatMap(doFancyStuff)
I think the main problem is that it's awkward to flatMap on a Future[Either[Error, X]] in the sense of EitherT[Future, Error, X]-monad stack, because the original flatMap of the Future gets in the way, and the compiler isn't looking for a monad instance that could handle the combination of Future and Either simultaneously. However, if you wrap the futures in EitherT, everything works smoothly.
For cats 1.0.1
In the following, (a,b).tupled corresponds to Cartesian.product(a, b), and (a, b).mapN corresponds to the deprecated (a |#| b).map.
Given types A, B, C, Error, the following code snippets compile under cats 1.0.1:
If you want to preserve your definition of M (you probably should), then you
can avoid the above mentioned problems by wrapping everything in EitherT and then
extracting the value:
import scala.util.Either
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global // required by Monad[Future]
import cats.instances.future._ // Monad for `Future`
import cats.syntax.apply._ // `tupled` and `mapN`
import cats.data.EitherT // EitherT monad transformer
type M[X] = Future[Either[Error, X]]
val ma: M[A] = ???
val mb: M[B] = ???
def doStuff(a: A, b: B): C = ???
val result1: M[C] = (EitherT(ma), EitherT(mb)).mapN(doStuff).value
def doFancyStuff(a: A, b: B): M[C] = ???
val result2: M[C] = (for {
ab <- (EitherT(ma), EitherT(mb)).tupled
c <- EitherT(doFancyStuff(ab._1, ab._2))
} yield c).value
However, if this seems too awkward, and you can adjust the definition of M,
the following variant could be slightly shorter:
import scala.util.Either
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global // required by Monad[Future]
import cats.instances.future._ // Monad for `Future`
import cats.syntax.apply._ // `tupled` and `mapN`
import cats.data.EitherT // EitherT monad transformer
type M[X] = EitherT[Future, Error, X]
val ma: M[A] = ??? // either adjust signatures, or wrap result in EitherT(res)
val mb: M[B] = ???
def doStuff(a: A, b: B): C = ???
val result1: M[C] = (ma, mb).mapN(doStuff)
def doFancyStuff(a: A, b: B): M[C] = ???
val result2: M[C] = (ma, mb).tupled.flatMap{
case (a, b) => doFancyStuff(a, b)
}
This is because (ma, mb).tupled builds a M[(A, B)], where M is the previously mentioned monad stack, which then can be easily flatMapped with a (A, B) => M[C] function to M[C].
For older versions with Cartesian (untested)
Assuming that (ma, mb).tupled corresponds to the deprecated Cartesian.product and (ma, mb).mapN corresponds to the deprecated (ma |#| mb).map, the two definitions of result1 and result2 in the above code snippet for 1.0.1 translate to:
val result1: M[C] = (ma |#| mb).map(doStuff)
val result2: M[C] = Cartesian[M].product(ma, mb).flatMap{
case (a, b) => doFancyStuff(a, b)
}
Again, this works only because Cartesian[M].product(ma, mb) builds an M[(A, B)] from M[A] and M[B], where M[X] is defined as EitherT[Future, Error, X]. If it were defined as Future[Either[Error, X]], then the flatMap would be invoked on the Future, and instead of doFancyStuff we would have to pass something like Either[Error, (A, B)] => Future[Either[Error, C]], which is probably not what you want.
I am looking at this question from Scala and Scalaz angles. OptionT works for Future but not Try. What is the reason there is no OptionT for Try where there is a usecase a function i.e. def foo(i: Int): Try[Option[Int]] = ... may or not return a value and occasionally network exception will happen? Thanks
The reason is Try isn't a valid functor.
You'll need to use scalaz-outlaws or write your own Try instances. Here's a working example using scalaz-outlaws' Try instances:
import scala.util.{Try,Success,Failure}
import scalaz._
import Scalaz._
implicit val tryOutlawInstances = new Traverse[Try] with Monad[Try] with Plus[Try]{
def point[A](a: ⇒ A): Try[A] = Success(a)
override def map[A,B](fa: Try[A])(f: A ⇒ B) = fa map f
def bind[A,B](fa: Try[A])(f: A ⇒ Try[B]) = fa flatMap f
def traverseImpl[F[_], A, B](fa: Try[A])(f: A ⇒ F[B])(implicit F: Applicative[F]) : F[Try[B]] = fa match {
case Success(a) ⇒ F.map(f(a))(Success.apply)
case Failure(f) ⇒ F.point(Failure(f))
}
def plus[A](a: Try[A], b: ⇒ Try[A]) = a orElse b
}
val foo = Try("foo".some)
val result = OptionT(foo).map(x => x.toUpperCase).run
I've used cats for the first time to solve day 1 of advent of code and I'm wondering if it's possible to improve things.
Given a method update with the following signature
def update(i: Instruction): PosAndDir => PosAndDir
I've come up with :
val state: State[PosAndDir, List[Unit]] = instructions.map(i => State.modify(update(i))).toList.sequenceU
val finalState = state.runS(PosAndDir(Pos(0, 0), North)).value
And also
def update2(i: Instruction): State[PosAndDir, Option[Pos]] =
State.modify(update(i)).inspect(pad => if (i == Walk) Some(pad.pos) else None)
…
val state = instructions.map(update2).toList.sequenceU
val positions = state.runA(PosAndDir(Pos(0, 0), North)).value.flatten
More precisely, questions are :
why do we need to call .value (with scalaz, it's transparent) ?
is there a way to write update2 with a for comprehension to improve readability ?
is there an Applicative instance for Seq in cats (I know there is not in scalaz). ?
any idea to improve the code ?
cats defines State[S, A] as an alias for stack-safe StateT[Eval, S , A] which is StateT[Trampoline, S, A] in scalaz terms, so runS returns Eval[A], where value will be run without stackoverflow even for very long flatMap sequences.
Using some more additional imports
import cats.data.{State, StateT}
import cats.MonadState
import cats.syntax.functorFilter._
import cats.instances.option._
and some preparations
type Walk[x] = StateT[Option, PosAndDir, x]
val stateMonad = MonadState[Walk, PosAndDir]
import stateMonad._
you can make your function look like this
def update2(i: Instruction): StateT[Option, PosAndDir, Pos] =
for (pad ← get if i == Walk) yield pad.pos
not that this solution will not work in 2.12 due to this improvement, you can make it work with this workaround
implicit class FunctorWithFilter[F[_] : FunctorFilter, A](fa: F[A]) {
def withFilter(f: A ⇒ Boolean) = fa.filter(f)
}
There is no instances for Seq, this answer describes why. While there are some non-orthodox instances in the alleycats project. I'm not really sure if you need for Applicative[Seq], from your code you are rather have need for Traverse[Seq], or if you replace your sequence with sequence_ even Foldable[Seq].
Good news there is Foldable[Iterable] in the alleycats, and here is my attempt to define something lookalike for Seq instance
implicit val seqInstance = new MonadFilter[Seq] with Traverse[Seq] {
def traverse[G[_] : Applicative, A, B](fa: Seq[A])(f: (A) ⇒ G[B]): G[Seq[B]] =
fa match {
case head +: tail ⇒ f(head).map2(traverse(tail)(f))(_ +: _)
case _empty ⇒ Seq.empty[B].pure[G]
}
def foldLeft[A, B](fa: Seq[A], b: B)(f: (B, A) ⇒ B): B = fa.foldLeft(b)(f)
def foldRight[A, B](fa: Seq[A], lb: Eval[B])(f: (A, Eval[B]) ⇒ Eval[B]): Eval[B] =
fa match {
case head +: tail ⇒ f(head, foldRight(tail, lb)(f))
case _empty ⇒ lb
}
def pure[A](x: A): Seq[A] = Seq(x)
def empty[A]: Seq[A] = Seq.empty[A]
def flatMap[A, B](fa: Seq[A])(f: (A) ⇒ Seq[B]): Seq[B] = fa.flatMap(f)
def tailRecM[A, B](a: A)(f: (A) ⇒ Seq[Either[A, B]]): Seq[B] = {
#tailrec def go(seq: Seq[Either[A, B]]): Seq[B] =
if (seq.contains((_: Either[A, B]).isLeft))
go(seq.flatMap {
case Left(a) ⇒ f(a)
case b ⇒ Seq(b)
}) else seq.collect { case Right(b) ⇒ b }
go(Seq(Left(a)))
}
override def mapFilter[A, B](fa: Seq[A])(f: (A) ⇒ Option[B]): Seq[B] =
fa.flatMap(f(_).toSeq)
}
didn't spent much time but here is my attempt to simplifying some parts via the Monocle library:
import cats.{MonadState, Foldable, Functor}
import cats.instances.option._
import cats.syntax.foldable._
import cats.syntax.functor._
import cats.syntax.functorFilter._
import monocle.macros.Lenses
#Lenses
case class Pos(x: Int, y: Int)
sealed abstract class Dir(val cmd: Pos ⇒ Pos)
case object South extends Dir(Pos.y.modify(_ - 1))
case object North extends Dir(Pos.y.modify(_ + 1))
case object East extends Dir(Pos.x.modify(_ + 1))
case object West extends Dir(Pos.x.modify(_ - 1))
#Lenses
case class PosAndDir(pos: Pos, dir: Dir)
val clockwise = Vector(North, East, South, West)
val right: Map[Dir, Dir] = clockwise.zip(clockwise.tail :+ clockwise.head).toMap
val left: Map[Dir, Dir] = right.map(_.swap)
sealed abstract class Instruction(val cmd: PosAndDir ⇒ PosAndDir)
case object TurnLeft extends Instruction(PosAndDir.dir.modify(left))
case object TurnRight extends Instruction(PosAndDir.dir.modify(right))
case object Walk extends Instruction(pd ⇒ PosAndDir.pos.modify(pd.dir.cmd)(pd))
def runInstructions[F[_] : Foldable : Functor](instructions: F[Instruction])(start: PosAndDir): PosAndDir =
instructions.map(i => State.modify(i.cmd)).sequence_.runS(start).value
Is there a way to convert a
Either[A, Future[B]]
to a
Future[Either[A, B]]
I have in mind something like the Future.sequence method which converts from a List[Future] to a Future[List]
Not sure there's an out of the box solution, this is what I came up with:
def foldEitherOfFuture[A, B](e: Either[A, Future[B]]): Future[Either[A, B]] =
e match {
case Left(s) => Future.successful(Left(s))
case Right(f) => f.map(Right(_))
}
In addition to catch eventual exception from the Future you can add a recover and map it to a Left:
case Right(f) => f.map(Right(_)).recover { case _ => Left(/** some error*/) }
There is no api functional call to do that. I'd try something like this:
def getResult[A, B]: Either[A, Future[B]] = ???
val res = getResult.fold(fa = l => Future(Left(l)), fb = r => r.map(value => Right(value)))
If you're using scalaz, you can just use sequenceU
import scala.concurrent.ExecutionContext.Implicits.global
import scalaz._
import Scalaz._
val x: Either[String, Future[Int]] = ???
val y: Future[Either[String, Int]] = x.sequenceU
Update (August 2019):
If you're using cats, use sequence:
import cats.implicits._
import scala.concurrent.ExecutionContext.Implicits.global
val x: Either[String, Future[Int]] = ???
val y: Future[Either[String, Int]] = x.sequence
Dumonad adds a set of extension methods to ease of reactive programming:
import io.github.dumonad.dumonad.Implicits._
val eitherOfFuture: Either[L,Future[R]]
val futureOfEither: Future[Either[L,R]] = eitherOfFuture.extractFuture