.some
and the corresponding constructor method none
for Option
;.asRight
, .asLeft
for Either
;.valid
, .invalid
, .validNel
, .invalidNel
for Validated
import cats.implicits._ Some("a") //Some[String] "a".some //Option[String]
Either
(see chapter 4.4.2 of the book Scala with Cats )..asRight
and .asLeft
still have one type parameter. For example, "1".asRight[Int]
is Either[Int, String]
. If you do not provide this parameter, the compiler will try to output it and get Nothing
. Still, it is more convenient than either to provide both parameters each time or not to provide either one, as in the case of constructors.Apply
method (that is, in Applicative
, Monad
, etc.), simply means “process the original calculation and replace the result with what is specified in the second argument”. In terms of code (in the case of Monad
): fa.flatMap(_ => fb)
Either
: import cats.implicits._ val success1 = "a".asRight[Int] val success2 = "b".asRight[Int] val failure = 400.asLeft[String] success1 *> success2 //Right(b) success2 *> success1 //Right(a) success1 *> failure //Left(400) failure *> success1 //Left(400)
Monix
, IO
and other similar Monix
. success1 <* success2 //Right(a)
productR
alias, and <is the productL
alias.productR
), there is also >> from FlatMapSyntax
. >> is defined in the same way as fa.flatMap(_ => fb)
, but with two nuances:productR
, and therefore, if for any reason the contract of this method changes (theoretically, it can be changed without violating monadic laws, but I am not sure about MonadError
), you will not suffer;fb: => F[B]
. The difference in semantics becomes fundamental if you perform calculations that can lead to a stack explosion.lift
. But when you succeed, you will find that it is everywhere.lift
comes from category theory . I will try to explain: take an operation, change the signature of its type so that it becomes directly related to the abstract type F. def lift[A, B](f: A => B): F[A] => F[B] = map(_)(f)
EitherT.liftF
is essentially EitherT.right.
Scaladoc example : import cats.data.EitherT import cats.implicits._ EitherT.liftF("a".some) //EitherT(Some(Right(a))) EitherT.liftF(none[String]) //EitherT(None)
lift
present in the standard Scala library everywhere. The most popular (and, perhaps, the most useful in daily work) example is PartialFunction
: val intMatcher: PartialFunction[Int, String] = { case 1 => "jak siÄ™ masz!" } val liftedIntMatcher: Int => Option[String] = intMatcher.lift liftedIntMatcher(1) //Some(jak siÄ™ masz!) liftedIntMatcher(0) //None intMatcher(1) //jak siÄ™ masz! intMatcher(0) //Exception in thread "main" scala.MatchError: 0
mapN
is a useful helper function for working with tuples. Again, this is not a novelty, but a replacement for the good old operator |@|
, he's “Scream”. // where t2: Tuple2[F[A0], F[A1]] def mapN[Z](f: (A0, A1) => Z)(implicit functor: Functor[F], semigroupal: Semigroupal[F]): F[Z] = Semigroupal.map2(t2._1, t2._2)(f)
import cats.implicits._ ("a".some, "b".some).mapN(_ ++ _) //Some(ab) (List(1, 2), List(3, 4), List(0, 2).mapN(_ * _ * _)) //List(0, 6, 0, 8, 0, 12, 0, 16)
leftmap
for tuples: ("a".some, List("b","c").mapN(_ ++ _)) //won't compile, because outer type is not the same ("a".some, List("b", "c")).leftMap(_.toList).mapN(_ ++ _) //List(ab, ac)
.mapN
is instantiating case classes: case class Mead(name: String, honeyRatio: Double, agingYears: Double) ("półtorak".some, 0.5.some, 3d.some).mapN(Mead) //Some(Mead(półtorak,0.5,3.0))
import cats.effect.IO import cats.implicits._ //interchangable with eg Monix's Task type Query[T] = IO[Option[T]] def defineMead(qName: Query[String], qHoneyRatio: Query[Double], qAgingYears: Query[Double]): Query[Mead] = (for { name <- OptionT(qName) honeyRatio <- OptionT(qHoneyRatio) agingYears <- OptionT(qAgingYears) } yield Mead(name, honeyRatio, agingYears)).value def defineMead2(qName: Query[String], qHoneyRatio: Query[Double], qAgingYears: Query[Double]): Query[Mead] = for { name <- qName honeyRatio <- qHoneyRatio agingYears <- qAgingYears } yield (name, honeyRatio, agingYears).mapN(Mead)
Nested
- in fact, a generalizing twin monadny transformers. As the name suggests, it allows you to perform attachments under certain conditions. Here is an example for .map(_.map( :
import cats.implicits._ import cats.data.Nested val someValue: Option[Either[Int, String]] = "a".asRight.some Nested(someValue).map(_ * 3).value //Some(Right(aaa))
Functor
, Nested
summarizes the operations Applicative
, ApplicativeError
and Traverse
. Additional information and examples are here .ApplicativeError
and MonadError
have several useful methods, and it may be useful for you to learn the subtle differences between the main four. So, with ApplicativeError F[A]:
handleError
converts all errors at the dial peer to A according to the specified function.recover
works in a similar way, but accepts partial functions, and therefore can convert to A errors you have selected.handleErrorWith
is similar to handleError
, but its result should look like F[A]
, which means it helps you convert errors.recoverWith
acts as recover, but also requires F[A]
as a result.handleErrorWith
and recoverWith
, which cover all possible functions. However, each method has its advantages and is convenient in its own way.cats.effect.IO
, monix.Task
, etc.Either/EitherT
, Validated
and Ior
- .valueOr
. In fact, it works like .getOrElse
for Option
, but it is generalized for classes that contain something “left”. import cats.implicits._ val failure = 400.asLeft[String] failure.valueOr(code => s"Got error code $code") //"Got error code 400"
Try
most popular in this project, because Try
, as you know, does not satisfy all monadic laws in terms of fatal errors. Now he is truly represented in the Cats.cats.x
for basic (kernel) types;cats.data
for data types like Validated, monad transformers, etc .;cats.instances.x.
_ to directly import the implementation of various timeclasses to the implicit scope for individual concrete types, so that when calling, for example, sth.pure, the error "implicit not found" does not occur.cats.implicits._
import, which imports all the syntax and all instances of the type class into the implicit scope. import cats._ import cats.data._ import cats.implicits._
cats.syntax.x
provides the extension syntax related to x;cats.instances.x
provides the cats.instances.x
instances..asRight
, which is an .asRight
method for Either
, do the following: import cats.syntax.either._ "a".asRight[Int] //Right[Int, String](a)
Option.pure
you must import cats.syntax.monad
And cats.instances.option
: import cats.syntax.applicative._ import cats.instances.option._ "a".pure[Option] //Some(a)
// , `pure`, // import cats.implicits._ import cats.instances.option._ "a".pure[Option] //could not find implicit value for parameter F: cats.Applicative[Option]
cats.implicits
and cats.instances.option
are extensions of cats.instances.OptionInstances
. In fact, we import its implicit scope twice, which confuses the compiler.cats.implicits
and explore the type hierarchy.cats
and scalaz
actively updated. Take cats as an example. Here are just the latest changes:Source: https://habr.com/ru/post/448128/
All Articles