Taming asynchronous workflows with Functional Reactive ...€¦ · Taming asynchronous workflows...

Post on 31-May-2020

23 views 0 download

transcript

Taming asynchronous workflows with Functional

Reactive ProgrammingLambdaJam - Brisbane, 2013

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

Friday, 17 May 13

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

Functional programmers like programming with values:

a, b, c...

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

Friday, 17 May 13

We get new values by applying functions to it

(f a) ;;=> b

Friday, 17 May 13

But that’s hardly useful when we have multiple values

(def vals [a b c])

Friday, 17 May 13

So we use Higher Order Functions

(map f vals)

Friday, 17 May 13

And compose them as we see fit

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

Friday, 17 May 13

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

a?Friday, 17 May 13

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

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

Friday, 17 May 13

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

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

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

Does this sound familiar?

Friday, 17 May 13

Spreadsheets: a poor man’s reactive programming model

Values

Function

Friday, 17 May 13

Spreadsheets: a poor man’s reactive programming model

As we change a value

Our function cell reacts to the

change

Friday, 17 May 13

‘Changing a value’ is an event

Several events over time form an event stream

Friday, 17 May 13

“Functional Reactive Programming is about effectively processing event streams without

explicitly managing state”- me

Friday, 17 May 13

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

regular values.”- Haskell wiki

Friday, 17 May 13

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

implementations

Friday, 17 May 13

In Rx, event streams are called Observable sequences

Friday, 17 May 13

Rx 101

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

;; 84

Friday, 17 May 13

Rx 101

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

;; 120

Friday, 17 May 13

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

Observables are Monads

Friday, 17 May 13

The Monad Type Class

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

Friday, 17 May 13

Monad functions: return

return :: a -> m a

returnValue :: a -> Observable a

Friday, 17 May 13

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

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

Monad functions: >>= (bind)

Friday, 17 May 13

Demo: Simple polling app

Friday, 17 May 13

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

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

The core idea

Friday, 17 May 13

Turn server results into an event stream

112334

Friday, 17 May 13

Duplicate stream, skipping one

112334

123345

skip 1

Friday, 17 May 13

Zip them together112334

1

2

zip

2

3

3

3

3

4

4

5 1

123345

1

Friday, 17 May 13

Now we have access to both the previous and current

results, with no local variables

Friday, 17 May 13

Show me the code!

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

(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

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

regular values.”- Haskell wiki

Friday, 17 May 13

Questions?Leonardo Borges

@leonardo_borgeswww.leonardoborges.comwww.thoughtworks.com

Friday, 17 May 13

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