- 1. How to startHow to start Functional ProgrammingFunctional Programming (in Scala):Day1(in Scala):Day1
- 2. Who am I?Who am I?
- 3. Taisuke Oe (Twitter: @OE_uia, GitHub: @taisukeoe) ScalaMatsuri organizer as a chairperson Technical Advisor at Septeni Original, Inc.
- 4. ScalaMatsuri CFP is open now!ScalaMatsuri CFP is open now!
- 6. Functional Programming is the paradigm to construct a software with composing computations like functions. (in a casual de nition)
- 7. Through learning FP, you can learn the ways to make functions or comutations smallish, composable and iducible.
- 8. That helps to keep your software clean and extensible, even in OOP.
- 9. Scala is indeed a functional language,Scala is indeed a functional language, butbut not very strict about FP principles.
- 10. Scala uni es FP and OOP, and recommends to leverage both of their strengths.
- 11. Today's topicToday's topic Function compositions. Function purity. Abstracting from functions and composition.
- 12. Composing functions andComposing functions and methods.methods.
- 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.
- 20. Methods and type parameterMethods and type parameter
- 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)
- 25. Pure FunctionsPure Functions All functions so far are pure functions They always return the same value with the same arguments.
- 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.
- 31. Abstracting from functionsAbstracting from 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)
- 35. ApplyApply combinecombineintointo foldLeftfoldLeft operation.operation. combineworks for Seq[Int]Then how about Seq[Option[Int]]? scala Seq(1,2,3).foldLeft(0)(combine) res0: Int = 6
- 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.
- 41. MonoidMonoid?? Monoidcan be de ned as follows. trait Monoid[T] { def empty: T def combine(t1: T, t2: T): T }
- 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
- 48. //Monoid[Int] scala foldLeft(Seq(1,2,3)) res0: Int = 6 //Monoid[Option[Int]] scala foldLeft(Seq(Some(1), None, Some(3))) res1: Option[Int] = Some(4) //Monoid[Option[(Int,String)]] scala foldLeft(Seq(Some((1,a)), None, Some(2,b))) res2: Option[(Int,String)] = Some((3,ab))
- 49. Now you enjoy foldLeftfor any type with Monoid!
- 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.
- 58. This is so called Adhoc Polymorphism.
- 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.
- 62. Typeclass makes types more extesible without modi cation of its original behaviour.
- 63. So typeclass is inline with open/closed principles.
- 64. Further readingFurther reading Book:Book: Functional Programming in Scala Chinese version
- 65. OSS projectOSS project Both of these projects have a tons of typeclasses . Scalaz Cats: Typelevel.scala