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

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
 

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

ODP
Incredible Machine with Pipelines and Generators
dantleech
 
PDF
Golang Performance : microbenchmarks, profilers, and a war story
Aerospike
 
PDF
Beyond Breakpoints: A Tour of Dynamic Analysis
C4Media
 
PDF
JVMLS 2016. Coroutines in Kotlin
Andrey Breslav
 
PDF
Frege - consequently functional programming for the JVM
Dierk König
 
PDF
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
 
PDF
Building Hermetic Systems (without Docker)
William Farrell
 
KEY
Locks? We Don't Need No Stinkin' Locks - Michael Barker
JAX London
 
KEY
Lock? We don't need no stinkin' locks!
Michael Barker
 
PDF
ECMAScript 6
偉格 高
 
PDF
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
jeffz
 
PDF
Continuation Passing Style and Macros in Clojure - Jan 2012
Leonardo Borges
 
PPT
JS everywhere 2011
Oleg Podsechin
 
PDF
ClojureScript interfaces to React
Michiel Borkent
 
PDF
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
John Stevenson
 
PDF
Exploring Clojurescript
Luke Donnet
 
PDF
FireWorks workflow software
Anubhav Jain
 
PDF
Think Async: Asynchronous Patterns in NodeJS
Adam L Barrett
 
PDF
WebAssembly. Neither Web Nor Assembly, All Revolutionary
C4Media
 
PPT
React native
Mohammed El Rafie Tarabay
 
Incredible Machine with Pipelines and Generators
dantleech
 
Golang Performance : microbenchmarks, profilers, and a war story
Aerospike
 
Beyond Breakpoints: A Tour of Dynamic Analysis
C4Media
 
JVMLS 2016. Coroutines in Kotlin
Andrey Breslav
 
Frege - consequently functional programming for the JVM
Dierk König
 
ClojureScript loves React, DomCode May 26 2015
Michiel Borkent
 
Building Hermetic Systems (without Docker)
William Farrell
 
Locks? We Don't Need No Stinkin' Locks - Michael Barker
JAX London
 
Lock? We don't need no stinkin' locks!
Michael Barker
 
ECMAScript 6
偉格 高
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
jeffz
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Leonardo Borges
 
JS everywhere 2011
Oleg Podsechin
 
ClojureScript interfaces to React
Michiel Borkent
 
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
John Stevenson
 
Exploring Clojurescript
Luke Donnet
 
FireWorks workflow software
Anubhav Jain
 
Think Async: Asynchronous Patterns in NodeJS
Adam L Barrett
 
WebAssembly. Neither Web Nor Assembly, All Revolutionary
C4Media
 
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
Functional Reactive Programming in Clojurescript
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
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
 
Functional Reactive Programming in Clojurescript
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
 
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
 
Ad

Recently uploaded (20)

PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
PDF
IoT-Powered Industrial Transformation – Smart Manufacturing to Connected Heal...
Rejig Digital
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PDF
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
PDF
July Patch Tuesday
Ivanti
 
PDF
Biography of Daniel Podor.pdf
Daniel Podor
 
PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PDF
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PDF
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
Reverse Engineering of Security Products: Developing an Advanced Microsoft De...
nwbxhhcyjv
 
IoT-Powered Industrial Transformation – Smart Manufacturing to Connected Heal...
Rejig Digital
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
July Patch Tuesday
Ivanti
 
Biography of Daniel Podor.pdf
Daniel Podor
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
What Makes Contify’s News API Stand Out: Key Features at a Glance
Contify
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 

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