Fantastic Monads and where to find them

Jakub Kozłowski - Scala Developer @ Scalac

ScalaUA - Kiev, April 8, 2017

Scala

focusing on functional programming

rich type system, implicits, type inference

reducing boilerplate

Typelevel

Cats

typelevel project

"Lightweight, modular, and extensible library for functional programming"

Inspired by Scalaz

Provides type classes, instances and data structures

Using Cats

Excellent docs at

http://typelevel.org/cats/typeclasses.html

http://typelevel.org/cats/datatypes.html

Type classes

trait Addable[T]{
  def add(a: T, b: T): T
}

implicit val IntAddable: Addable[Int] = new Addable[Int]{
  override def add(a: Int, b: Int): Int = a + b
}

def addThree[T](a: T, b: T, c: T)(implicit addable: Addable[T]): T =
  addable.add(addable.add(a, b), c)

Type class syntax

trait Semigroup[T]{
  def combine(a: T, b: T): T
}

object Semigroup {
  def apply[T : Semigroup]: Semigroup[T] = implicitly[Semigroup[T]]
}

//scala 2.12 SAM syntax
implicit val StringSemigroup: Semigroup[String] = _ + _

def combineAll[T : Semigroup](elems: NonEmptyList[T]): T =
  elems.reduceLeft(Semigroup[T].combine)

Standard library samples

//Ordering
list.sorted
//Numeric
list.sum

Type classes in Cats

Functor

Applicative

Monad

Traverse

...many many more, but these are important for the samples

Functor

trait Functor[F[_]]{
  def map[T, U](ts: F[T])(f: T => U): F[U]
}
def mapPlusOne[F[_] : Functor](ints: F[Int]): F[Int] =
  Functor[F].map(ints)(_ + 1)
or...

import cats.syntax.functor._
def mapPlusOne[F[_] : Functor](ints: F[Int]): F[Int] =
  ints.map(_ + 1)
mapPlusOne(List(1, 2, 3)) // List(2, 3, 4)
mapPlusOne(Option(3)) // Some(4): Option[Int]
mapPlusOne(none[Int]) //None: Option[Int]

Applicative

trait Applicative[F[_]] extends Functor[F]{ //simplified
  def pure[A](x: A): F[A]

  def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
}

M-word

trait Monad[F[_]] extends Applicative[F]{
  def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
}

Traverse

trait Traverse[F[_]] extends Functor[F]{
  def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]
}
def sequence[G[_]: Applicative, A](fa: F[G[A]]): G[F[A]]
x.traverse(f) == x.map(f).sequence
x.sequence = x.traverse(identity)

Data types in Cats

Validated

Monad transformers (OptionT)

Validated

trait Validated[+E, +A]
case class Valid[+A](a: A) extends Validated[Nothing, A]
case class Invalid[+E](a: E) extends Validated[E, Nothing]
case class NonEmptyList[A](head: A, tail: List[A])
type ValidatedNel[E, A] = Validated[NonEmptyList[E], A]

Bonus slide with things I forgot

Why

trait BookService[M[_]]

Because

type Id[A] = A

is also a monad

Tests!

>> BookServiceTests.scala <<

Looks better than tens of Future.successful

Links

herding cats

Typeclasses in Scala (pending!)

typeclasses in cats (cats docs)

datatypes in cats (cats docs)

Scala Wave 2017 scalawave.io

Thank you!

Questions?

Please vote on vote.scalaua.com

Slides: kubukoz.github.io/fantastic-monads-slides

Code: github.com/kubukoz/fantastic-monads-code


Contact me:

@kubukoz

| kubukoz@gmail.com

| kubukoz.com