functional reactive programming in clojurescript

40
Taming asynchronous workflows with Functional Reactive Programming LambdaJam - Brisbane, 2013 Leonardo Borges @leonardo_borges www.leonardoborges.com www.thoughtworks.com Friday, 17 May 13

Upload: leonardo-borges

Post on 17-May-2015

8.046 views

Category:

Technology


2 download

DESCRIPTION

FRP Talk given at LambdaJam Australia 2013

TRANSCRIPT

Page 1: Functional Reactive Programming in Clojurescript

Taming asynchronous workflows with Functional

Reactive ProgrammingLambdaJam - Brisbane, 2013

Leonardo Borges@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com

Friday, 17 May 13

Page 2: Functional Reactive Programming in Clojurescript

Leonardo Borges@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com

• Thoughtworker• Functional Programming enthusiast• Clojure Evangelist• Founder & Organiser of the Sydney Clojure User Group (clj-syd)• World traveller• Fan of Murray’s Beers :)

about:me

Friday, 17 May 13

Page 3: Functional Reactive Programming in Clojurescript

Functional programmers like programming with values:

a, b, c...

and pure functions:f, g, h...

Friday, 17 May 13

Page 4: Functional Reactive Programming in Clojurescript

We get new values by applying functions to it

(f a) ;;=> b

Friday, 17 May 13

Page 5: Functional Reactive Programming in Clojurescript

But that’s hardly useful when we have multiple values

(def vals [a b c])

Friday, 17 May 13

Page 6: Functional Reactive Programming in Clojurescript

So we use Higher Order Functions

(map f vals)

Friday, 17 May 13

Page 7: Functional Reactive Programming in Clojurescript

And compose them as we see fit

(-> vals (filter f) (map g) (reduce h))

Friday, 17 May 13

Page 8: Functional Reactive Programming in Clojurescript

But what if the value isn’t known...yet?

a?Friday, 17 May 13

Page 9: Functional Reactive Programming in Clojurescript

We make promises

;; thread#1(def a (promise))

;; ...later in the program(f @a) ;;<= blocks thread

;; thread#2(deliver a 10) ;; now thread#1 continues

Friday, 17 May 13

Page 10: Functional Reactive Programming in Clojurescript

Not great if we want to ‘react’ to a new value

Friday, 17 May 13

Page 11: Functional Reactive Programming in Clojurescript

What about a list of - as of yet unknown - values?

[a,b,c]? ? ?Friday, 17 May 13

Page 12: Functional Reactive Programming in Clojurescript

Or better yet, a value that changes over time?

0

37.5

75

112.5

150

10s 20s 30s 40s 50s 60

Val

ue

TimeFriday, 17 May 13

Page 13: Functional Reactive Programming in Clojurescript

Does this sound familiar?

Friday, 17 May 13

Page 14: Functional Reactive Programming in Clojurescript

Spreadsheets: a poor man’s reactive programming model

Values

Function

Friday, 17 May 13

Page 15: Functional Reactive Programming in Clojurescript

Spreadsheets: a poor man’s reactive programming model

As we change a value

Our function cell reacts to the

change

Friday, 17 May 13

Page 16: Functional Reactive Programming in Clojurescript

‘Changing a value’ is an event

Several events over time form an event stream

Friday, 17 May 13

Page 17: Functional Reactive Programming in Clojurescript

“Functional Reactive Programming is about effectively processing event streams without

explicitly managing state”- me

Friday, 17 May 13

Page 18: Functional Reactive Programming in Clojurescript

“FRP is about handling time-varying values like they were

regular values.”- Haskell wiki

Friday, 17 May 13

Page 19: Functional Reactive Programming in Clojurescript

We’ll use Reactive Extensions (Rx) - but there are many

implementations

Friday, 17 May 13

Page 20: Functional Reactive Programming in Clojurescript

In Rx, event streams are called Observable sequences

Friday, 17 May 13

Page 21: Functional Reactive Programming in Clojurescript

Rx 101

