functional programming from oo perspective (sayeret lambda lecture)

72
26-Oct-11 Ittay Dror [email protected] @ittayd http://www.tikalk.com/blogs/ittayd Functional Programming From OOP perspective

Upload: ittayd

Post on 07-May-2015

872 views

Category:

Technology


1 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Functional Programming from OO perspective (Sayeret Lambda lecture)

26-Oct-11

Ittay Dror

[email protected]

@ittayd

http://www.tikalk.com/blogs/ittayd

Functional Programming

From OOP perspective

Page 2: Functional Programming from OO perspective (Sayeret Lambda lecture)

2 WWW.TIKALK.COM

What is FP?

Page 3: Functional Programming from OO perspective (Sayeret Lambda lecture)

3 WWW.TIKALK.COM

“a programming paradigm that

treats computation as the

evaluation of mathematical

functions and avoids state and

mutable data”

Page 4: Functional Programming from OO perspective (Sayeret Lambda lecture)

4 WWW.TIKALK.COM

• Functions as values • Immutable data structures • Mathematical models • Referential transparency

Page 5: Functional Programming from OO perspective (Sayeret Lambda lecture)

5 WWW.TIKALK.COM

Why Should We Care?

Page 6: Functional Programming from OO perspective (Sayeret Lambda lecture)

6 WWW.TIKALK.COM

Not everything is an

object

Page 7: Functional Programming from OO perspective (Sayeret Lambda lecture)

7 WWW.TIKALK.COM

service.init val data = service.get service.close println(data)

May Forget

Nothing to return?

May forget / call twice

Page 8: Functional Programming from OO perspective (Sayeret Lambda lecture)

8 WWW.TIKALK.COM

IOC

Page 9: Functional Programming from OO perspective (Sayeret Lambda lecture)

9 WWW.TIKALK.COM

class Service { def withData[T](f: Data => T) { init if (thereIsData) f(getData) close } }

service.witData(println)

Page 10: Functional Programming from OO perspective (Sayeret Lambda lecture)

10 WWW.TIKALK.COM

Simplification

Page 11: Functional Programming from OO perspective (Sayeret Lambda lecture)

11 WWW.TIKALK.COM

