λ-Functional Programming
with Scala
©2013 Raymond Tay
About m(e)I write code.
I write books too !
https://github.com/raygit/Introduction_to_Scala
The Whats and Whos
Is Scala a fad?
This is when i first heard of Scala
Mutability
val x = 3
var y = 3
Mutability?scala> val x = mutable.HashMap[String,String]()
x: scala.collection.mutable.HashMap[String,String] = Map()
scala> x += ("a" → "a")
res0: x.type = Map(a -> a)
------
scala> val y = immutable.HashMap[String,String]()
y: scala.collection.immutable.HashMap[String,String] = Map()
scala> y += ("a" → "a")
<console>:9: error: reassignment to val
y += ("a" → "a")
Free of side effects
•Code reuse
•Make better building blocks
•Easier to reason about, optimize and test
Functions are First-classdef multiplyFour : Int ⇒ Int = (4 * )
def addTwo: Int ⇒ Int = (2 + )
def º[A,B,C](f: A ⇒ B, g : B ⇒ C ) = f andThen g // Parametric-polymorphism
def f = º(multiplyFour , addTwo) // We’ll make it look more ‘natural’ in the section: Typeclasses
f(4)
res6: Int = 18
(addTwo compose multiplyFour)(4)
res4: Int = 18
Closureval x = 3 // what if its `var x = 3`?
def λ = (y: Int) ⇒ x + y
Be careful what you `close` over i.e. context-sensitive
val xval x λλ33
var xvar x λλ33
77
Lambdas
def g(λ: Int ⇒ Int) = λ
g((x:Int) ⇒ x * 2) OK
g( (x:Int) ⇒ (y:Int) ⇒ x + y ) FAIL
g( ((x: Int) ⇒ (y: Int) ⇒ x + y)(4) ) OK
Matching// simulate a binary tree
sealed trait Tree
case class Branch(ele: Int, left: Tree: right: Tree) extends Tree
case object Leaf extends Tree
// inOrder aka Depth-First Traversal
def inOrder(t: Tree) : List[Int] = t match {
case Branch(ele, l, r) ⇒ inOrder(l):::List(ele):::inOrder(r)
case Leaf ⇒ Nil
}
Recursiondef string2spaces(ss: List[Char]) = ss match {
case Nil ⇒ Nil
case h :: tail ⇒ ‘ ‘ :: string2spaces(tail)
}
import scala.annotation.tailrec
@tailrec
def string2spaces(ss: List[Char], acc: List[Char]): List[Char] = ss match {
case Nil ⇒ acc
case h :: tail ⇒ string2spaces(tail, ‘ ‘ +: acc)
}
Lazy vs Eager Eval
def IamEager[A](value: A)
def IamLazy[A](value: ⇒ A)
TypeclassesWhat I really want to write is
(addTwo ∘ multiplyFour)(4) and not
(addTwo compose multiplyFour)(4)
typeclasses - create higher kinded types! e.g. List[Int ⇒ Int]
Typeclasses in Scalatrait Fn extends (Int ⇒ Int) {
def apply(x: Int) : Int
def º(f: Fn) = f andThen this
}
def addTwo = new Fn { def apply(x: Int) = 2 + x }
def multiplyFour = new Fn { def apply(x: Int) = 4 * x }
multiplyFour º addTwo
res0: Int => Int = <function1>
(addTwo º multiplyFour)(4)
res1: Int = 18
Typeclasses in Scala
sealed trait MList[+A]
case object Nil extends MList[Nothing]
case class ::[+A](head: A, tail: MList[A]) extends MList[A]
object MList {
def apply[A](xs: A*) : MList[A] = if (xs.isEmpty) Nil else ::(xs.head, apply(xs.tail: _*))
}
Typeclasses in Scala
object Main extends App {
val x = MList(1,2,3,4,5) match {
case ::(x, ::(2, ::(4, _))) => x
case Nil => 42
case ::(x, ::(y, ::(3, ::(4, _)))) => x + y
case ::(h, t) => h
case _ => 101
}
println(s"value of ${x}")
}
Adhoc Polymorphism
scala> (1,2,3) map { 1 + _ }
<console>:8: error: value map is not a member of (Int, Int, Int)
(1,2,3) map { 1 + _ }
scala> implicit def giveMeMap[A](t : Tuple3[A,A,A]) = new Tuple3[A,A,A](t._1, t._2, t._3) { def map[B](f: A => B) = new Tuple3(f(_1), f(_2), f(_3)) }scala> (1,2,3) map { 1 + _ }res1: (Int, Int, Int) = (2,3,4)
Adhoc Concurrency
class Matrix(val repr: Array[Array[Double]])
trait ThreadStrategy {
def execute[A](f: () ⇒ A) : () ⇒ A
}
object SingleThreadStrategy extends ThreadStrategy { // uses a single thread }
object ThreadPoolStrategy extends ThreadStrategy { // uses a thread pool }
Adhoc Concurrencyscala> val m = new Matrix(Array(Array(1.2, 2.2), Array(3.4, 4.5)))
m: Matrix =
Matrix
|1.2 | 2.2|
|3.4 | 4.5|
scala> val n = new Matrix(Array(Array(1.2, 2.2), Array(3.4, 4.5)))
n: Matrix =
Matrix
|1.2 | 2.2|
|3.4 | 4.5|
Adhoc Concurrency
scala> MatrixUtils.multiply(m, n)
res1: Matrix =
Matrix
|8.92 | 12.540000000000001|
|19.38 | 27.73|
scala> MatrixUtils.multiply(m, n)(ThreadPoolStrategy)
Executing function on thread: 38
Executing function on thread: 39
Executing function on thread: 40
Executing function on thread: 41
res2: Matrix = // truncated but result is the same, trust me ;)
Concurrency on Collections!
par
val parList = (1 to 1000000).toList.par
(1 to 1000000).toList.par.partition{ _ % 2 == 0 }
Functional Data Structures - List
def foldRight[A,B](l: List[A], z: B)(f: (A,B) ⇒ B) : B = l match {
case Nil ⇒ z
case ::(h, t) ⇒ f(h, foldRight(t,z)(f))
}
@tailrec
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) ⇒ B) : B = l match {
case Nil ⇒ z
case ::(h, t) => foldLeft(t, f(z,h))(f)
}
Reactive Concurrency
If i had more time...
•Existential Types
•Self Types
•Structural Typing (think Duck Typing)
•Compile-time metaprogramming (macros,quasiquotes)
•Reactive Programming through Akka
•Monoids, Monads, Endos, Corecursive and a whole lot more
Thanks
twitter: @RaymondTayBL