# Practical Scalaz

Gregg Hernandez <gregg@lucidchart.com>

golucid.co

golucid.co

golucid.co

# Scalaz

An extension to the core Scala library for functional programming.

## imports

``````import scalaz._
import Scalaz._``````

## imports

``````import scalaz.std.option._
import scalaz.std.list._
import scalaz.std.int._
// etc.``````

## Boolean

``import scalaz.syntax.std.boolean._``

## Boolean

``````def runQuery(count: Option[Int]) = ???

val limit = 10
val limitQuery = true

val count =
if (limitQuery) Some(limit) else None

runQuery(count)``````

## Boolean

``````def runQuery(count: Option[Int]) = ???

val limit = 10
val limitQuery = true

runQuery(limitQuery.option(limit))``````

## Boolean

``````def getOne() = ???
def getAll() = ???

val all = true

if (all) {
getAll()
} else {
getOne()
}``````

## Boolean

``````def getOne() = ???
def getAll() = ???

val all = true

all.fold(getAll(), getOne())``````

## Boolean

``````def close(): Unit = ???

val doorIsOpen = true

when(doorIsOpen)(close()) // closes door``````

## Boolean

``````def close(): Unit = ???

val doorIsOpen = true

unless(doorIsOpen)(close()) // does nothing``````

## Equal

``````import scalaz.syntax.equal._
``````

## Equal

``1 == "1"``

## Equal

``````1 == "1"

