The Scala's `cats`

library has a bunch of operators. For this reason I decided to create a blog post that could act as quick reference for learning how to use all of them. This is inspired in the Cats Docs, but I added an explanation to each operator.

Also, you will find that I started describing some annotations and then some symbology used in the documentation or comments. I think this is useful because I was unsure of their meaning the first time I saw them.

`@specialized`

, `@sp`

`@speciallized`

(`@op`

for short) prevents the boxing of java primitive types and therefore the unnecessary instantiation of object in the heap. Even if scala has an unified typed system we need to manually use `@sp`

because the optimization can produce larger compilation times and bigger artifacts.

`@typeclass`

, `@op`

: simulacrum annotationsThe Simulacrum library provides `@typeclass`

and `@op`

to help us to define type-classes and operators.

`<->`

, `<=>`

: EquivalentIf you see the `<->`

or `<=>`

symbols in the comments, these likely represent "equivalency":

`<->`

: \$ \longleftrightarrow \$`<=>`

: \$ \Longleftrightarrow \$

And please don't get confused with the `pminus`

of Spire, that is unrelated.

For example, when you see: `IO.suspend(f) <-> IO(f).flatten`

what it really means is that `IO.suspend(f)`

is equivalent(\$ \longleftrightarrow \$) to `IO(f).flatten`

.

`>`

, `>=`

, `<`

, `<=`

: `PartialOrder[A]`

operatorsThe normal and expected order comparison operators:

`>`

:`gt(x: A, y: A): Boolean`

`>=`

:`gteqv(x: A, y: A): Boolean`

`<`

:`lt(x: A, y: A): Boolean`

`<=`

:`lteqv(x: A, y: A): Boolean`

We can use `ParialOrder[A]`

to compare the malevolence of our cats:

```
case class BadCat(kills: BigInt)
implicit val badCatPO = new PartialOrder[BadCat] {
override def partialCompare(x: BadCat, y: BadCat): Double =
implicitly[PartialOrder[BigInt]].partialCompare(x.kills,y.kills)
}
```

`*>`

, `<*`

, `<*>`

: `Apply[F[_]]`

operators`Apply`

in an `Applicative`

without `pure`

. It has 3 operators:

```
trait Apply[F[_]] {
// <*> applies the function to the value.
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
// *> Compose two actions, discarding any value produced by the first.
def productR[A, B](fa: F[A])(fb: F[B]): F[B] = ???
// <* Compose two actions, discarding any value produced by the second.
def productL[A, B](fa: F[A])(fb: F[B]): F[A] = ???
}
```

Here is an example of how we can apply a `F[A=>B]`

to a `F[A]`

and also discard values:

```
val multiply: Option[Int => Int] = Some{ _ * 2}
multiply <*> Some(4) /* Option[Int] = Some(8) */
1.some *> 2.some /* Option[Int] = Some(2) */
1.some <* 2.some /* Option[Int] = Some(1) */
```

Why would you want to discard your results? Maybe you don't care about the result but you do about the sequencing:

```
val p = IO(println("hi")) *> IO(println("bye"))
p.unsafeRunSync()
/* hi
/* bye
```

`<&`

, `&>`

: `Parallel[M[_], F[_]]`

operatorsA type that can represent a parallel relationship from a monad `M[_]`

and an applicative `F[_]`

.

`&>`

, is like `*>`

but for parallel

```
parProductR[A, B](ma: M[A])(mb: M[B]): M[B]
```

`<&`

, is like `<*`

but for parallel

```
parProductL[A, B](ma: M[A])(mb: M[B]): M[A]
```

`===`

, `=!=`

: `Eq[A]`

operators```
public boolean equals(Object anObject)
```

In Java we compare two object with `equals`

, it's basically a non-typed comparison. `Eq[A]`

gives us type safety for comparisons back.

```
trait Eq[@sp A] extends Any {
// ===
def eqv(x: A, y: A): Boolean
// =!=
def neqv(x: A, y: A): Boolean = !eqv(x, y)
}
```

We use `Eq`

for typed comparisons:

```
case class MutantDog(eyes: BigInt)
implicit val mutantEq = new Eq[MutantDog]{
override def eqv(x: MutantDog, y: MutantDog): Boolean =
x.eyes === y.eyes
}
MutantDog(1) === MutantDog(1) /* true */
MutantDog(1) === MutantDog(2) /* false */
MutantDog(1) == true /* false, but you shouldn't be able to do that */
MutantDog(1) === true /* doesn't compile */
```

`>>=`

, `>>`

: `FlatMap[F[_]]`

operatorsThe first operator `>>=`

is the `flatMap`

. The following example is pretty much like haskell's `>>=`

bind operator and `do`

-notation

```
(2.some >>= { x =>
Some(x * 2)
} >>= { x =>
Some(x + 1)
}) === (for {
a <- 2.some
b <- Some(a * 2)
c <- Some(b + 1)
} yield c) /* true */
```

`>>`

is the followed by operator, it has the following signature:

```
def >>[B](fb: => F[B])(implicit F: FlatMap[F]): F[B]
```

This does the same that `*>`

of `Apply[F[_]]`

does, but `fb`

is a by-name argument. You use this when you need to evaluate `fb`

inside `flatMap`

to ensure stack-safety.

`|-|`

,`|+|`

, `<+>`

`Group[A]`

is a `Monoid[A]`

where every element has an opposite. `Semigroup[A]`

wraps any `A`

with the associative operation `combine`

. `SemigroupK[F[_]]`

is like `Semigroup[A]`

but operates with type constructors `F[_]`

.

`|-|`

is the`remove(x: A, y: A): A`

for`Group[A]`

`|+|`

is the`combine(x: A, y: A): A`

for`Semigroup[A]`

`<+>`

is the`combineK(x: F[A], y: F[A]): F[A]`

for`Semigroup[F[_]]`

`<<<`

, `>>>`

: `Compose[F[_,_]]`

operators`>>>`

is the normal `andThen`

operator, it has the same logic than normal function composition `g(f(x))`

but is more general, you can use it for `F[_,_]`

s:

```
val map1 = Map( 1 -> "a", 2 -> "b")
val map2 = Map("a" -> true, "b" -> false)
val map3 = map1 >>> map2
map1(1) /* true */
map2(2) /* true */
```

finally `<<<`

is just like `>>>`

: `f <<< g`

\$ \longleftrightarrow \$ `f >>> g`

`***`

, `&&&`

: `Arrow[F[_,_]]`

operatorsWhen we talk about arrows the first operator we think about are the `>>>`

and `<<<`

but they are defined for `Compose[F[_,_]]`

right? Well...

`Compose[F[_,_]]`

brings`>>>`

and`<<<`

`Category[F[_,_]]`

extends`Compose[F[_,_]]`

`Arrow[F[_,_]]`

extends`Category[F[_,_]]`

therefore every arrow supports`>>>`

and`<<<`

.

But arrow gives us more:

`***`

```
split[A, B, C, D](f: F[A, B], g: F[C, D]): F[(A, C), (B, D)]
```

`&&&`

```
merge[A, B, C](f: F[A, B], g: F[A, C]): F[A, (B, C)]
```

```
type ⊥ = Nothing
type ⊤ = Any
type ~>[F[_], G[_]] = arrow.FunctionK[F, G]
type :<:[F[_], G[_]] = InjectK[F, G]
```