SlideShare a Scribd company logo
1 of 72
Download to read offline
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

Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)
Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)
Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)Dimitris Kolovos
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJSstefanmayer13
 
Rx- Reactive Extensions for .NET
Rx- Reactive Extensions for .NETRx- Reactive Extensions for .NET
Rx- Reactive Extensions for .NETJakub Malý
 
A Quick Intro to ReactiveX
A Quick Intro to ReactiveXA Quick Intro to ReactiveX
A Quick Intro to ReactiveXTroy Miles
 
Functional Reactive Programming
Functional Reactive ProgrammingFunctional Reactive Programming
Functional Reactive ProgrammingOlav Haugen
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library designLeonardo Borges
 
Functional programming in C#
Functional programming in C#Functional programming in C#
Functional programming in C#Thomas Jaskula
 
What is Reactive programming?
What is Reactive programming?What is Reactive programming?
What is Reactive programming?Kevin Webber
 
Reactive Programming with JavaScript
Reactive Programming with JavaScriptReactive Programming with JavaScript
Reactive Programming with JavaScriptCodemotion
 
Functional Programming in C# and F#
Functional Programming in C# and F#Functional Programming in C# and F#
Functional Programming in C# and F#Alfonso Garcia-Caro
 
Functional Reactive Programming in Javascript
Functional Reactive Programming in JavascriptFunctional Reactive Programming in Javascript
Functional Reactive Programming in JavascriptBrian Lonsdorf
 
02 - [ASP.NET Core] ASP.NET Core MVC
02 - [ASP.NET Core] ASP.NET Core MVC 02 - [ASP.NET Core] ASP.NET Core MVC
02 - [ASP.NET Core] ASP.NET Core MVC Cellenza
 
Microservices: Architecture for the Real-time Organization
Microservices: Architecture for the Real-time OrganizationMicroservices: Architecture for the Real-time Organization
Microservices: Architecture for the Real-time OrganizationKevin Webber
 
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache Accumulo
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache AccumuloReal-Time Distributed and Reactive Systems with Apache Kafka and Apache Accumulo
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache AccumuloJoe Stein
 
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...Wes McKinney
 
RxJS - The Reactive Extensions for JavaScript
RxJS - The Reactive Extensions for JavaScriptRxJS - The Reactive Extensions for JavaScript
RxJS - The Reactive Extensions for JavaScriptViliam Elischer
 
Reactive Extensions for JavaScript
Reactive Extensions for JavaScriptReactive Extensions for JavaScript
Reactive Extensions for JavaScriptJim Wooley
 

Viewers also liked (20)

Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)
Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)
Eclipse Modeling Framework (EMF) and Graphical Modeling Framework (GMF)
 
Functional Reactive Programming with RxJS
Functional Reactive Programming with RxJSFunctional Reactive Programming with RxJS
Functional Reactive Programming with RxJS
 
Rx- Reactive Extensions for .NET
Rx- Reactive Extensions for .NETRx- Reactive Extensions for .NET
Rx- Reactive Extensions for .NET
 
A Quick Intro to ReactiveX
A Quick Intro to ReactiveXA Quick Intro to ReactiveX
A Quick Intro to ReactiveX
 
Functional Reactive Programming
Functional Reactive ProgrammingFunctional Reactive Programming
Functional Reactive Programming
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library design
 
Functional programming in C#
Functional programming in C#Functional programming in C#
Functional programming in C#
 
What is Reactive programming?
What is Reactive programming?What is Reactive programming?
What is Reactive programming?
 
Functional Programming with C#
Functional Programming with C#Functional Programming with C#
Functional Programming with C#
 
ASP.NET MVC Core
ASP.NET MVC CoreASP.NET MVC Core
ASP.NET MVC Core
 
Reactive Programming with JavaScript
Reactive Programming with JavaScriptReactive Programming with JavaScript
Reactive Programming with JavaScript
 
Functional Programming in C# and F#
Functional Programming in C# and F#Functional Programming in C# and F#
Functional Programming in C# and F#
 
Functional Reactive Programming in Javascript
Functional Reactive Programming in JavascriptFunctional Reactive Programming in Javascript
Functional Reactive Programming in Javascript
 
02 - [ASP.NET Core] ASP.NET Core MVC
02 - [ASP.NET Core] ASP.NET Core MVC 02 - [ASP.NET Core] ASP.NET Core MVC
02 - [ASP.NET Core] ASP.NET Core MVC
 
Frisby Api automation
Frisby Api automationFrisby Api automation
Frisby Api automation
 
Microservices: Architecture for the Real-time Organization
Microservices: Architecture for the Real-time OrganizationMicroservices: Architecture for the Real-time Organization
Microservices: Architecture for the Real-time Organization
 
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache Accumulo
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache AccumuloReal-Time Distributed and Reactive Systems with Apache Kafka and Apache Accumulo
Real-Time Distributed and Reactive Systems with Apache Kafka and Apache Accumulo
 
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...
Practical Medium Data Analytics with Python (10 Things I Hate About pandas, P...
 
RxJS - The Reactive Extensions for JavaScript
RxJS - The Reactive Extensions for JavaScriptRxJS - The Reactive Extensions for JavaScript
RxJS - The Reactive Extensions for JavaScript
 
Reactive Extensions for JavaScript
Reactive Extensions for JavaScriptReactive Extensions for JavaScript
Reactive Extensions for JavaScript
 

Similar to Functional Reactive Programming / Compositional Event Systems

Incredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and GeneratorsIncredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and Generatorsdantleech
 
Golang Performance : microbenchmarks, profilers, and a war story
Golang Performance : microbenchmarks, profilers, and a war storyGolang Performance : microbenchmarks, profilers, and a war story
Golang Performance : microbenchmarks, profilers, and a war storyAerospike
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisC4Media
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinAndrey Breslav
 
Frege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVMFrege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVMDierk König
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015Michiel Borkent
 
Building Hermetic Systems (without Docker)
Building Hermetic Systems (without Docker)Building Hermetic Systems (without Docker)
Building Hermetic Systems (without Docker)William Farrell
 
Locks? We Don't Need No Stinkin' Locks - Michael Barker
Locks? We Don't Need No Stinkin' Locks - Michael BarkerLocks? We Don't Need No Stinkin' Locks - Michael Barker
Locks? We Don't Need No Stinkin' Locks - Michael BarkerJAX London
 
Lock? We don't need no stinkin' locks!
Lock? We don't need no stinkin' locks!Lock? We don't need no stinkin' locks!
Lock? We don't need no stinkin' locks!Michael Barker
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)jeffz
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Leonardo Borges
 