[warn] comparing values of types Int and String
[warn] using `==' will always yield false
[warn]     1 == "1"
[warn]       ^``````

## Equal

``"1" == 1``

## Equal

``````"1" == 1 // compiles with no errors or warnings
// always false

if ("1" == 1) {
println("this will never print")
}``````

## Equal

``````boolean	equals(Object obj)

def ==(arg: Any): Boolean``````

## Equal

``````class EqualOps[F] {
def ===(other: F): Boolean
}``````

## Equal

``````1 === "1"

"1" === 1``````

## Equal

``````1 === "1"
[error]  found   : String("1")
[error]  required: Int
[error]     1 === "1"
[error]           ^

"1" === 1
[error]  found   : Int(1)
[error]  required: String
[error]     "1" === 1
[error]             ^``````

## Equal

``````class Foo(val a: String, val b: Int)
object Foo {
implicit eq = Equal.equal[Foo] { (x, y) =>
x.a === y.a && x.b === y.b
}
}

new Foo("hi", 1) === new Foo("hi", 1) // true``````

## Equal

``````case class Foo(a: String, b: Int)
object Foo {
implicit eq = Equal.equalA[Foo]
}

Foo("hi", 1) === Foo("hi", 1) // true``````

# Memo

## Memo

``````def slowFib(n: Int): Int = n match {
case 0 => 0
case 1 => 1
case n => slowFib(n - 2) + slowFib(n - 1)
}

slowFib(30)
slowFib(40)
slowFib(45)

[success] Total time: 7 s``````

## Memo

``````val cache = mutable.Map.empty[Int, Int]

def slowFib(n: Int): Int = {
if (!cache.contains(n)) {
cache(n) = n match {
case 0 => 0
case 1 => 1
case n => slowFib(n - 2) + slowFib(n - 1)
}
}

cache(n)
}``````

## Memo

``````lazy val memoizedFib: Int => Int = {
Memo.mutableHashMapMemo[Int, Int] { n =>
n match {
case 0 => 0
case 1 => 1
case n =>
memoizedFib(n - 2) + memoizedFib(n - 1)
}
}
}
``````

## Memo

``````lazy val memoizedFib: Int => Int = ???

memoizedFib(30)
memoizedFib(40)
memoizedFib(45)

[success] Total time: 0 s``````

## Memo

``````Memo.arrayMemo
Memo.doubleArrayMemo
Memo.immutableHashMapMemo
Memo.immutableListMapMemo
Memo.immutableMapMemo
Memo.immutableTreeMapMemo
Memo.mutableHashMapMemo
Memo.mutableMapMemo
Memo.nilMemo
Memo.weakHashMapMemo``````

## Option

``````import scalaz.std.option._
import scalaz.syntax.std.option._``````

## Option

``````def runQuery(count: Option[Int]) = ???

runQuery(Some(10))``````

## Option

``````def runQuery(count: Option[Int]) = ???

runQuery(10.some)``````

## Option

``````val l = List(1,2,3,4,5)

// verify that no items are > 2
l.foldLeft(None) { case (sofar, next) =>
sofar.orElse((next > 2).option(s"\$next > 2"))
}``````

## Option

``````val l = List(1,2,3,4,5)

// verify that no items are > 2
l.foldLeft(None) { case (sofar, next) =>
sofar.orElse((next > 2).option(s"\$next > 2"))
}

[error] type mismatch;
[error]  found   : Option[String]
[error]  required: None.type
[error]       sofar.orElse((next > 2).option(s"\$next > 2"))
[error]                   ^``````

## Option

``````// Scala
object None extends Option[Nothing]``````

## Option

``````val l = List(1,2,3,4,5)

// verify that no items are > 2
l.foldLeft(none[String]) { case (sofar, next) =>
sofar.orElse((next > 2).option(s"\$next > 2"))
}``````

## Option

``````// Scala
object None extends Option[Nothing]

// Scalaz
def none[A]: Option[A] = None``````

## Not just Scalaz

``````val l = List(1,2,3,4,5)

// verify that no items are > 2
l.foldLeft(Option.empty[String]) {
case (sofar, next) =>
sofar.orElse((next > 2).option(s"\$next > 2"))
}``````

## Not just Scalaz

``````// Scala
object None extends Option[Nothing]

// Scalaz
def none[A]: Option[A] = None

// Scala
def empty[A]: Option[A] = None``````

## Either

``````import scalaz.std.either._
import scalaz.syntax.std.either._``````

## Either

``````def handleString(s: String) = ???
def handleInt(i: Int) = ???

val r: Either[String, Int] = Right(10)
val l: Either[String, Int] = Left("hello")

// calls handleInt(10)
r.fold(handleString(_), handleInt(_))

// calls handleString("hello")
l.fold(handleString(_), handleInt(_))``````

## Either

``````def handleString(s: String) = ???
def handleInt(i: Int) = ???

val r: Either[String, Int] = Right(10)

r match {
case Right(i) => handleInt(i)
case Left(s) => handleString(s)
}``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: Either[String, Int] = Right(100)

r.map(subtract).map(divide)``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: Either[String, Int] = Right(100)

r.map(subtract).map(divide)

[error] value map is not a member of Either
[error]     r.map(subtract).map(divide)
[error]       ^``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: Either[String, Int] = Right(100)

r.right.map(subtract).right.map(divide)
// Right(11)``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: \/[String, Int] = 100.right

r.map(subtract).map(divide) // 11.right``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: String \/ Int = 100.right

r.map(subtract).map(divide) // 11.right``````

## Either

``````type Xor[A, B] = A \/ B

def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: Xor[String, Int] = 100.right

r.map(subtract).map(divide) // 11.right``````

## Either

``````type Xor[A, B] = A \/ B

def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: Xor[String, Int] = 10.right

r.map(subtract).map(divide)``````

## Either

``````type Xor[A, B] = A \/ B

def subtract(i: Int): Int = i - 10
def divide(i: Int): Int = 1000 / i

val r: Xor[String, Int] = 10.right

r.map(subtract).map(divide)

[error] java.lang.ArithmeticException: / by zero
``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Xor[String, Int] =
if (i == 0) {
"Divide by zero".left
} else {
(1000 / i).right
}

val r: Xor[String, Int] = 10.right

r.map(subtract).flatMap(divide)
// "Divide by zero".left
``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Xor[String, Int] =
if (i == 0) {
"Divide by zero".left
} else {
(1000 / i).right
}

val r: Xor[String, Int] = 100.right

r.map(subtract).flatMap(divide)
// 11.right
``````

## Either

``````def subtract(i: Int): Int = i - 10
def divide(i: Int): Xor[String, Int] = ???

val r: Xor[String, Int] = 100.right

for {
x <- r.map(subtract)
y <- divide(x)
} yield y

// 11.right
``````

## OneAnd

``````final case class OneAnd[F[_], A](
tail: F[A]
)``````

## OneAnd

``````final case class OneAnd[F[_], A](
tail: F[A]
)

type NonEmptyList[A] = OneAnd[List, A]``````

## OneAnd

``````final case class OneAnd[F[_], A](
tail: F[A]
)

type NonEmptyList[A] = OneAnd[List, A]
type NonEmptySet[A] = OneAnd[Set, A]``````

## OneAnd

``````
def getUsers(ids: List[Int]): List[Users] = {
sql"SELECT * FROM users WHERE id IN (\$ids)"
.as[List[User]]
}

getUsers(Nil)``````

## OneAnd

``````
def getUsers(ids: List[Int]): List[Users] = {
sql"SELECT * FROM users WHERE id IN (\$ids)"
.as[List[User]]
}

getUsers(Nil)

// runtime error: invalid sql syntax
// SELECT * FROM users WHERE id IN ()``````

## OneAnd

``````
def getUsers(ids: NonEmptyList[Int]): List[Users] = {
sql"SELECT * FROM users WHERE id IN (\$ids)"
.as[List[User]]
}

getUsers(Nil) // Won't compile``````

## Validation

``````sealed abstract class Validation[+E, +A]

final case class Success[A](a: A)
extends Validation[Nothing, A]

final case class Failure[E](e: E)
extends Validation[E, Nothing]``````

## Validation

``````def gtTen(i: Int): Validation[String, Int]

def containsOne(i: Int): Validation[String, Int]

val i = 11
val j = 12
(gtTen(i) |@| containsOne(j)) { _ * _ }
// Success(132)``````

## Validation

``````def gtTen(i: Int): Validation[String, Int]

def containsOne(i: Int): Validation[String, Int]

val i = 9
val j = 12
(gtTen(i) |@| containsOne(j)) { _ * _ }
// Failure(9 <= 10)``````

## Validation

``````def gtTen(i: Int): Validation[String, Int]

def containsOne(i: Int): Validation[String, Int]

val i = 11
val j = 22
(gtTen(i) |@| containsOne(j)) { _ * _ }
// Failure(22 does not contain 1)``````

## Validation

``````def gtTen(i: Int): Validation[String, Int]

def containsOne(i: Int): Validation[String, Int]

val i = 9
val j = 22
(gtTen(i) |@| containsOne(j)) { _ * _ }
// Failure(9 <= 1022 does not contain 1)``````

## Validation

``````def gtTen(i: Int): ValidationNel[String, Int]

def containsOne(i: Int): ValidationNel[String, Int]``````

## Validation

``````Validation[NonEmptyList[String], Int]

ValidationNel[String, Int]``````

## Validation

``````type ValidationNel[E, +X] =
Validation[NonEmptyList[E], X]``````

## Validation

``````def gtTen(i: Int): ValidationNel[String, Int]

def containsOne(i: Int): ValidationNel[String, Int]

(gtTen(11) |@| containsOne(12)) { _ * _ }
//Success(132)
(gtTen(9) |@| containsOne(12)) { _ * _ }
//Failure(NonEmpty[9 <= 10])
(gtTen(11) |@| containsOne(22)) { _ * _ }
//Failure(NonEmpty[22 does not contain 1]
(gtTen(9) |@| containsOne(22)) { _ * _ }
//Failure(NonEmpty[9 <= 10,22 does not contain 1])``````

## Validation

``````def email(s: String) = ???
def phone(s: String) = ???

(email(e) |@| phone(p) |@| addr(a)) { (e, p, a) =>
UserInfo(e, p, a)
}
``````

``def getUser(id: Int): ?``

``def getUser(id: Int): User``

``def getUser(id: Int): Option[User]``

``def getUser(id: Int): Future[Option[User]]``

``````def getUser(id: Int): Future[Option[User]]

getUser(10).map { user: Option[User] =>

}``````

``````def getUser(id: Int): Future[Option[User]]

getUser(10).map { user: Option[User] =>
user.map { user: User =>
user.email
}
}
``````

``````def getUser(id: Int): Future[Option[User]]

val email: Future[Option[String]] =
getUser(10).map { user: Option[User] =>
user.map { user: User =>
user.email
}
}
``````

``````def getUser(id: Int): Future[Option[User]]

getUser(10).map { user: User =>
user.email
}
``````

## Transformers

``case class OptionT[F[_], A](run: F[Option[A]])``

## Transformers

``````def getUser(id: Int): Future[Option[User]]

OptionT[Future, User](getUser(10)).map { user =>
user.email
}
``````

## Transformers

``````def getUser(id: Int): OptionT[Future, User]

getUser(10).map { user: User =>
user.email
}
``````

## Transformers

``````def getUser(uid: Int): OptionT[Future, User]
def getTeam(u: User): OptionT[Future, Team]
def getSub(t: Team): OptionT[Future, Subscription]

getUser(userId).flatMap { user =>
getTeam(user).flatMap { team =>
getSub(team).map { sub =>
sub.renewalDate
}
}
}
``````

## Transformers

``````def getUser(uid: Int): OptionT[Future, User]
def getTeam(u: User): OptionT[Future, Team]
def getSub(t: Team): OptionT[Future, Subscription]

for {
user <- getUser(userId)
team <- getTeam(user)
sub <- getSub(team)
} yield {
sub.renewalDate
}``````

## Transformers

``````def getUser(uid: Int): Future[Option[User]]
def getTeam(u: User): Future[Option[Team]]
def getSub(t: Team): Future[Option[Subscription]]

val rdate: ? = getUser(uid).map { userOpt =>
userOpt.map { user =>
getTeam(user).map { teamOpt =>
teamOpt.map { team =>
getSub(team).map { subOpt =>
subOpt.map { sub =>
sub.renewalDate
}}}}}}``````

## Transformers

``````def getUser(uid: Int): Future[Option[User]]
def getTeam(u: User): Future[Option[Team]]
def getSub(t: Team): Future[Option[Subscription]]

type Ouch =
Future[Option[Future[Option[Future[Option[Date]]]]]]
val rdate: Ouch = getUser(uid).map { userOpt =>
userOpt.map { user =>
getTeam(user).map { teamOpt =>
teamOpt.map { team =>
getSub(team).map { subOpt =>
subOpt.map { sub => sub.renewalDate
}}}}}}``````

## Transformers

``````def getUser(uid: Int): OptionT[Future, User]
def getTeam(u: User): OptionT[Future, Team]
def getSub(t: Team): OptionT[Future, Subscription]

val rdate: OptionT[Future, Date] = for {
user <- getUser(userId)
team <- getTeam(user)
sub <- getSub(team)
} yield {
sub.renewalDate
}

rdate.run: Future[Option[Date]]``````

## Transformers

``````OptionT[F[_], A]  <=> F[Option[A]]

EitherT[F[_], A, B] <=> F[Either[A, B]]

ListT[F[_], A] <=> F[List[A]]
``````

## Transformers

``````OptionT[Future, A] <=> Future[Option[A]]

EitherT[Future, A, B] <=> Future[Either[A, B]]

ListT[Future, A] <=> Future[List[A]]
``````

## Applicative

``````def gtTen(i: Int): Validation[String, Int]

def containsOne(i: Int): Validation[String, Int]

val i = 11
val j = 12
(gtTen(i) |@| containsOne(j)) { _ * _ }
// Success(132)``````

## Applicative

``````val a = Option(99)
val b = Option("hello")
val c = Option(1.2)

(a |@| b |@| c) { (a, b, c) =>
s"\$a \$b \$c"
}

// Some(99 hello 1.2)``````

## Applicative

``````val a = Option(99)
val b = Option.empty[Int]
val c = Option(1.2)

(a |@| b |@| c) { (a, b, c) =>
s"\$a \$b \$c"
}

// None``````

## Applicative

``````val a = List(1,2)
val b = List(3,4)

(a |@| b) { (a, b) =>
(a, b)
}
``````

## Applicative

``````val a = List(1,2)
val b = List(3,4)

(a |@| b) { (a, b) =>
(a, b)
}

// List((1,3), (1,4), (2,3), (2,4)``````

## Applicative

``````val a = List(1,2)
val b = List(3,4)

(a |@| b) { (a, b) =>
a * b
}``````

## Applicative

``````val a = List(1,2)
val b = List(3,4)

(a |@| b) { (a, b) =>
a * b
}

// 1 * 3
// 1 * 4
// 2 * 3
// 2 * 4
// List(3, 4, 6, 8)``````

## Applicative

``````val a = Future(1)
val b = Future(2)
val c = Future(3)

(a |@| b |@| c) { (a, b, c) =>
a * b * c
}

// Future(6)``````

## Applicative

``````val a = Future(1)
val b = Future[Int](throw new Exception("bad"))
val c = Future(3)

val res = (a |@| b |@| c) { (a, b, c) =>
a * b * c
}

println(res)

## Semigroup

``1 |+| 1``

## Semigroup

``````1 |+| 1

// 2``````

## Semigroup

``List(1,2) |+| List(3,4)``

## Semigroup

``````List(1,2) |+| List(3,4)

// List(1,2,3,4)``````

## Semigroup

``Map("a" -> 1) |+| Map("b" -> 2)``

## Semigroup

``````Map("a" -> 1) |+| Map("b" -> 2)

// Map("a" -> 1, "b" -> 2)``````

## Semigroup

``Map("a" -> 1) |+| Map("a" -> 1)``

## Semigroup

``````Map("a" -> 1) |+| Map("a" -> 1)

// Map("a" -> 2)``````

## Semigroup

``````val a = Map("a" ->
Map("b" ->
Map("c" -> List(1,2,3))))
val b = Map("a" ->
Map("b" ->
Map("c" -> List(4,5,6))))

a |+| b

// Map(a ->
//   Map(b ->
//     Map(c -> List(1, 2, 3, 4, 5, 6))))``````

## References

Cats typelevel.org/cats

Learning Scalaz eed3si9n.com/learning-scalaz/

## Thanks

@gregghz

gregg@lucidchart.com

github.com/gregghz

golucid.co

By Gregg H

• 2,096