SlideShare a Scribd company logo
Taming Asynchronous Workflows with
Functional Reactive Programming
EuroClojure - Kraków, 2014
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com
About
‣ ThoughtWorker
‣ Functional Programming & Clojure
advocate
‣ Founder of the Sydney Clojure User
Group
‣ Currently writing “Clojure Reactive
Programming”
Taming Asynchronous Workflows with
Functional Reactive Programming
Taming Asynchronous Workflows with
Functional Reactive Programming
Compositional Event Systems
http://bit.ly/conal-ces
http://bit.ly/rx-commit
http://bit.ly/reactive-cocoa-commit
There are only two hard things in
Computer Science: cache invalidation
and naming things. - Phil Karlton
:)
Ok, so what’s the difference?
‣ Created in 1997 by Conal Elliott for the reactive animations framework Fran, in Haskell
‣ Since then other implementations have appeared: reactive-banana, NetWire, Sodium
(all in Haskell)
‣ And then FRP-inspired ones: Rx[.NET | Java | JS], Baconjs, reagi (Clojurescript)
‣ Main abstractions: Behaviors e Events
More about FRP
‣ Created in 1997 by Conal Elliott for the reactive animations framework Fran, in Haskell
‣ Since then other implementations have appeared: reactive-banana, NetWire, Sodium
(all in Haskell)
‣ And then FRP-inspired ones: Rx[.NET | Java | JS], Baconjs, reagi (Clojure[script])
‣ Main abstractions: Behaviors e Events
‣ Traditionally defined as:
type Behavior a = [Time] -> [a]!
type Event a = [Time] -> [Maybe a]
More about FRP
We’ll be focusing on
Compositional Event Systems
Prelude
Imperative programming describes computations as a series of actions
which modify program state
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5]; Requires a variable
to store state
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
We iterate over the
array
Imperative programming describes computations as a series of actions
which modify program state
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
And then we filter the
items…
Imperative programming describes computations as a series of actions
which modify program state
var result = 1;!
numbers.forEach(function(n){!
if(n % 2 === 0) {!
result *= n;!
}!
});!
console.log( result );!
// 8!
var numbers = [1,2,3,4,5];
…and perform the
multiplication in the
same function
Imperative programming describes computations as a series of actions
which modify program state
(def numbers [1 2 3 4 5])!
!
(def result!
(->> numbers!
(filter even?)!
(reduce *)))!
!
(prn result)!
!
;; 8
In functional programming, we describe what we want to do but not
how we want it done
That is, there are no variables with
local state and we get better re-use
from single purpose functions
Compositional Event Systems brings the same
principle to values we work with daily: DOM
events (clicks, key presses, mouse movement),
Ajax calls…
Let’s look at an example
Game movements in
Javascript
var JUMP = 38, CROUCH = 40,!
LEFT = 37, RIGHT = 39,!
FIRE = 32;!
!
function goRight (){!
$(‘h1').html("Going right...");!
}!
!
function goLeft (){!
$(‘h1').html("Going left...");!
}!
!
function jump (){!
$('h1').html("Jumping...");!
}!
!
function crouch (){!
$('h1').html("Crouching...");!
}!
!
function fire (){!
$('h1').html("Firing...");!
}
Game movements in
Javascript
$(window.document).keyup(function(event){!
switch(event.keyCode){!
case JUMP :!
jump();!
break;!
case CROUCH:!
crouch();!
break;!
case LEFT :!
goLeft();!
break;!
case RIGHT :!
goRight();!
break;!
case FIRE :!
fire();!
break;!
};!
});
We now have limitations similar to
the multiplication example
Let us think key presses as a list of keys
over a period of time
This leads to the following solution
Reactive game movements
(def UP 38) (def RIGHT 39)!
(def DOWN 40) (def LEFT 37)!
(def FIRE 32) (def PAUSE 80)!
!
!
(def source (.fromEvent js/Rx.Observable js/window "keyup"));!
!
(-> source (.filter #(= UP %)) (.subscribe jump))!
(-> source (.filter #(= DOWN %)) (.subscribe crouch))!
(-> source (.filter #(= RIGHT %)) (.subscribe go-right))!
(-> source (.filter #(= LEFT %)) (.subscribe go-left))!
(-> source (.filter #(= FIRE %)) (.subscribe fire))!
http://bit.ly/rxjava-github
http://bit.ly/rxjs-github
Reactive game movements
(def UP 38) (def RIGHT 39)!
(def DOWN 40) (def LEFT 37)!
(def FIRE 32) (def PAUSE 80)!
!
!
(def source (.fromEvent js/Rx.Observable js/window "keyup"));!
!
(-> source (.filter #(= UP %)) (.subscribe jump))!
(-> source (.filter #(= DOWN %)) (.subscribe crouch))!
(-> source (.filter #(= RIGHT %)) (.subscribe go-right))!
(-> source (.filter #(= LEFT %)) (.subscribe go-left))!
(-> source (.filter #(= FIRE %)) (.subscribe fire))!
http://bit.ly/rxjava-github
http://bit.ly/rxjs-github
Behaviours
;; behavior examples!
(def time-b (r/behavior (System/currentTimeMillis)))!
@time-b!
;; 1403691712988!
@time-b!
;; 1403691714156!
http://bit.ly/reagi
Behaviours to Event Streams
http://bit.ly/reagi
(def time-e (r/sample 1000 time-b))!
!
(->> time-e (r/map println))!
;; t + 1 sec!
;; 1403692132586!
;; t + 2 sec:!
;; 1403692133587!
Combinators
(-> (Observable/return 42)!
(.map #(* % 2))!
(.subscribe println))!
!
;; 84!
!
(-> (Observable/from [10 20 30])!
(.map #(* % 2))!
(.reduce +)!
(.subscribe println))!
!
;; 120!
Combinators: flatMap /
selectMany
(defn project-range [n]!
(Rx.Observable/return (range n)))!
!
(-> (Observable/from [1 2 3])!
(.selectMany project-range)!
(.subscribe (rx/fn* println)))!
!
;; 0!
;; 0!
;; 1!
;; 0!
;; 1!
;; 2!
?
(Observable/from [1 2 3])
1 2 3
(-> (Observable/from [1 2 3])!
(.selectMany project-range)!
…)
(project-range 2)
0 1
(project-range 1)
0
(project-range 3)
0 1 2
0 0 1 0 1 2
What about network IO?
‣ Callback hell :(
‣ Clojure promises don’t compose
‣ Promises in JS are slightly better but have limitations
‣ They work well for a single level of values
‣ However are a poor composition mechanism
‣ What if we have a series of values that changes over time?
Demo: Simple polling app
This is what the server gives us
{:id 7!
:question "Which is the best music style?"!
:results {:a 10!
:b 47!
:c 17}}!
And this is 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;
The core idea
First, we need to turn the results into a stream
4 3 3 2 1 1
So we duplicate the stream, skipping one element
4 3 3 2 1 1
5 4 3 3 2 1
(skip 1)
Finally, we zip the streams
4 3 3 2 1 1
5 4 3 3 2 1
zip
[5,4] [4,3] [3,3] [3,2] [2,1] [1,1]
The core idea, in code
(defn results-observable!
"Returns an Observable that yields server-side questions/results"!
[]!
(.create js/Rx.Observable!
(fn [observer]!
(srm/rpc!
(poll-results) [resp]!
(.onNext observer resp))!
(fn [] (.log js/console "Disposed")))))
The core idea, in code
(def results-connectable!
"Zips results-observable with itself, but shifted by 1.!
This simulates a 'buffer' or 'window' of results"!
(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 results into a
stream
The core idea, in code
(def results-connectable!
"Zips results-observable with itself, but shifted by 1.!
This simulates a 'buffer' or 'window' of results"!
(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}))))!
Clone stream, skip
one
The core idea, in code
(def results-connectable!
"Zips results-observable with itself, but shifted by 1.!
This simulates a 'buffer' or 'window' of results"!
(let [obs (-> js/Rx.Observable!
(.interval 2000)!
(.selectMany results-observable))!
obs-1 (.skip obs 1)]!
(.zip obs obs-1 (fn [prev curr]!
{:prev prev!
:curr curr}))))!
Zip them together
Can we do better?
Buffering
(def results-buffer!
"Returns an Observable with results buffered into a 2-element vector"!
(-> js/Rx.Observable!
(.interval 2000)!
(.selectMany results-observable)!
(.bufferWithCount 2)))!
Live Demo
"FRP is about handling time-varying
values like they were regular values" -
Haskell Wiki
"FRP is about handling time-varying
values like they were regular values" -
Haskell Wiki
It also applies to FRP-inspired systems
Why not use core.async?
Previously, with CES
(-> (Observable/from [10 20 30])!
(.map (rx/fn [v] (* v 2)))!
(.reduce (rx/fn* +)!
(.subscribe (rx/fn* println)))))
With core.async
(defn from-array [coll]!
(let [stream-c (chan)]!
(go (doseq [n coll]!
(>! stream-c n))!
(close! stream-c))!
stream-c))!
!
(def c (->> (async-from [10 20 30])!
(a/map< #(* % 2))!
(a/reduce + 0)))!
!
(go-loop []!
(when-let [v (<! c)]!
(println v)!
(recur)))!
Multiple subscribers with CES
(def sum-of-squares (-> (Observable/from [10 20 30])!
(.map (rx/fn [v] (* v 2)))!
(.reduce (rx/fn* +))))!
!
!
!
(.subscribe sum-of-squares (rx/action* println)) ;; 120!
(.subscribe sum-of-squares (rx/action* println)) ;; 120
Multiple subscribers with core.async [1/3]
(def in (chan))!
(def sum-of-squares (->> in!
(a/map< #(* % 2))!
(a/reduce + 0)))!
Multiple subscribers with core.async [2/3]
(def publication (pub sum-of-squares (fn [_] :n)))!
!
(def sub-1 (chan))!
(def sub-2 (chan))!
!
(sub publication :n sub-1)!
(sub publication :n sub-2)
Multiple subscribers with core.async [3/3]
(go (doseq [n [10 20 30]]!
(>! in n))!
(close! in))!
!
(go-loop []!
(when-let [v (<! sub-1)]!
(prn v)!
(recur))) ;; 120!
!
(go-loop []!
(when-let [v (<! sub-2)]!
(prn v)!
(recur))) ;; 120
core.async operates at a lower level of
abstraction
it is however a great foundation for a
FRP-inspired framework
Reagi - shown earlier - is built on top of
core.async
http://bit.ly/reagi
Bonus example: a reactive API to
AWS
Bonus example: a reactive API to
AWS
‣ Retrieve list of resources from a stack
(CloudFormation.describeStackResources)
‣ For each EC2 Instance, call EC2.describeInstances to retrieve status
‣ For each RDS Instance, call RDS.describeDBInstances to retrieve status
‣ Merge results and display
Step 1: turn api calls into streams
(defn resources-stream [stack-name]!
(.create js/Rx.Observable!
(fn [observer]!
(.describeStackResources js/cloudFormation #js {"StackName" : stackName}!
(fn [err data]!
(if err!
(.onError observer err)!
(doseq [resource data]!
(.onNext observer resource))!
(.onCompleted observer)))!
(fn [] (.log js/console "Disposed")))))
Step 1: turn api calls into streams
(defn ec2-instance-stream [resource-ids]!
(.create js/Rx.Observable!
(fn [observer]!
(.describeInstaces js/ec2 #js {"InstanceIds" resource-ids}!
(fn [err data]!
(if err!
(.onError observer err)!
(doseq [instance data]!
(.onNext observer instance)))!
(.onCompleted observer)))!
(fn [] (.log js/console "Disposed")))))!
Step 1: turn api calls into streams
(defn rds-instance-stream [resource-id]!
(.create js/Rx.Observable!
(fn [observer]!
(.describeDBInstances js/rds #js {"DBInstanceIdentifier" resource-id}!
(fn [err data]!
(if err!
(.onError observer err)!
(.onNext observer data))!
(.onCompleted observer)))!
(fn [] (.log js/console "Disposed")))))
Step 2: transform the different API
responses into a common output
(def resources (resourcesStream "my-stack"))!
!
(def ec2-data (-> resources!
(.filter ec2?)!
(.map :resource-id)!
(.flatMap ec2-instance-stream)!
(.map (fn [data] {:instance-id ...!
:status ...}))))!
!
(def rds-data (-> resources!
(.filter rds?)!
(.map :resource-id)!
(.flatMap rds-instance-stream)!
(.map (fn [data] {:instance-id ...!
:status ...}))))!
Step 3: merge results and update UI
(-> ec2-data!
(.merge rds-data)!
(.reduce conj [])!
(.subscribe (fn [data] (update-interface ...))))
Easy to reason about, maintain
and test
References
!
‣ Conal Elliott “Functional Reactive Animation” paper: http://bit.ly/conal-frp
!
FRP-inspired frameworks:
‣ Reagi: http://bit.ly/reagi
‣ RxJS: http://bit.ly/rxjs-github
‣ RxJava: http://bit.ly/rxjava-github
‣ Bacon.js: https://github.com/baconjs/bacon.js
!
FRP implementations:
‣ Reactive Banana: http://www.haskell.org/haskellwiki/Reactive-banana
‣ Elm: http://elm-lang.org/
‣ NetWire: http://www.haskell.org/haskellwiki/Netwire
Thanks!
Questions?
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com

More Related Content

What's hot (20)

PPTX
Musculature of the Head
Pam Fabie
 
PPT
Arterial Blood Gas analysis
Dr Shibu Chacko MBE
 
PPTX
Circulatory system - The Heart
Jorge Pinto
 
PPTX
Transport of oxygen (the guyton and hall physiology)
Maryam Fida
 
PPT
Capillary function
Ministry of Health, Myanmar
 
PPT
Unit 5 respiratory system nrs 237 new
menwar
 
PPTX
Hypoxia
Yogesh Ramasamy
 
PPTX
Circulation and Blood
sidkrish123
 
PPTX
Cardiac cycle
med_students0
 
PPTX
Anatomy of Pituitary
Abhishek Rai
 
PPTX
Regulation of-arterial-blood-pressure
Dr Abdul Majid Siddiqui
 
PPTX
Starling forces
muti ullah
 
PPT
Respiratory Physiology & Respiratory Function During Anesthesia
Dang Thanh Tuan
 
PPT
4@neaural control of respiration
Mohanad Mohanad
 
PDF
physiological dead space and its measurements
meducationdotnet
 
PPTX
Chapter 22: Respiratory System (#2)
Caroline Tokarski
 
PPTX
Physiological Regulation of Arterial Blood Pressure.pptx
Kpgu
 
PPT
Pediatric Airway, Respiratory Distress &amp; Failure, &amp; Hypoperfusion Eme...
Steve Marchbank
 
PPT
Respiratory physiology
Chy Yong
 
PPTX
Blood vessels physiology
Asha damodar
 
Musculature of the Head
Pam Fabie
 
Arterial Blood Gas analysis
Dr Shibu Chacko MBE
 
Circulatory system - The Heart
Jorge Pinto
 
Transport of oxygen (the guyton and hall physiology)
Maryam Fida
 
Capillary function
Ministry of Health, Myanmar
 
Unit 5 respiratory system nrs 237 new
menwar
 
Circulation and Blood
sidkrish123
 
Cardiac cycle
med_students0
 
Anatomy of Pituitary
Abhishek Rai
 
Regulation of-arterial-blood-pressure
Dr Abdul Majid Siddiqui
 
Starling forces
muti ullah
 
Respiratory Physiology & Respiratory Function During Anesthesia
Dang Thanh Tuan
 
4@neaural control of respiration
Mohanad Mohanad
 
physiological dead space and its measurements
meducationdotnet
 
Chapter 22: Respiratory System (#2)
Caroline Tokarski
 
Physiological Regulation of Arterial Blood Pressure.pptx
Kpgu
 
Pediatric Airway, Respiratory Distress &amp; Failure, &amp; Hypoperfusion Eme...
Steve Marchbank
 
Respiratory physiology
Chy Yong
 
Blood vessels physiology
Asha damodar
 

Viewers also liked (20)

PDF
Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)
Dimitris Kolovos
 
PPTX
Functional Reactive Programming with RxJS
stefanmayer13
 
PPTX
Rx- Reactive Extensions for .NET
Jakub Malý
 
PDF
A Quick Intro to ReactiveX
Troy Miles
 
PDF
Functional Reactive Programming
Olav Haugen
 
PDF
The algebra of library design
Leonardo Borges
 
PPTX
Functional programming in C#
Thomas Jaskula
 
PDF
What is Reactive programming?
Kevin Webber
 
PPTX
Functional Programming with C#
EastBanc Tachnologies
 
PPTX
ASP.NET MVC Core
Eduard Tomàs
 
PDF
Reactive Programming with JavaScript
Codemotion
 
PDF
Functional Programming in C# and F#
Alfonso Garcia-Caro
 
KEY
Functional Reactive Programming in Javascript
Brian Lonsdorf
 
PPTX
02 - [ASP.NET Core] ASP.NET Core MVC
Cellenza
 
PPTX
Frisby Api automation
Dineesha Suraweera
 
PDF
Microservices: Architecture for the Real-time Organization
Kevin Webber
 
PPTX
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache Accumulo
Joe Stein
 
PDF
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...
Wes McKinney
 
PDF
RxJS - The Reactive Extensions for JavaScript
Viliam Elischer
 
PPTX
Reactive Extensions for JavaScript
Jim Wooley
 
Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)
Dimitris Kolovos
 
Functional Reactive Programming with RxJS
stefanmayer13
 
Rx- Reactive Extensions for .NET
Jakub Malý
 
A Quick Intro to ReactiveX
Troy Miles
 
Functional Reactive Programming
Olav Haugen
 
The algebra of library design
Leonardo Borges
 
Functional programming in C#
Thomas Jaskula
 
What is Reactive programming?
Kevin Webber
 
Functional Programming with C#
EastBanc Tachnologies
 
ASP.NET MVC Core
Eduard Tomàs
 
Reactive Programming with JavaScript
Codemotion
 
Functional Programming in C# and F#
Alfonso Garcia-Caro
 
Functional Reactive Programming in Javascript
Brian Lonsdorf
 
02 - [ASP.NET Core] ASP.NET Core MVC
Cellenza
 
Frisby Api automation
Dineesha Suraweera
 
Microservices: Architecture for the Real-time Organization
Kevin Webber
 
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache Accumulo
Joe Stein
 
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...
Wes McKinney
 
RxJS - The Reactive Extensions for JavaScript
Viliam Elischer
 
Reactive Extensions for JavaScript
Jim Wooley
 
Ad

Similar to Functional Reactive Programming / Compositional Event Systems (20)

PDF
Functional Reactive Programming in Clojurescript
Leonardo Borges
 
PDF
(Functional) reactive programming (@pavlobaron)
Pavlo Baron
 
PDF
Functional Reactive Programming in JavaScript
zupzup.org
 
PPTX
Real world functional reactive programming
Eric Polerecky
 
PPTX
RxJS vs RxJava: Intro
Martin Toshev
 
PDF
Funtional Reactive Programming with Examples in Scala + GWT
Vasil Remeniuk
 
PPTX
Reactive programming
saykopatt
 
PDF
Learn you some rx for the greater good
3camp
 
PDF
Flow Base Programming with Node-RED and Functional Reactive Programming with ...
Sven Beauprez
 
PPTX
Luis Atencio on RxJS
Luis Atencio
 
PDF
Buy ebook Functional Reactive Programming 1st Edition Stephen Blackheath chea...
wongazarok
 
PDF
Introduction To Functional Reactive Programming Poznan
Eliasz Sawicki
 
PDF
ReactiveX
BADR
 
PPTX
Functional Reactive Programming
Alessandro Melchiori
 
PPTX
Reactive programming every day
Vadym Khondar
 
PDF
Moving towards Reactive Programming
Deepak Shevani
 
PDF
ReactiveCocoa - Functional Reactive Programming concepts in iOS
Andrei Popa
 
PPTX
RxJs
Akila Iroshan
 
Functional Reactive Programming in Clojurescript
Leonardo Borges
 
(Functional) reactive programming (@pavlobaron)
Pavlo Baron
 
Functional Reactive Programming in JavaScript
zupzup.org
 
Real world functional reactive programming
Eric Polerecky
 
RxJS vs RxJava: Intro
Martin Toshev
 
Funtional Reactive Programming with Examples in Scala + GWT
Vasil Remeniuk
 
Reactive programming
saykopatt
 
Learn you some rx for the greater good
3camp
 
Flow Base Programming with Node-RED and Functional Reactive Programming with ...
Sven Beauprez
 
Luis Atencio on RxJS
Luis Atencio
 
Buy ebook Functional Reactive Programming 1st Edition Stephen Blackheath chea...
wongazarok
 
Introduction To Functional Reactive Programming Poznan
Eliasz Sawicki
 
ReactiveX
BADR
 
Functional Reactive Programming
Alessandro Melchiori
 
Reactive programming every day
Vadym Khondar
 
Moving towards Reactive Programming
Deepak Shevani
 
ReactiveCocoa - Functional Reactive Programming concepts in iOS
Andrei Popa
 
Ad

More from Leonardo Borges (19)

PDF
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Leonardo Borges
 
PDF
Parametricity - #cljsyd - May, 2015
Leonardo Borges
 
PDF
From Java to Parellel Clojure - Clojure South 2019
Leonardo Borges
 
PDF
Futures e abstração - QCon São Paulo 2015
Leonardo Borges
 
PDF
High Performance web apps in Om, React and ClojureScript
Leonardo Borges
 
PDF
Programação functional reativa: lidando com código assíncrono
Leonardo Borges
 
PDF
Monads in Clojure
Leonardo Borges
 
PDF
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Leonardo Borges
 
PDF
Intro to Clojure's core.async
Leonardo Borges
 
PDF
Clojure/West 2013 in 30 mins
Leonardo Borges
 
PDF
Clojure Reducers / clj-syd Aug 2012
Leonardo Borges
 
PDF
The many facets of code reuse in JavaScript
Leonardo Borges
 
PDF
Continuation Passing Style and Macros in Clojure - Jan 2012
Leonardo Borges
 
PDF
Heroku addons development - Nov 2011
Leonardo Borges
 
PDF
Clouds against the Floods (RubyConfBR2011)
Leonardo Borges
 
KEY
Clouds Against the Floods
Leonardo Borges
 
KEY
Arel in Rails 3
Leonardo Borges
 
PDF
Testing with Spring
Leonardo Borges
 
PDF
JRuby in The Enterprise
Leonardo Borges
 
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Leonardo Borges
 
Parametricity - #cljsyd - May, 2015
Leonardo Borges
 
From Java to Parellel Clojure - Clojure South 2019
Leonardo Borges
 
Futures e abstração - QCon São Paulo 2015
Leonardo Borges
 
High Performance web apps in Om, React and ClojureScript
Leonardo Borges
 
Programação functional reativa: lidando com código assíncrono
Leonardo Borges
 
Monads in Clojure
Leonardo Borges
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Leonardo Borges
 
Intro to Clojure's core.async
Leonardo Borges
 
Clojure/West 2013 in 30 mins
Leonardo Borges
 
Clojure Reducers / clj-syd Aug 2012
Leonardo Borges
 
The many facets of code reuse in JavaScript
Leonardo Borges
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Leonardo Borges
 
Heroku addons development - Nov 2011
Leonardo Borges
 
Clouds against the Floods (RubyConfBR2011)
Leonardo Borges
 
Clouds Against the Floods
Leonardo Borges
 
Arel in Rails 3
Leonardo Borges
 
Testing with Spring
Leonardo Borges
 
JRuby in The Enterprise
Leonardo Borges
 

Recently uploaded (20)

PDF
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
PPTX
The Future of AI & Machine Learning.pptx
pritsen4700
 
PPTX
Agile Chennai 18-19 July 2025 | Emerging patterns in Agentic AI by Bharani Su...
AgileNetwork
 
PDF
Per Axbom: The spectacular lies of maps
Nexer Digital
 
PDF
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
PDF
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
PPTX
cloud computing vai.pptx for the project
vaibhavdobariyal79
 
PDF
Market Insight : ETH Dominance Returns
CIFDAQ
 
PDF
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
PDF
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
PDF
introduction to computer hardware and sofeware
chauhanshraddha2007
 
PPTX
AI Code Generation Risks (Ramkumar Dilli, CIO, Myridius)
Priyanka Aash
 
PDF
A Strategic Analysis of the MVNO Wave in Emerging Markets.pdf
IPLOOK Networks
 
PPTX
Agile Chennai 18-19 July 2025 | Workshop - Enhancing Agile Collaboration with...
AgileNetwork
 
PDF
Generative AI vs Predictive AI-The Ultimate Comparison Guide
Lily Clark
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PDF
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
PPTX
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
PPTX
Introduction to Flutter by Ayush Desai.pptx
ayushdesai204
 
PDF
State-Dependent Conformal Perception Bounds for Neuro-Symbolic Verification
Ivan Ruchkin
 
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
The Future of AI & Machine Learning.pptx
pritsen4700
 
Agile Chennai 18-19 July 2025 | Emerging patterns in Agentic AI by Bharani Su...
AgileNetwork
 
Per Axbom: The spectacular lies of maps
Nexer Digital
 
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
cloud computing vai.pptx for the project
vaibhavdobariyal79
 
Market Insight : ETH Dominance Returns
CIFDAQ
 
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
introduction to computer hardware and sofeware
chauhanshraddha2007
 
AI Code Generation Risks (Ramkumar Dilli, CIO, Myridius)
Priyanka Aash
 
A Strategic Analysis of the MVNO Wave in Emerging Markets.pdf
IPLOOK Networks
 
Agile Chennai 18-19 July 2025 | Workshop - Enhancing Agile Collaboration with...
AgileNetwork
 
Generative AI vs Predictive AI-The Ultimate Comparison Guide
Lily Clark
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
Introduction to Flutter by Ayush Desai.pptx
ayushdesai204
 
State-Dependent Conformal Perception Bounds for Neuro-Symbolic Verification
Ivan Ruchkin
 

Functional Reactive Programming / Compositional Event Systems

  • 1. Taming Asynchronous Workflows with Functional Reactive Programming EuroClojure - Kraków, 2014 Leonardo Borges @leonardo_borges www.leonardoborges.com www.thoughtworks.com
  • 2. About ‣ ThoughtWorker ‣ Functional Programming & Clojure advocate ‣ Founder of the Sydney Clojure User Group ‣ Currently writing “Clojure Reactive Programming”
  • 3. Taming Asynchronous Workflows with Functional Reactive Programming
  • 4. Taming Asynchronous Workflows with Functional Reactive Programming Compositional Event Systems
  • 8. There are only two hard things in Computer Science: cache invalidation and naming things. - Phil Karlton :)
  • 9. Ok, so what’s the difference?
  • 10. ‣ Created in 1997 by Conal Elliott for the reactive animations framework Fran, in Haskell ‣ Since then other implementations have appeared: reactive-banana, NetWire, Sodium (all in Haskell) ‣ And then FRP-inspired ones: Rx[.NET | Java | JS], Baconjs, reagi (Clojurescript) ‣ Main abstractions: Behaviors e Events More about FRP
  • 11. ‣ Created in 1997 by Conal Elliott for the reactive animations framework Fran, in Haskell ‣ Since then other implementations have appeared: reactive-banana, NetWire, Sodium (all in Haskell) ‣ And then FRP-inspired ones: Rx[.NET | Java | JS], Baconjs, reagi (Clojure[script]) ‣ Main abstractions: Behaviors e Events ‣ Traditionally defined as: type Behavior a = [Time] -> [a]! type Event a = [Time] -> [Maybe a] More about FRP
  • 12. We’ll be focusing on Compositional Event Systems
  • 14. Imperative programming describes computations as a series of actions which modify program state var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; Requires a variable to store state
  • 15. var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; We iterate over the array Imperative programming describes computations as a series of actions which modify program state
  • 16. var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; And then we filter the items… Imperative programming describes computations as a series of actions which modify program state
  • 17. var result = 1;! numbers.forEach(function(n){! if(n % 2 === 0) {! result *= n;! }! });! console.log( result );! // 8! var numbers = [1,2,3,4,5]; …and perform the multiplication in the same function Imperative programming describes computations as a series of actions which modify program state
  • 18. (def numbers [1 2 3 4 5])! ! (def result! (->> numbers! (filter even?)! (reduce *)))! ! (prn result)! ! ;; 8 In functional programming, we describe what we want to do but not how we want it done
  • 19. That is, there are no variables with local state and we get better re-use from single purpose functions
  • 20. Compositional Event Systems brings the same principle to values we work with daily: DOM events (clicks, key presses, mouse movement), Ajax calls…
  • 21. Let’s look at an example
  • 22. Game movements in Javascript var JUMP = 38, CROUCH = 40,! LEFT = 37, RIGHT = 39,! FIRE = 32;! ! function goRight (){! $(‘h1').html("Going right...");! }! ! function goLeft (){! $(‘h1').html("Going left...");! }! ! function jump (){! $('h1').html("Jumping...");! }! ! function crouch (){! $('h1').html("Crouching...");! }! ! function fire (){! $('h1').html("Firing...");! }
  • 23. Game movements in Javascript $(window.document).keyup(function(event){! switch(event.keyCode){! case JUMP :! jump();! break;! case CROUCH:! crouch();! break;! case LEFT :! goLeft();! break;! case RIGHT :! goRight();! break;! case FIRE :! fire();! break;! };! });
  • 24. We now have limitations similar to the multiplication example
  • 25. Let us think key presses as a list of keys over a period of time
  • 26. This leads to the following solution
  • 27. Reactive game movements (def UP 38) (def RIGHT 39)! (def DOWN 40) (def LEFT 37)! (def FIRE 32) (def PAUSE 80)! ! ! (def source (.fromEvent js/Rx.Observable js/window "keyup"));! ! (-> source (.filter #(= UP %)) (.subscribe jump))! (-> source (.filter #(= DOWN %)) (.subscribe crouch))! (-> source (.filter #(= RIGHT %)) (.subscribe go-right))! (-> source (.filter #(= LEFT %)) (.subscribe go-left))! (-> source (.filter #(= FIRE %)) (.subscribe fire))! http://bit.ly/rxjava-github http://bit.ly/rxjs-github
  • 28. Reactive game movements (def UP 38) (def RIGHT 39)! (def DOWN 40) (def LEFT 37)! (def FIRE 32) (def PAUSE 80)! ! ! (def source (.fromEvent js/Rx.Observable js/window "keyup"));! ! (-> source (.filter #(= UP %)) (.subscribe jump))! (-> source (.filter #(= DOWN %)) (.subscribe crouch))! (-> source (.filter #(= RIGHT %)) (.subscribe go-right))! (-> source (.filter #(= LEFT %)) (.subscribe go-left))! (-> source (.filter #(= FIRE %)) (.subscribe fire))! http://bit.ly/rxjava-github http://bit.ly/rxjs-github
  • 29. Behaviours ;; behavior examples! (def time-b (r/behavior (System/currentTimeMillis)))! @time-b! ;; 1403691712988! @time-b! ;; 1403691714156! http://bit.ly/reagi
  • 30. Behaviours to Event Streams http://bit.ly/reagi (def time-e (r/sample 1000 time-b))! ! (->> time-e (r/map println))! ;; t + 1 sec! ;; 1403692132586! ;; t + 2 sec:! ;; 1403692133587!
  • 31. Combinators (-> (Observable/return 42)! (.map #(* % 2))! (.subscribe println))! ! ;; 84! ! (-> (Observable/from [10 20 30])! (.map #(* % 2))! (.reduce +)! (.subscribe println))! ! ;; 120!
  • 32. Combinators: flatMap / selectMany (defn project-range [n]! (Rx.Observable/return (range n)))! ! (-> (Observable/from [1 2 3])! (.selectMany project-range)! (.subscribe (rx/fn* println)))! ! ;; 0! ;; 0! ;; 1! ;; 0! ;; 1! ;; 2!
  • 33. ?
  • 35. (-> (Observable/from [1 2 3])! (.selectMany project-range)! …) (project-range 2) 0 1 (project-range 1) 0 (project-range 3) 0 1 2 0 0 1 0 1 2
  • 36. What about network IO? ‣ Callback hell :( ‣ Clojure promises don’t compose ‣ Promises in JS are slightly better but have limitations ‣ They work well for a single level of values ‣ However are a poor composition mechanism ‣ What if we have a series of values that changes over time?
  • 38. This is what the server gives us {:id 7! :question "Which is the best music style?"! :results {:a 10! :b 47! :c 17}}!
  • 39. And this is 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;
  • 41. First, we need to turn the results into a stream 4 3 3 2 1 1
  • 42. So we duplicate the stream, skipping one element 4 3 3 2 1 1 5 4 3 3 2 1 (skip 1)
  • 43. Finally, we zip the streams 4 3 3 2 1 1 5 4 3 3 2 1 zip [5,4] [4,3] [3,3] [3,2] [2,1] [1,1]
  • 44. The core idea, in code (defn results-observable! "Returns an Observable that yields server-side questions/results"! []! (.create js/Rx.Observable! (fn [observer]! (srm/rpc! (poll-results) [resp]! (.onNext observer resp))! (fn [] (.log js/console "Disposed")))))
  • 45. The core idea, in code (def results-connectable! "Zips results-observable with itself, but shifted by 1.! This simulates a 'buffer' or 'window' of results"! (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 results into a stream
  • 46. The core idea, in code (def results-connectable! "Zips results-observable with itself, but shifted by 1.! This simulates a 'buffer' or 'window' of results"! (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}))))! Clone stream, skip one
  • 47. The core idea, in code (def results-connectable! "Zips results-observable with itself, but shifted by 1.! This simulates a 'buffer' or 'window' of results"! (let [obs (-> js/Rx.Observable! (.interval 2000)! (.selectMany results-observable))! obs-1 (.skip obs 1)]! (.zip obs obs-1 (fn [prev curr]! {:prev prev! :curr curr}))))! Zip them together
  • 48. Can we do better?
  • 49. Buffering (def results-buffer! "Returns an Observable with results buffered into a 2-element vector"! (-> js/Rx.Observable! (.interval 2000)! (.selectMany results-observable)! (.bufferWithCount 2)))!
  • 51. "FRP is about handling time-varying values like they were regular values" - Haskell Wiki
  • 52. "FRP is about handling time-varying values like they were regular values" - Haskell Wiki It also applies to FRP-inspired systems
  • 53. Why not use core.async?
  • 54. Previously, with CES (-> (Observable/from [10 20 30])! (.map (rx/fn [v] (* v 2)))! (.reduce (rx/fn* +)! (.subscribe (rx/fn* println)))))
  • 55. With core.async (defn from-array [coll]! (let [stream-c (chan)]! (go (doseq [n coll]! (>! stream-c n))! (close! stream-c))! stream-c))! ! (def c (->> (async-from [10 20 30])! (a/map< #(* % 2))! (a/reduce + 0)))! ! (go-loop []! (when-let [v (<! c)]! (println v)! (recur)))!
  • 56. Multiple subscribers with CES (def sum-of-squares (-> (Observable/from [10 20 30])! (.map (rx/fn [v] (* v 2)))! (.reduce (rx/fn* +))))! ! ! ! (.subscribe sum-of-squares (rx/action* println)) ;; 120! (.subscribe sum-of-squares (rx/action* println)) ;; 120
  • 57. Multiple subscribers with core.async [1/3] (def in (chan))! (def sum-of-squares (->> in! (a/map< #(* % 2))! (a/reduce + 0)))!
  • 58. Multiple subscribers with core.async [2/3] (def publication (pub sum-of-squares (fn [_] :n)))! ! (def sub-1 (chan))! (def sub-2 (chan))! ! (sub publication :n sub-1)! (sub publication :n sub-2)
  • 59. Multiple subscribers with core.async [3/3] (go (doseq [n [10 20 30]]! (>! in n))! (close! in))! ! (go-loop []! (when-let [v (<! sub-1)]! (prn v)! (recur))) ;; 120! ! (go-loop []! (when-let [v (<! sub-2)]! (prn v)! (recur))) ;; 120
  • 60. core.async operates at a lower level of abstraction
  • 61. it is however a great foundation for a FRP-inspired framework
  • 62. Reagi - shown earlier - is built on top of core.async http://bit.ly/reagi
  • 63. Bonus example: a reactive API to AWS
  • 64. Bonus example: a reactive API to AWS ‣ Retrieve list of resources from a stack (CloudFormation.describeStackResources) ‣ For each EC2 Instance, call EC2.describeInstances to retrieve status ‣ For each RDS Instance, call RDS.describeDBInstances to retrieve status ‣ Merge results and display
  • 65. Step 1: turn api calls into streams (defn resources-stream [stack-name]! (.create js/Rx.Observable! (fn [observer]! (.describeStackResources js/cloudFormation #js {"StackName" : stackName}! (fn [err data]! (if err! (.onError observer err)! (doseq [resource data]! (.onNext observer resource))! (.onCompleted observer)))! (fn [] (.log js/console "Disposed")))))
  • 66. Step 1: turn api calls into streams (defn ec2-instance-stream [resource-ids]! (.create js/Rx.Observable! (fn [observer]! (.describeInstaces js/ec2 #js {"InstanceIds" resource-ids}! (fn [err data]! (if err! (.onError observer err)! (doseq [instance data]! (.onNext observer instance)))! (.onCompleted observer)))! (fn [] (.log js/console "Disposed")))))!
  • 67. Step 1: turn api calls into streams (defn rds-instance-stream [resource-id]! (.create js/Rx.Observable! (fn [observer]! (.describeDBInstances js/rds #js {"DBInstanceIdentifier" resource-id}! (fn [err data]! (if err! (.onError observer err)! (.onNext observer data))! (.onCompleted observer)))! (fn [] (.log js/console "Disposed")))))
  • 68. Step 2: transform the different API responses into a common output (def resources (resourcesStream "my-stack"))! ! (def ec2-data (-> resources! (.filter ec2?)! (.map :resource-id)! (.flatMap ec2-instance-stream)! (.map (fn [data] {:instance-id ...! :status ...}))))! ! (def rds-data (-> resources! (.filter rds?)! (.map :resource-id)! (.flatMap rds-instance-stream)! (.map (fn [data] {:instance-id ...! :status ...}))))!
  • 69. Step 3: merge results and update UI (-> ec2-data! (.merge rds-data)! (.reduce conj [])! (.subscribe (fn [data] (update-interface ...))))
  • 70. Easy to reason about, maintain and test
  • 71. References ! ‣ Conal Elliott “Functional Reactive Animation” paper: http://bit.ly/conal-frp ! FRP-inspired frameworks: ‣ Reagi: http://bit.ly/reagi ‣ RxJS: http://bit.ly/rxjs-github ‣ RxJava: http://bit.ly/rxjava-github ‣ Bacon.js: https://github.com/baconjs/bacon.js ! FRP implementations: ‣ Reactive Banana: http://www.haskell.org/haskellwiki/Reactive-banana ‣ Elm: http://elm-lang.org/ ‣ NetWire: http://www.haskell.org/haskellwiki/Netwire