Elements of Functional Programming
        Popular Functional Languages
          - Scala
- F#
- Haskell
- Clojure
- Scheme
- Ocaml
Variables
          
val x = 10
x = 20 // error!
var y = 30
y = 40 // OK
          
        Case classes
          
case class Point(x: Int, y: Int)
val p1 = Point(10, 20)
val p2 = Point(0, p1.y)
          
        Functions
          
object Utils {
  def times(x: Int, n: Int): Int =
    x * n
  def twice(x: Int) = times(2, x)
}
          
        Lambda Expression
          
def twice(f: Int => Int, x: Int): Int =
  f(f(x))
twice((x: Int) => x * 3, 10)
twice(x => x * 3, 10)
twice(_ * 3, 10)
          
        Parametric Polymorphism
          
def twice[T](f: T => T, x: T): T =
  f(f(x))
          
        Currying
          
def twice[T](f: T => T)(x: T): T =
  f(f(x))
val plusFour: Int => Int = twice(_ + 2)
plusFour(10)
twice((_: Int) + 2)(10)
          
        ADT
          
sealed trait MyBool
case object True extends MyBool
case object False extends MyBool
def not(b: MyBool): MyBool = b match {
  case True => False
  case False => True
}
          
        ADT
          
sealed trait E
case class Plus(a: E, b: E) extends E
case class Const(x: Int) extends E
        Pattern Matching
          
def eval(e: E): Int = e match {
  case Const(x) => x
  case Plus(a, b) => eval(a) + eval(b)
}
val e: E =
  Plus(
    Const(10),
    Plus(Const(2), Const(3)))
println(eval(e)) // prints 15
        Pattern Matching
          
def opt(e: E): E = e match {
  case Plus(Const(0), x) => x
  case Plus(x, Const(0)) => x
  case Plus(x, y) =>
    Plus(opt(x), opt(y))
  case c@Const(_) => c
}
        Pattern Matching
          
val e: E =
  Plus(Const(10),
    Plus(Const(2), Const(0)))
println(opt(e))
// Prints: Plus(Const(10),Const(2))
        Implicits
          
trait Logger {
  def output(s: String): Unit
}
def log(s: String)(implicit log: Logger) =
  log.output(s)
        Implicits
          
implicit val logger = new Logger {
  override def output(s: String): Unit =
    println(s)
}
def work(): Unit = {
  log("Working...")
  log("Done!")
}
        Type classes
          
trait Show[T] {
  def show(x: T): String
}
        Type classes
          
def show[T](x: T)(implicit s: Show[T]): String =
  s.show(x)
def mkShow[T](f: T => String): Show[T] =
  new Show[T] {
    override def show(x: T): String = f(x)
  }
        Type classes
          
implicit val stringShow: Show[String] =
  mkShow(x => x)
implicit val intShow: Show[Int] =
  mkShow(_.toString)
implicit
  def ls[T](implicit s: Show[T]): Show[List[T]] =
    mkShow(_.map(s.show).mkString(", "))
        Type classes
          
println(show(10))
println(show("Hello"))
println(show(List(1, 2, 3)))
println(show('a')) // error!
        Equality type class
          
true == true
"hello" == UserId(32)
2 == 2.0
dbConnection == dbConnection
        Equality type class
          
trait Eq[T] {
  def equal(a: T, b: T): Boolean
}
        Equality operations
          
trait EqOps[T] {
  def ===(other: T): Boolean
}
        Equality operations
          
implicit def toEqOps[T](t: T)(implicit e: Eq[T]): EqOps[T] =
  new EqOps[T] {
    def ===(other: T) =
      e.equal(t, other)
  }
        Equality instances
          
implicit val intEq: Eq[Int] = new Eq[Int] {
  override def equal(a: Int, b: Int): Boolean =
    a == b
}
        Equality instances
          
