13. What is a function?What is a function?
A function is a computation to transform inputs into outputs.
It's an instance of FunctionNtraits in Scala.
FunctionNmeans a function type which takes N arguments
(from 0 to 22).
Function0[T], Function1[T1,T2], ... , Function22[T1,...,T23]
Function1Function1
Int=Intis a type alias to Function1[Int,Int].
scala val double = (i:Int) = i * 2
double: Int = Int = function1
14. Function1 is composable.Function1 is composable.
Function1has andThenand composemethod for function
compositions.
scala val quadraple = double compose double
quadraple: Int = Int = function1
scala quadraple(3)
res0: Int = 12
15. Function2 to 22 don't have thoseFunction2 to 22 don't have those
methods, but...methods, but...
16. Function2 to 22 can be curried.Function2 to 22 can be curried.
Curryingmeans converting a multiple argument funtion to
Function1.
17. Currying Function2Currying Function2
Function2[Int,String,Int]is curriedto
Function1[Int,Function1[String,Int]]
scala val combine = (left:Int, right:Int) = left + right
combine: (Int, Int) = Int = function2
scala combine.curried
res0: Int = (Int = Int) = function1
18. Function2 to 22 can be composed viaFunction2 to 22 can be composed via
currying.currying.
Thus Function1- Function22are composable.
scala double andThen combine.curried
res0: Int = (Int = Int) = function1
19. FP fundamentalsFP fundamentals
As we see, functions can take another function as an
agrument or a return value.
This is to say a function is a rst class citizen.
Those functions are called higher order functions.
Above two are fundamentals in FP.
21. Di erence from functionsDi erence from functions
Method is de ned by def keyword.
Methods can be expanded to FunctionNby _. (eta-expansion)
scala def double(i:Int):Int = i * 2
double: (i: Int)Int
scala double _
res0: Int = Int = function1
22. Methods can take type parameters or an implicit parameter
list, while functions cannot.
23. Methods with type parameterMethods with type parameter
Seq[T] has a method map[U]which modi es Ttyped elements
into Utyped elements.
def map[U](f: T = U): Seq[U]
scala Seq(1,2,3).map(_ + 1)
res0: Seq[Int] = List(2,3,4)
24. Combine all together.Combine all together.
Now we know function composition basics!
scala val apCurried = combine.curried
apCurried: Int = (Int = Int) = function1
// (X + 3) * 2
scala val plus3Double = apCurried(3) andThen double
plus3Double: Int = Int = function1
scala seq = Seq(1,2,3).map(plus3Double)
seq: Seq[Int] = Seq(8,10,12)
26. Watch out side e ectsWatch out side e ects
Changing any state.
Depending on mutable state which may change.
Standard ouput
File I/O
Throwing exceptions.
All above side effects may change functions behaviour
depends on state.
27. What isWhat is resultresult??
var counter = 0
val next = (nth: Int) = {
counter += nth
counter
}
scala next(1)
res0: Int = 1
scala val result = (next andThen next andThen next)(3)
28. You have to care the order of execution and each state, even
if you compose!
It's sometimes hard to predict how impure functions behave.
scala val result = (next andThen next andThen next)(3)
result: Int = 16
29. localize side-e ectslocalize side-e ects
All side effects cannot be removed from your program.
The key is to localize and seperate side effects from other
functions.
30. Referential transparencyReferential transparency
Excluding side-effects, expressions can be replaced with its
evaluation with keeping the meaning of program.
It is called referentially transparent
Referential transparent functions are called pure functions.
32. RethinkRethink combinecombinefunctionfunction
We de ned combinefunction as a binary operation of Int.
It's amazingly useful for fold-like operation.
scala val combine = (left:Int, right:Int) = left + right
combine: (Int, Int) = Int = function2
33. foldLeftfoldLeft
Here is the foldLeftsignature of Seq[A].
This foldLefttakes two arguments - one is a default value,
and another is a binary operation of Int.
def foldLeft[B](z: B)(op: (B, A) ⇒ B): B
34. It folds the sequence from left to right. Thus:
means
(((0 + 1) + 2) + 3)
Seq(1,2,3).foldLeft(0)((x: Int, y:Int) = x + y)
36. combiningcombining Option[Int]Option[Int]scala val combineOptions = (left:Option[Int], right:Option[Int
(left , right) match{
case (None, None) = None
case (Some(l), None) = Some(l)
case (None, Some(r)) = Some(r)
case (Some(l), Some(r)) = Some(l + r)
}
combineOptions: (Option[Int], Option[Int]) = Option[Int] = fun
37. Okay then, how about Seq[Option[String]]?
scala Seq(Some(1),None,Some(3)).foldLeft(None)(combineOptions)
res0: Option[Int] = Some(4)
38. Do we have to de ne combineOptionXXXfor each Option[T]?
39. Abstract from functions.Abstract from functions.
We see the following operations are required for the element
type of Seqand its foldLeftoperation.
returning default value
binary operation
40. Let's abstract these two and make a certain type for them.
We call the type Monoid.
42. De neDe ne MonoidMonoidofof IntIntandand StringString
In this context, implicitis the keyword to pass a value as an
argument implicitly.
implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
val empty: Int = 0
def combine(left: Int, right: Int): Int = left + right
}
43. implicit val stringMonoid: Monoid[String] = new Monoid[String] {
val empty: String =
def combine(left: String, right: String): String = left + righ
}
44. Induce Monoid of Option[T]Induce Monoid of Option[T]
Now Monoid[Option[T]]instance can be induced from
Monoid[T]instance.
45. (Disclaimer: for simplicity, above induction function is de ned as T
type has to be Monoid, instead of Semigroup. )
implicit def optionMonoid[T](implicit M:Monoid[T]): Monoid[Optio
val empty: Option[T] = None
def combine(left:Option[T], right:Option[T]) =
(left , right) match{
case (None, None) = None
case (Some(l), None) = Some(l)
case (None, Some(r)) = Some(r)
case (Some(l), Some(r)) = Some(M.combine(l, r))
}
}
46. Compose Monoids for tupleCompose Monoids for tuple
You can also compose Monoid instances.
implicit def tupleMonoid[S,T](implicit MS:Monoid[S], MT:Monoid[T
new Monoid[(S,T)]{
val empty: (S,T) = (MS.empty, MT.empty)
def combine(left:(S,T), right:(S,T)) =
(MS.combine(left._1, right._1), MT.combine(left._2, righ
}
47. De neDe ne foldLeftfoldLeftmethod to usemethod to use
MonoidMonoiddef foldLeft[T](seq: Seq[T])(implicit M:Monoid[T]): T = seq.fold
50. Cooler stu ofCooler stu of MonoidMonoid
Let's de ne a new fold operation like foldMapusing Monoid.
51. Now you can map values and fold them with traversing a
sequence just once!
def foldMap[T,U](s: Seq[T])(f: T = U)(implicit M:Monoid[U]) =
s.foldLeft(M.empty){case (l, r) = M.combine(l, f(r))}
scala foldMap(Seq(1,2,3))(_.toString)
res0: String = 123
52. RecapRecap MonoidMonoid- it's a typeclass.- it's a typeclass.
Monoid[T]is a type for a binary operation and a default value
against Ttype.
53. By de ning Monoid[T]instance against Ttype, new
behaviours are added into Ttype.
54. Monoidis so called typeclass and above description is the
bene t of typeclass.
55. What is typeclass?What is typeclass?
typeclass comes from Functional Language Haskell to
contrain a type parameter and admit new functions to its
type.
56. It means adding new behaviours into exisiting types without
changing their codebase!
57. Thus you can add new behaviours into even Stringtype
which souce codes cannot be modi ed or extended.
59. Typeclasses out of the boxTypeclasses out of the box
Scala standard library de nes several typeclasses.
Ordering[T]typeclass is to de ne natural ordering of Ttype.
60. sortedmethod in Seq[T]use Ordering[T]typeclass
instances otherwise it fails to compile.
def sorted[B : A](implicit ord: math.Ordering[B]): List[A]
scala Seq(3,1,2).sorted
res3: Seq[Int] = List(1, 2, 3)
61. Typeclass works well with OOPTypeclass works well with OOP
Typeclass is not a concept just for Functional Programming.