Ittay Dror             ittayd@tikalk.com             @ittayd             http://www.tikalk.com/blogs/ittayd    Functional ...
What is FP?     2        WWW.TIKALK.COM
“a programming paradigm that    treats computation as the   evaluation of mathematical functions and avoids state and     ...
• Functions as values• Immutable data structures• Mathematical models• Referential transparency                    4      ...
Why Should We Care?         5        WWW.TIKALK.COM
Not everything is an      object         6             WWW.TIKALK.COM
May Forget                                         Nothing toservice.init                             return?val data = se...
IOC 8    WWW.TIKALK.COM
class Service {  def withData[T](f: Data => T) {    init    if (thereIsData)      f(getData)    close  }}service.witData(p...
Simplification      10         WWW.TIKALK.COM
In OOP: trait DataConsumer[T] {   def withData(data: Data): T {In FP: Data => T                     11          WWW.TIKALK...
Factories are partially  applied functions           12         WWW.TIKALK.COM
val factory_: File => String => User =  file => name => readFromFile(name)val factory: String => User = factory_(usersFile...
Security   14      WWW.TIKALK.COM
Immutable data is   sharable        15          WWW.TIKALK.COM
Instead of modifying,     create new          16        WWW.TIKALK.COM
Abstraction     17       WWW.TIKALK.COM
Functors, Applicatives,      Monads           18         WWW.TIKALK.COM
Usual way of describing:                  WTF??            19        WWW.TIKALK.COM
OO way: Design Patterns           20       WWW.TIKALK.COM
Values in a context         21           WWW.TIKALK.COM
Option[X]List[X]Future[X]            22   WWW.TIKALK.COM
trait Future[A] {          def get: A        {def findUser(name: String): Future[User] = ……val future = findUser(userName)...
trait Future[A] {      def onReady(f: A => Unit)    }val future = findUser(userName)future.onReady{user => println(user)} ...
Functor   25     WWW.TIKALK.COM
trait Future[A] {  def map[B](f: A => B): Future[B]{val user = findUser(userName)val age: Future[Int] = user.map{user => u...
val result = new ArrayList(list.size)for (i <- 0 to (list.size - 1)) {  result += compute(list(i))}result                 ...
class ComputeTask extends RecursiveTask {  def compute = // split and callinvokeAll...{val pool = new ForkJoinPool()val ta...
trait Future[A] {  def get: A    def map[B](f: A => B) = new Future[B] {      def get = f(Future.this.get)    {{          ...
def marry(man: User, woman: User): Family = ⠄⠄⠄val joe = findUser("joe")val jane = findUser("jane")   Get Joe and Jane mar...
Future[Family]                                    User => Familyjoe.map{joe => jane.map{jane => marry(joe, jane)}}        ...
Attempt Itrait Future[A] {  def apply[B, C](other: Future[B], f: (A, B) =>C): Future[C]} joe.apply(jane, marry)           ...
It is easier to work withsingle argument functions             33          WWW.TIKALK.COM
Curried Functionsval func: Int => Int => Int = a => b => a + b  (marry _).curried                        34               ...
Attempt IItrait Future[A] {  ...    def apply[B](f: Future[A => B]): Future[B]{                          35               ...
Future[User => Family]                         User => User => Familyjoe.apply(jane.map((marry _).curried))               ...
We can do better       37          WWW.TIKALK.COM
val marry: Future[User => User => Family] = Future(marry)val partial: Future[User => Family] = futureMarry.apply(joe)val f...
Applicative Functors         39            WWW.TIKALK.COM
• Put value in context• Apply function in a context to value ina context                     40                     WWW.TI...
trait Future[A] {  def apply[B, C](b: Future[B])                 (implicit ev: A <:< (B => C))                 : Future[C]...
trait Future[A] {  def apply[B, C](b: Future[B])                 (implicit ev: A <:< (B => C)) =    new Future[C] {      d...
Composing Functions thatReturn Value in a Context            43        WWW.TIKALK.COM
Composing Special           Functionsdef findUser(name: String): Future[User]def findProfile(user: User): Future[Profile]f...
Monads  45     WWW.TIKALK.COM
trait Future[A] {  ...  def flatMap[B](f: A => Future[B]): Future[B]}findUser("joe").flatMap(findProfile)                 ...
trait Future[A] {  ...  def flatMap[B](f: A => Future[B]): Future[B] =    new Future[B] {      def get = f(Future.this.get...
All Togethertrait Context[A] {  def map[B](f: A => B): Context[B]  def apply[B, C](b: Context[B])                 (implici...
Laws 49    WWW.TIKALK.COM
Idiomatic “interface” for    context classes            50         WWW.TIKALK.COM
Monoid• For type A to be (have) a Monoid:   • Binary operation „•„: (A, A) => A   • Identity element „∅‟: A               ...
• String is a Monoid (2 ways):   • Binary operation: append or prepend   • Identity element: “”• Int is a Monoid (2 ways):...
• Future[A] is a monoid, if A is a monoid   • Binary operation: Future(A#•)      • (Future as applicative)   • Identity el...
Monoids generalize folds           54        WWW.TIKALK.COM
Folds: reduce values to          one• List(x,y,z) => ∅ • x • y • z• Option(x) => if Some ∅ • x                else ∅      ...
Unfolds: Create values from initial value and        function• 1, if (a < 3) Some(a, a+1) else None   • Some(1, 2), Some(2...
Since many things aremonoids, we can havemany generic algorithms           57       WWW.TIKALK.COM
Problems with subtyping: • Namespace pollution • Need to control the class • Describes behavior, not „is-a‟ • Sometimes ab...
Typeclass• Define an API• Create instance for each class thatcan conform to the API                    59                 ...
Java example: Comparator      60        WWW.TIKALK.COM
trait Functor[F[_]] {  def map[A, B](fa: F[A], f: A => B): F[B]{implicit object FutureHasFunctor  extends Functor[Future] ...
def age(name: String)       (implicit functor: Functor[Future]) {  functor.map(findUser(name), {u: User => u.age})}       ...
def age[F[_] : Functor](name: String) {  functor.map(findUser(name), {u: User => u.age})}                        63       ...
Generic Programming         64       WWW.TIKALK.COM
def sequence[A, AP[_] : Applicative]            (apas: List[AP[A]]): AP[List[A]]val futureOfList = sequence(listOfFutures)...
trait Applicative[AP[_]] {  def pure[A](a: A) : AP[A]  def apply[A, B](ap: AP[A => B], a: AP[A]): AP[B]{                  ...
It is NOT important if youdon’t understand the next             slide             67         WWW.TIKALK.COM
def sequence[A, AP[_] : Applicative](apas: List[AP[A]]):  AP[List[A]] = {    val applicative = implicitly[Applicative[AP]]...
Beyond  69     WWW.TIKALK.COM
val m = Map[Int, Int]()m.map{case (k, v) => k + v}                     70       WWW.TIKALK.COM
def map[B, That](f: A => B)    (implicit bf: CanBuildFrom[Repr, B, That])    : That                        71             ...
?72   WWW.TIKALK.COM
Upcoming SlideShare
Loading in...5
×

Functional Programming from OO perspective (Sayeret Lambda lecture)

884

Published on

A lecture about some FP concepts from an (impure) OO perspective.

Published in: Technology, Business
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
884
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
25
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Functional Programming from OO perspective (Sayeret Lambda lecture)

  1. 1. Ittay Dror ittayd@tikalk.com @ittayd http://www.tikalk.com/blogs/ittayd Functional Programming From OOP perspective26-Oct-11
  2. 2. What is FP? 2 WWW.TIKALK.COM
  3. 3. “a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data” 3 WWW.TIKALK.COM
  4. 4. • Functions as values• Immutable data structures• Mathematical models• Referential transparency 4 WWW.TIKALK.COM
  5. 5. Why Should We Care? 5 WWW.TIKALK.COM
  6. 6. Not everything is an object 6 WWW.TIKALK.COM
  7. 7. May Forget Nothing toservice.init return?val data = service.getservice.close May forget / call twiceprintln(data) 7 WWW.TIKALK.COM
  8. 8. IOC 8 WWW.TIKALK.COM
  9. 9. class Service { def withData[T](f: Data => T) { init if (thereIsData) f(getData) close }}service.witData(println) 9 WWW.TIKALK.COM
  10. 10. Simplification 10 WWW.TIKALK.COM
  11. 11. In OOP: trait DataConsumer[T] { def withData(data: Data): T {In FP: Data => T 11 WWW.TIKALK.COM
  12. 12. Factories are partially applied functions 12 WWW.TIKALK.COM
  13. 13. val factory_: File => String => User = file => name => readFromFile(name)val factory: String => User = factory_(usersFile) Look ma, no interfaces 13 WWW.TIKALK.COM
  14. 14. Security 14 WWW.TIKALK.COM
  15. 15. Immutable data is sharable 15 WWW.TIKALK.COM
  16. 16. Instead of modifying, create new 16 WWW.TIKALK.COM
  17. 17. Abstraction 17 WWW.TIKALK.COM
  18. 18. Functors, Applicatives, Monads 18 WWW.TIKALK.COM
  19. 19. Usual way of describing: WTF?? 19 WWW.TIKALK.COM
  20. 20. OO way: Design Patterns 20 WWW.TIKALK.COM
  21. 21. Values in a context 21 WWW.TIKALK.COM
  22. 22. Option[X]List[X]Future[X] 22 WWW.TIKALK.COM
  23. 23. trait Future[A] { def get: A {def findUser(name: String): Future[User] = ……val future = findUser(userName)val user = future.getprintln(user) 23 WWW.TIKALK.COM
  24. 24. trait Future[A] { def onReady(f: A => Unit) }val future = findUser(userName)future.onReady{user => println(user)} 24 WWW.TIKALK.COM
  25. 25. Functor 25 WWW.TIKALK.COM
  26. 26. trait Future[A] { def map[B](f: A => B): Future[B]{val user = findUser(userName)val age: Future[Int] = user.map{user => user.age} 26 WWW.TIKALK.COM
  27. 27. val result = new ArrayList(list.size)for (i <- 0 to (list.size - 1)) { result += compute(list(i))}result Vs.list.map(compute) 27 WWW.TIKALK.COM
  28. 28. class ComputeTask extends RecursiveTask { def compute = // split and callinvokeAll...{val pool = new ForkJoinPool()val task = new ComputeTask()pool.invoke(task) Vs.list.par.map(compute) 28 WWW.TIKALK.COM
  29. 29. trait Future[A] { def get: A def map[B](f: A => B) = new Future[B] { def get = f(Future.this.get) {{ 29 WWW.TIKALK.COM
  30. 30. def marry(man: User, woman: User): Family = ⠄⠄⠄val joe = findUser("joe")val jane = findUser("jane") Get Joe and Jane married 30 WWW.TIKALK.COM
  31. 31. Future[Family] User => Familyjoe.map{joe => jane.map{jane => marry(joe, jane)}} User => Future[Family] Future[Future[Family]] 31 WWW.TIKALK.COM
  32. 32. Attempt Itrait Future[A] { def apply[B, C](other: Future[B], f: (A, B) =>C): Future[C]} joe.apply(jane, marry) 32 WWW.TIKALK.COM
  33. 33. It is easier to work withsingle argument functions 33 WWW.TIKALK.COM
  34. 34. Curried Functionsval func: Int => Int => Int = a => b => a + b (marry _).curried 34 WWW.TIKALK.COM
  35. 35. Attempt IItrait Future[A] { ... def apply[B](f: Future[A => B]): Future[B]{ 35 WWW.TIKALK.COM
  36. 36. Future[User => Family] User => User => Familyjoe.apply(jane.map((marry _).curried)) User => Future[Family] 36 WWW.TIKALK.COM
  37. 37. We can do better 37 WWW.TIKALK.COM
  38. 38. val marry: Future[User => User => Family] = Future(marry)val partial: Future[User => Family] = futureMarry.apply(joe)val family: Future[Family] = partial.apply(jane)Future(marry).apply(joe).apply(jane)Future(marry)(joe)(jane) Using apply compiles iff A is a function 38 WWW.TIKALK.COM
  39. 39. Applicative Functors 39 WWW.TIKALK.COM
  40. 40. • Put value in context• Apply function in a context to value ina context 40 WWW.TIKALK.COM
  41. 41. trait Future[A] { def apply[B, C](b: Future[B]) (implicit ev: A <:< (B => C)) : Future[C]{object Future { def apply[A](a: A): Future[A]} Future((marry _).curried)(joe)(jane) 41 WWW.TIKALK.COM
  42. 42. trait Future[A] { def apply[B, C](b: Future[B]) (implicit ev: A <:< (B => C)) = new Future[C] { def get = Future.this.get(b.get) {{object Future { def apply[A](a: A) = new Future[A] { def get = a } }} 42 WWW.TIKALK.COM
  43. 43. Composing Functions thatReturn Value in a Context 43 WWW.TIKALK.COM
  44. 44. Composing Special Functionsdef findUser(name: String): Future[User]def findProfile(user: User): Future[Profile]findProfile(findUser("joe")) 44 WWW.TIKALK.COM
  45. 45. Monads 45 WWW.TIKALK.COM
  46. 46. trait Future[A] { ... def flatMap[B](f: A => Future[B]): Future[B]}findUser("joe").flatMap(findProfile) 46 WWW.TIKALK.COM
  47. 47. trait Future[A] { ... def flatMap[B](f: A => Future[B]): Future[B] = new Future[B] { def get = f(Future.this.get).get } }} 47 WWW.TIKALK.COM
  48. 48. All Togethertrait Context[A] { def map[B](f: A => B): Context[B] def apply[B, C](b: Context[B]) (implicit ev: A <:< (B => C)): Context[C] def flatMap[B](f: A => Context[B]): Context[B]} 48 WWW.TIKALK.COM
  49. 49. Laws 49 WWW.TIKALK.COM
  50. 50. Idiomatic “interface” for context classes 50 WWW.TIKALK.COM
  51. 51. Monoid• For type A to be (have) a Monoid: • Binary operation „•„: (A, A) => A • Identity element „∅‟: A 51 WWW.TIKALK.COM
  52. 52. • String is a Monoid (2 ways): • Binary operation: append or prepend • Identity element: “”• Int is a Monoid (2 ways): • Binary operation: + or * • Identity element: 0 or 1 52 WWW.TIKALK.COM
  53. 53. • Future[A] is a monoid, if A is a monoid • Binary operation: Future(A#•) • (Future as applicative) • Identity element: Future(A#identity) 53 WWW.TIKALK.COM
  54. 54. Monoids generalize folds 54 WWW.TIKALK.COM
  55. 55. Folds: reduce values to one• List(x,y,z) => ∅ • x • y • z• Option(x) => if Some ∅ • x else ∅ 55 WWW.TIKALK.COM
  56. 56. Unfolds: Create values from initial value and function• 1, if (a < 3) Some(a, a+1) else None • Some(1, 2), Some(2, 3), None • ∅•1•2•3 • If our monoid is a List: • Nil ++ List(1) ++ List(2) ++ List(3) • List(1,2,3) 56 WWW.TIKALK.COM
  57. 57. Since many things aremonoids, we can havemany generic algorithms 57 WWW.TIKALK.COM
  58. 58. Problems with subtyping: • Namespace pollution • Need to control the class • Describes behavior, not „is-a‟ • Sometimes ability is conditional: • Future is a monoid if A is a monoid • Sometimes there are different definitions • E.g., 2 monoids for integers • Maybe a class has several facets • E.g. context of 2 values 58 WWW.TIKALK.COM
  59. 59. Typeclass• Define an API• Create instance for each class thatcan conform to the API 59 WWW.TIKALK.COM
  60. 60. Java example: Comparator 60 WWW.TIKALK.COM
  61. 61. trait Functor[F[_]] { def map[A, B](fa: F[A], f: A => B): F[B]{implicit object FutureHasFunctor extends Functor[Future] { def map[A, B](t: Future[A], f: A => B) = new Future[B] { def get = f(t.get) } }{def age(name: String) = { val functor = implicitly[Functor[Future]] functor.map(findUser(name), {u: User => u.age})} 61 WWW.TIKALK.COM
  62. 62. def age(name: String) (implicit functor: Functor[Future]) { functor.map(findUser(name), {u: User => u.age})} 62 WWW.TIKALK.COM
  63. 63. def age[F[_] : Functor](name: String) { functor.map(findUser(name), {u: User => u.age})} 63 WWW.TIKALK.COM
  64. 64. Generic Programming 64 WWW.TIKALK.COM
  65. 65. def sequence[A, AP[_] : Applicative] (apas: List[AP[A]]): AP[List[A]]val futureOfList = sequence(listOfFutures) 65 WWW.TIKALK.COM
  66. 66. trait Applicative[AP[_]] { def pure[A](a: A) : AP[A] def apply[A, B](ap: AP[A => B], a: AP[A]): AP[B]{ 66 WWW.TIKALK.COM
  67. 67. It is NOT important if youdon’t understand the next slide 67 WWW.TIKALK.COM
  68. 68. def sequence[A, AP[_] : Applicative](apas: List[AP[A]]): AP[List[A]] = { val applicative = implicitly[Applicative[AP]] import applicative._ val cons = pure{x: A => xs: List[A] => x :: xs} apas match { case Nil => pure(Nil) case apa :: apas => val recursion = sequence(apas) // AP[List[A]] val partial = apply(cons, apa) // AP[List[A]=>List[A]] apply(partial, recursion) }} 68 WWW.TIKALK.COM
  69. 69. Beyond 69 WWW.TIKALK.COM
  70. 70. val m = Map[Int, Int]()m.map{case (k, v) => k + v} 70 WWW.TIKALK.COM
  71. 71. def map[B, That](f: A => B) (implicit bf: CanBuildFrom[Repr, B, That]) : That 71 WWW.TIKALK.COM
  72. 72. ?72 WWW.TIKALK.COM
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×