ClojureScript interfaces to React
ClojureScript interfaces to ReactClojureScript interfaces to React
ClojureScript interfaces to ReactMichiel Borkent
 
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in ClojurescriptProgscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in ClojurescriptJohn Stevenson
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
FireWorks workflow software
FireWorks workflow softwareFireWorks workflow software
FireWorks workflow softwareAnubhav Jain
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 
WebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All RevolutionaryWebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All RevolutionaryC4Media
 

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

Incredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and GeneratorsIncredible Machine with Pipelines and Generators
Incredible Machine with Pipelines and Generators
 
Golang Performance : microbenchmarks, profilers, and a war story
Golang Performance : microbenchmarks, profilers, and a war storyGolang Performance : microbenchmarks, profilers, and a war story
Golang Performance : microbenchmarks, profilers, and a war story
 
Beyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic AnalysisBeyond Breakpoints: A Tour of Dynamic Analysis
Beyond Breakpoints: A Tour of Dynamic Analysis
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in Kotlin
 
Frege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVMFrege - consequently functional programming for the JVM
Frege - consequently functional programming for the JVM
 
ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015ClojureScript loves React, DomCode May 26 2015
ClojureScript loves React, DomCode May 26 2015
 
Building Hermetic Systems (without Docker)
Building Hermetic Systems (without Docker)Building Hermetic Systems (without Docker)
Building Hermetic Systems (without Docker)
 
Locks? We Don't Need No Stinkin' Locks - Michael Barker
Locks? We Don't Need No Stinkin' Locks - Michael BarkerLocks? We Don't Need No Stinkin' Locks - Michael Barker
Locks? We Don't Need No Stinkin' Locks - Michael Barker
 
Lock? We don't need no stinkin' locks!
Lock? We don't need no stinkin' locks!Lock? We don't need no stinkin' locks!
Lock? We don't need no stinkin' locks!
 
ECMAScript 6
ECMAScript 6ECMAScript 6
ECMAScript 6
 
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)The Evolution of Async-Programming on .NET Platform (.Net China, C#)
The Evolution of Async-Programming on .NET Platform (.Net China, C#)
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
ClojureScript interfaces to React
ClojureScript interfaces to ReactClojureScript interfaces to React
ClojureScript interfaces to React
 
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in ClojurescriptProgscon 2017: Taming the wild fronteer - Adventures in Clojurescript
Progscon 2017: Taming the wild fronteer - Adventures in Clojurescript
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
FireWorks workflow software
FireWorks workflow softwareFireWorks workflow software
FireWorks workflow software
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
WebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All RevolutionaryWebAssembly. Neither Web Nor Assembly, All Revolutionary
WebAssembly. Neither Web Nor Assembly, All Revolutionary
 
React native
React nativeReact native
React native
 

More from Leonardo Borges

Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015
Realtime collaboration with Clojure - EuroClojure - Barcelona, 2015Leonardo Borges
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Leonardo Borges
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019Leonardo Borges
 
Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015Futures e abstração - QCon São Paulo 2015
Futures e abstração - QCon São Paulo 2015Leonardo Borges
 
High Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptHigh Performance web apps in Om, React and ClojureScript
High Performance web apps in Om, React and ClojureScriptLeonardo Borges
 
Programação functional reativa: lidando com código assíncrono
Programação functional reativa: lidando com código assíncronoProgramação functional reativa: lidando com código assíncrono
Programação functional reativa: lidando com código assíncronoLeonardo Borges
 
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013
Clojure Macros Workshop: LambdaJam 2013 / CUFP 2013Leonardo Borges
 
Intro to Clojure's core.async
Intro to Clojure's core.asyncIntro to Clojure's core.async
Intro to Clojure's core.asyncLeonardo Borges
 
Functional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptFunctional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptLeonardo Borges
 
Clojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsClojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsLeonardo Borges
 
Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Leonardo Borges
 
The many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptThe many facets of code reuse in JavaScript
The many facets of code reuse in JavaScriptLeonardo Borges
 
Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Heroku addons development - Nov 2011
Heroku addons development - Nov 2011Leonardo Borges
 
Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Clouds against the Floods (RubyConfBR2011)
Clouds against the Floods (RubyConfBR2011) Leonardo Borges
 
Clouds Against the Floods
Clouds Against the FloodsClouds Against the Floods
Clouds Against the FloodsLeonardo Borges
 

More from Leonardo Borges (19)

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

Recently uploaded

From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piececharlottematthew16
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 

Recently uploaded (20)

From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Story boards and shot lists for my a level piece
Story boards and shot lists for my a level pieceStory boards and shot lists for my a level piece
Story boards and shot lists for my a level piece
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 

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