In OOP: trait DataConsumer[T] { def withData(data: Data): T {

In FP:

Data => T

Page 12: Functional Programming from OO perspective (Sayeret Lambda lecture)

12 WWW.TIKALK.COM

Factories are partially

applied functions

Page 13: Functional Programming from OO perspective (Sayeret Lambda lecture)

13 WWW.TIKALK.COM

val factory_: File => String => User = file => name => readFromFile(name) val factory: String => User = factory_(usersFile)

Look ma, no interfaces

Page 14: Functional Programming from OO perspective (Sayeret Lambda lecture)

14 WWW.TIKALK.COM

Security

Page 15: Functional Programming from OO perspective (Sayeret Lambda lecture)

15 WWW.TIKALK.COM

Immutable data is

sharable

Page 16: Functional Programming from OO perspective (Sayeret Lambda lecture)

16 WWW.TIKALK.COM

Instead of modifying,

create new

Page 17: Functional Programming from OO perspective (Sayeret Lambda lecture)

17 WWW.TIKALK.COM

Abstraction

Page 18: Functional Programming from OO perspective (Sayeret Lambda lecture)

18 WWW.TIKALK.COM

Functors, Applicatives,

Monads

Page 19: Functional Programming from OO perspective (Sayeret Lambda lecture)

19 WWW.TIKALK.COM

Usual way of describing:

WTF??

Page 20: Functional Programming from OO perspective (Sayeret Lambda lecture)

20 WWW.TIKALK.COM

OO way: Design Patterns

Page 21: Functional Programming from OO perspective (Sayeret Lambda lecture)

21 WWW.TIKALK.COM

Values in a context

Page 22: Functional Programming from OO perspective (Sayeret Lambda lecture)

22 WWW.TIKALK.COM

Option[X]

List[X]

Future[X]

Page 23: Functional Programming from OO perspective (Sayeret Lambda lecture)

23 WWW.TIKALK.COM

trait Future[A] { def get: A {

def findUser(name: String): Future[User] = … … val future = findUser(userName) val user = future.get println(user)

Page 24: Functional Programming from OO perspective (Sayeret Lambda lecture)

24 WWW.TIKALK.COM

val future = findUser(userName) future.onReady{user => println(user)}

trait Future[A] { def onReady(f: A => Unit) }

Page 25: Functional Programming from OO perspective (Sayeret Lambda lecture)

25 WWW.TIKALK.COM

Functor

Page 26: Functional Programming from OO perspective (Sayeret Lambda lecture)

26 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 => user.age}

Page 27: Functional Programming from OO perspective (Sayeret Lambda lecture)

27 WWW.TIKALK.COM

list.map(compute)

Vs.

val result = new ArrayList(list.size) for (i <- 0 to (list.size - 1)) { result += compute(list(i)) } result

Page 28: Functional Programming from OO perspective (Sayeret Lambda lecture)

28 WWW.TIKALK.COM

list.par.map(compute)

Vs.

class ComputeTask extends RecursiveTask { def compute = // split and call invokeAll... { val pool = new ForkJoinPool() val task = new ComputeTask() pool.invoke(task)

Page 29: Functional Programming from OO perspective (Sayeret Lambda lecture)

29 WWW.TIKALK.COM

trait Future[A] { def get: A def map[B](f: A => B) = new Future[B] { def get = f(Future.this.get)

{ {

Page 30: Functional Programming from OO perspective (Sayeret Lambda lecture)

30 WWW.TIKALK.COM

def marry(man: User, woman: User): Family = ⠄⠄⠄ val joe = findUser("joe") val jane = findUser("jane")

Get Joe and Jane married

Page 31: Functional Programming from OO perspective (Sayeret Lambda lecture)

31 WWW.TIKALK.COM

joe.map{joe => jane.map{jane => marry(joe, jane)}}

User => Family

Future[Family]

User => Future[Family]

Future[Future[Family]]

Page 32: Functional Programming from OO perspective (Sayeret Lambda lecture)

32 WWW.TIKALK.COM

trait Future[A] { def apply[B, C](other: Future[B], f: (A, B) => C): Future[C] }

joe.apply(jane, marry)

Attempt I

Page 33: Functional Programming from OO perspective (Sayeret Lambda lecture)

33 WWW.TIKALK.COM

It is easier to work with

single argument functions

Page 34: Functional Programming from OO perspective (Sayeret Lambda lecture)

34 WWW.TIKALK.COM

Curried Functions

val func: Int => Int => Int = a => b => a + b

(marry _).curried

Page 35: Functional Programming from OO perspective (Sayeret Lambda lecture)

35 WWW.TIKALK.COM

trait Future[A] { ... def apply[B](f: Future[A => B]): Future[B] {

Attempt II

Page 36: Functional Programming from OO perspective (Sayeret Lambda lecture)

36 WWW.TIKALK.COM

joe.apply(jane.map((marry _).curried))

User => User => Family

Future[User => Family]

User => Future[Family]

Page 37: Functional Programming from OO perspective (Sayeret Lambda lecture)

37 WWW.TIKALK.COM

We can do better

Page 38: Functional Programming from OO perspective (Sayeret Lambda lecture)

38 WWW.TIKALK.COM

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

Page 39: Functional Programming from OO perspective (Sayeret Lambda lecture)

39 WWW.TIKALK.COM

Applicative Functors

Page 40: Functional Programming from OO perspective (Sayeret Lambda lecture)

40 WWW.TIKALK.COM

• Put value in context • Apply function in a context to value in a context

Page 41: Functional Programming from OO perspective (Sayeret Lambda lecture)

41 WWW.TIKALK.COM

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)

Page 42: Functional Programming from OO perspective (Sayeret Lambda lecture)

42 WWW.TIKALK.COM

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 } } }

Page 43: Functional Programming from OO perspective (Sayeret Lambda lecture)

43 WWW.TIKALK.COM

Composing Functions that

Return Value in a Context

Page 44: Functional Programming from OO perspective (Sayeret Lambda lecture)

44 WWW.TIKALK.COM

Composing Special

Functions

def findUser(name: String): Future[User] def findProfile(user: User): Future[Profile]

findProfile(findUser("joe"))

Page 45: Functional Programming from OO perspective (Sayeret Lambda lecture)

45 WWW.TIKALK.COM

Monads

Page 46: Functional Programming from OO perspective (Sayeret Lambda lecture)

46 WWW.TIKALK.COM

trait Future[A] { ... def flatMap[B](f: A => Future[B]): Future[B] }

findUser("joe").flatMap(findProfile)

Page 47: Functional Programming from OO perspective (Sayeret Lambda lecture)

47 WWW.TIKALK.COM

trait Future[A] { ... def flatMap[B](f: A => Future[B]): Future[B] = new Future[B] { def get = f(Future.this.get).get } } }

Page 48: Functional Programming from OO perspective (Sayeret Lambda lecture)

48 WWW.TIKALK.COM

All Together

trait 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] }

Page 49: Functional Programming from OO perspective (Sayeret Lambda lecture)

49 WWW.TIKALK.COM

Laws

Page 50: Functional Programming from OO perspective (Sayeret Lambda lecture)

50 WWW.TIKALK.COM

Idiomatic “interface” for

context classes

Page 51: Functional Programming from OO perspective (Sayeret Lambda lecture)

51 WWW.TIKALK.COM

Monoid • For type A to be (have) a Monoid:

• Binary operation „•„: (A, A) => A • Identity element „∅‟: A

Page 52: Functional Programming from OO perspective (Sayeret Lambda lecture)

52 WWW.TIKALK.COM

• Int is a Monoid (2 ways): • Binary operation: + or * • Identity element: 0 or 1

• String is a Monoid (2 ways): • Binary operation: append or prepend • Identity element: “”

Page 53: Functional Programming from OO perspective (Sayeret Lambda lecture)

53 WWW.TIKALK.COM

• Future[A] is a monoid, if A is a monoid • Binary operation: Future(A#•)

• (Future as applicative) • Identity element: Future(A#identity)

Page 54: Functional Programming from OO perspective (Sayeret Lambda lecture)

54 WWW.TIKALK.COM

Monoids generalize folds

Page 55: Functional Programming from OO perspective (Sayeret Lambda lecture)

55 WWW.TIKALK.COM

Folds: reduce values to

one

• List(x,y,z) => ∅ • x • y • z • Option(x) => if Some ∅ • x else ∅

Page 56: Functional Programming from OO perspective (Sayeret Lambda lecture)

56 WWW.TIKALK.COM

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)

Page 57: Functional Programming from OO perspective (Sayeret Lambda lecture)

57 WWW.TIKALK.COM

Since many things are

monoids, we can have

many generic algorithms

Page 58: Functional Programming from OO perspective (Sayeret Lambda lecture)

58 WWW.TIKALK.COM

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

Page 59: Functional Programming from OO perspective (Sayeret Lambda lecture)

59 WWW.TIKALK.COM

Typeclass

• Define an API • Create instance for each class that can conform to the API

Page 60: Functional Programming from OO perspective (Sayeret Lambda lecture)

60 WWW.TIKALK.COM

Java example:

Comparator

Page 61: Functional Programming from OO perspective (Sayeret Lambda lecture)

61 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 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}) }

Page 62: Functional Programming from OO perspective (Sayeret Lambda lecture)

62 WWW.TIKALK.COM

def age(name: String) (implicit functor: Functor[Future]) { functor.map(findUser(name), {u: User => u.age}) }

Page 63: Functional Programming from OO perspective (Sayeret Lambda lecture)

63 WWW.TIKALK.COM

def age[F[_] : Functor](name: String) { functor.map(findUser(name), {u: User => u.age}) }

Page 64: Functional Programming from OO perspective (Sayeret Lambda lecture)

64 WWW.TIKALK.COM

Generic Programming

Page 65: Functional Programming from OO perspective (Sayeret Lambda lecture)

65 WWW.TIKALK.COM

def sequence[A, AP[_] : Applicative] (apas: List[AP[A]]): AP[List[A]]

val futureOfList = sequence(listOfFutures)

Page 66: Functional Programming from OO perspective (Sayeret Lambda lecture)

66 WWW.TIKALK.COM

trait Applicative[AP[_]] { def pure[A](a: A) : AP[A] def apply[A, B](ap: AP[A => B], a: AP[A]): AP[B] {

Page 67: Functional Programming from OO perspective (Sayeret Lambda lecture)

67 WWW.TIKALK.COM

It is NOT important if you

don’t understand the next

slide

Page 68: Functional Programming from OO perspective (Sayeret Lambda lecture)

68 WWW.TIKALK.COM

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) } }

Page 69: Functional Programming from OO perspective (Sayeret Lambda lecture)

69 WWW.TIKALK.COM

Beyond

Page 70: Functional Programming from OO perspective (Sayeret Lambda lecture)

70 WWW.TIKALK.COM

val m = Map[Int, Int]() m.map{case (k, v) => k + v}

Page 71: Functional Programming from OO perspective (Sayeret Lambda lecture)

71 WWW.TIKALK.COM

def map[B, That](f: A => B) (implicit bf: CanBuildFrom[Repr, B, That]) : That

Page 72: Functional Programming from OO perspective (Sayeret Lambda lecture)

72 WWW.TIKALK.COM

?