(-> (.returnValue js/Rx.Observable 42) (.map #(* % 2)) (.subscribe #(.log js/console %)))

;; 84

Friday, 17 May 13

Page 22: Functional Reactive Programming in Clojurescript

Rx 101

(-> (.fromArray js/Rx.Observable (clj->js [10 20 30])) (.map #(* % 2)) (.reduce +) (.subscribe #(.log js/console %)))

;; 120

Friday, 17 May 13

Page 23: Functional Reactive Programming in Clojurescript

Rx 101(defn project-range [n] (.returnValue js/Rx.Observable (range n)))

(-> (.fromArray js/Rx.Observable (clj->js [1 2 3])) (.selectMany project-range) (.subscribe #(.log js/console (clj->js %))))

;; [0];; [0 1];; [0 1 2]

Friday, 17 May 13

Page 24: Functional Reactive Programming in Clojurescript

Observables are Monads

Friday, 17 May 13

Page 25: Functional Reactive Programming in Clojurescript

The Monad Type Class

class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b

Friday, 17 May 13

Page 26: Functional Reactive Programming in Clojurescript

Monad functions: return

return :: a -> m a

returnValue :: a -> Observable a

Friday, 17 May 13

Page 27: Functional Reactive Programming in Clojurescript

(>>=) :: m a -> (a -> m b) -> m b

selectMany :: Observable a -> (a -> Observable b) -> Observable b

Monad functions: >>= (bind)

Friday, 17 May 13

Page 28: Functional Reactive Programming in Clojurescript

Demo: Simple polling app

Friday, 17 May 13

Page 29: Functional Reactive Programming in Clojurescript

Server exposes poll questions and results

e.g.:{:id 7 :question "Which is the best music style?" :results {:a 10 :b 47 :c 17}}

Friday, 17 May 13

Page 30: Functional Reactive Programming in Clojurescript

What we want• Render results• Continuously poll server every 2 secs• If current question is the same as the previous one update results; • Otherwise:• Stop polling;• Display countdown message;• Render new question and results;• Restart polling;

Friday, 17 May 13

Page 31: Functional Reactive Programming in Clojurescript

The core idea

Friday, 17 May 13

Page 32: Functional Reactive Programming in Clojurescript

Turn server results into an event stream

112334

Friday, 17 May 13

Page 33: Functional Reactive Programming in Clojurescript

Duplicate stream, skipping one

112334

123345

skip 1

Friday, 17 May 13

Page 34: Functional Reactive Programming in Clojurescript

Zip them together112334

1

2

zip

2

3

3

3

3

4

4

5 1

123345

1

Friday, 17 May 13

Page 35: Functional Reactive Programming in Clojurescript

Now we have access to both the previous and current

results, with no local variables

Friday, 17 May 13

Page 36: Functional Reactive Programming in Clojurescript

Show me the code!

https://github.com/leonardoborges/frp-codeFriday, 17 May 13

Page 37: Functional Reactive Programming in Clojurescript

(def results-connectable (let [obs (-> js/Rx.Observable (.interval 2000) (.selectMany results-observable) (.publish) (.refCount)) obs-1 (.skip obs 1)] (.zip obs obs-1 (fn [prev curr] {:prev prev :curr curr}))))

Turn server results into an event stream{

The core idea

Clone stream, skip one

Zip them together {Friday, 17 May 13

Page 38: Functional Reactive Programming in Clojurescript

“FRP is about handling time-varying values like they were

regular values.”- Haskell wiki

Friday, 17 May 13

Page 39: Functional Reactive Programming in Clojurescript

Questions?Leonardo Borges

@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com

Friday, 17 May 13

Page 40: Functional Reactive Programming in Clojurescript

ReferencesCode - https://github.com/leonardoborges/frp-code

RxJS - https://github.com/Reactive-Extensions/RxJSRxJava - https://github.com/Netflix/RxJava

Other FRP implementations:Reactive-banana - http://www.haskell.org/haskellwiki/Reactive-bananaJavelin (Clojurescript) - https://github.com/tailrecursion/javelinBacon.js - https://github.com/raimohanska/bacon.js

Friday, 17 May 13