implicit def
tupleEq[A, B](implicit eqA: Eq[A], eqB: Eq[B]): Eq[(A, B)] =
  new Eq[(A, B)] {
    override def equal(a: (A, B), b: (A, B)): Boolean =
      eqA.equal(a._1, b._1) && eqB.equals(a._2, b._2)
  }
        Equality instances
          
import EqualityExample._
println(1 === 1) // true
println(1 === 2) // false
println((1, 2) === (1, 2)) // true
println(4 === "test") // error
        Optional values
          
sealed trait Opt[+T]
case class Some[T](x: T) extends Opt[T]
case object None extends Opt[Nothing]
        Optional values
          
def div(a: Int, b: Int): Opt[Int] =
  if (b == 0) None else Some(a / b)
        Optional values
          
def useDiv() = {
  val a = div(10, 5)
  println(a) // Some(2)
  val b = div(10, 0)
  println(b) // None
}
        Optional values
          
sealed trait Opt[+T] {
  def isDefined: Boolean
  def get: T
}
        Optional values
          
case class Some[T](x: T) extends Opt[T] {
  override def isDefined: Boolean = true
  override def get: T = x
}
        Optional values
          
case object None extends Opt[Nothing] {
  override def isDefined: Boolean = false
  override def get: Nothing =
    throw new RuntimeException("Error")
}
        Optional values
          
def useDiv() = {
  val a = div(10, 5)
  if (a.isDefined)
    println(a.get)
  val b = div(10, 0)
  if (b.isDefined)
    println(b.get)
}
        Optional values
          
sealed trait Opt[+T] {
  def map[R](f: T => R): Opt[R] = this match {
    case None => None
    case Some(x) => Some(f(x))
  }
}
        Optional values
          
def useDiv() = {
  val a = div(10, 5)
  println(a.map(_ + 1)) // prints Some(3)
  val b = div(10, 0).map(_ + 1)
  println(b) // prints None
}
        Optional values
          
def useDiv() = {
  val a = div(10, 5).map(_ + 1)
  println(a)
  // error in next line: A is Opt[Int]
  val b = div(a, 2).map(_ + 2)
  println(b)
}
        Optional values
          
sealed trait Opt[+T] {
  def flatMap[R](f: T => Opt[R]): Opt[R] =
    this match {
      case None => None
      case Some(x) => f(x)
    }
}
        Optional values
          
def useDiv() = {
  val a = div(10, 5)
  val b = a.flatMap(x => div(x, 2).map(_ + 1))
  println(b) // None
}
        Optional values
          
def useDiv2() = {
  val res = for {
    a <- div(10, 5)
    b <- div(a, 2)
  } yield b + 1
  println(res) // Some(2)
}
        Flat map chain
          
val a = div(10, 5)
  .flatMap(x => div(x, 0))
  .flatMap(x => div(x, 2))
  .flatMap(x => Some(x + 1))
println(a) // None
          
        Flat map chain
          
val a = div(10, 5)
  .flatMap(div(_, 0))
  .flatMap(div(_, 2))
  .flatMap(x => Some(x + 1))
println(a) // None
          
        Optional
          
sealed trait Opt[+T] {
  def isDefined: Boolean // Bad
  def get: T // Bad
  def getOrElse[B >: T](y: => B): B =
    this match {
      case Some(x) => x
      case None => y
    }
}
          
        Optional
          
div(10, 0).getOrElse(0) // 0
          
        Optional
          
div(10, 0) match {
  case Some(x) => println(x)
  // error: missing case
}
          
        Optional
          
div(10, 0) match {
  case Some(x) => println(x)
  case None => println("Nope.")
}
          
        Either
          
sealed trait Either[A, B]
case class Left[A, B](a: A) extends Either[A, B]
case class Right[A, B](b: B) extends Either[A, B]
          
        Either
          
def f(): Either[Int, String] =
  Left(10)
def g() = {
  f() match {
    case Left(a) => println("Left " + a)
    case Right(b) => println("Right " + b)
  }
}