SlideShare a Scribd company logo
1 of 76
Download to read offline
The algebra of library
design
#cljsyd - October 2014
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com
Algebra?
More specifically…
• Algebraic structures, studied in Abstract Algebra
• a set with one or more operations on it
• Category theory is another way to study these
structures
Overview
• The problem with Clojure futures
• A better futures library
• Functors, Applicative Functors and Monads
• What about core.async (and others?)
The beginning…
(def age (future (do (Thread/sleep 2000)!
31)))!
(prn "fetching age...")!
!
(def double-age (* 2 @age))!
(prn "age, doubled: " double-age)!
!
(prn "doing something else important...")
Do you see any issues?
The beginning…
(def age (future (do (Thread/sleep 2000)!
31)))!
(prn "fetching age...")!
!
(def double-age (* 2 @age))!
(prn "age, doubled: " double-age)!
!
(prn "doing something else important...")!
!
;; "fetching age..."!
;; "age, doubled: " 62!
;; "doing something else important..."!
It looks like we would like to execute
something once the Future has completed
A first glance at imminent
(require '[imminent.core :as i])!
!
(def age (i/future (do (Thread/sleep 2000)!
31)))!
(prn "fetching age...")!
(def double-age (i/map age #(* % 2)))!
(i/on-success double-age #(prn "age, doubled: " %))!
!
(prn "doing something else important...")
A first glance at imminent
(require '[imminent.core :as i])!
!
(def age (i/future (do (Thread/sleep 2000)!
31)))!
(prn "fetching age...")!
(def double-age (i/map age #(* % 2)))!
(i/on-success double-age #(prn "age, doubled: " %))!
!
(prn "doing something else important...")!
!
;; "fetching age..."!
;; "doing something else important..."!
;; "age, doubled: " 62!
Functor
class Functor f where!
fmap :: (a -> b) -> f a -> f b
Another example
(def age (future (do (Thread/sleep 2000)!
31)))!
(def name (future (do (Thread/sleep 2000)!
"Leonardo")))!
(prn "fetching name...")!
(prn (format "%s is %s years old" @name @age))!
(prn "more important things going on...")
Same as before, only this time we
want to execute the code once
both futures have completed
Rewriting it in imminent
(def age (i/future (do (Thread/sleep 2000)!
31)))!
(def name (i/future (do (Thread/sleep 2000)!
"Leonardo")))!
(prn "fetching name...")!
(def both (i/sequence [name age]))!
(i/on-success both !
(fn [[name age]]!
(prn (format "%s is %s years old" name age))))!
!
(prn "more important things going on...")!
!
Rewriting it in imminent
(def age (i/future (do (Thread/sleep 2000)!
31)))!
(def name (i/future (do (Thread/sleep 2000)!
"Leonardo")))!
(prn "fetching name...")!
(def both (i/sequence [name age]))!
(i/on-success both !
(fn [[name age]]!
(prn (format "%s is %s years old" name age))))!
!
(prn "more important things going on...")!
!
;; "fetching name..."!
;; "more important things going on..."!
;; "Leonardo is 31 years old"!
Monad
class Monad m where!
(>>=) :: m a -> (a -> m b) -> m b!
return :: a -> m a
Monad
class Monad m where!
(>>=) :: m a -> (a -> m b) -> m b!
return :: a -> m a
(>>=) is also called bind, flatmap, selectMany
and mapcat…
Monad - derived functions
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
Monad - derived functions
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
(defn mlift2!
[f]!
(fn [ma mb]!
(flatmap ma!
(fn [a]!
(flatmap mb!
(fn [b]!
(pure (f a b))))))))
Monad - derived functions
sequence :: Monad m => [m a] -> m [a]
Monad - derived functions
sequence :: Monad m => [m a] -> m [a]
(defn sequence!
[ms]!
(reduce (mlift2 conj)!
(pure [])!
ms))
Monad - derived functions
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
Monad - derived functions
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
(defn mmap!
[f vs]!
(sequence (map f vs)))
Monad - derived functions
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
(defn mmap!
[f vs]!
(sequence (map f vs)))
plus a bunch of others…
Let’s look at a more concrete
example
Aggregating movie data
(defn cast-by-movie [name]!
(future (do (Thread/sleep 5000)!
(:cast movie))))!
!
(defn movies-by-actor [name]!
(do (Thread/sleep 2000)!
(->> actor-movies!
(filter #(= name (:name %)))!
first)))!
!
(defn spouse-of [name]!
(do (Thread/sleep 2000)!
(->> actor-spouse!
(filter #(= name (:name %)))!
first)))!
!
(defn top-5 []!
(future (do (Thread/sleep 5000)!
top-5-movies)))!
The output
({:name "Cate Blanchett",!
:spouse "Andrew Upton",!
:movies!
("Lord of The Rings: The Fellowship of The Ring - (top 5)"...)}!
{:name "Elijah Wood",!
:spouse "Unknown",!
:movies!
("Eternal Sunshine of the Spotless Mind"...)}!
...)
One possible solution
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
movies (pmap movies-by-actor @cast)!
spouses (pmap spouse-of @cast)!
top-5 (top-5)]!
(prn "Fetching data...")!
(pprint (aggregate-actor-data spouses movies @top-5)))
One possible solution
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
movies (pmap movies-by-actor @cast)!
spouses (pmap spouse-of @cast)!
top-5 (top-5)]!
(prn "Fetching data...")!
(pprint (aggregate-actor-data spouses movies @top-5)))
;; "Elapsed time: 10049.334 msecs"
We face the same problems
as before
Re-arranging the code
would improve it
But the point is not having to
do so
In imminent
(defn cast-by-movie [name]!
(i/future (do (Thread/sleep 5000)!
(:cast movie))))!
!
(defn movies-by-actor [name]!
(i/future (do (Thread/sleep 2000)!
(->> actor-movies!
(filter #(= name (:name %)))!
first))))!
!
(defn spouse-of [name]!
(i/future (do (Thread/sleep 2000)!
(->> actor-spouse!
(filter #(= name (:name %)))!
first))))!
!
(defn top-5 []!
(i/future (do (Thread/sleep 5000)!
top-5-movies)))
In imminent
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
movies (i/flatmap cast #(i/map-future movies-by-actor %))!
spouses (i/flatmap cast #(i/map-future spouse-of %))!
result (i/sequence [spouses movies (top-5)])]!
(prn "Fetching data...")!
(pprint (apply aggregate-actor-data!
(i/dderef (i/await result)))))
In imminent
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
movies (i/flatmap cast #(i/map-future movies-by-actor %))!
spouses (i/flatmap cast #(i/map-future spouse-of %))!
result (i/sequence [spouses movies (top-5)])]!
(prn "Fetching data...")!
(pprint (apply aggregate-actor-data!
(i/dderef (i/await result)))))
;; "Elapsed time: 7087.603 msecs"
Everything is asynchronous
by default
We can optionally block and wait
for a result using the “i/await”
function
Ok, that’s cool!
But what about Applicative Functors?
Writing this sucks
(defn int-f [n]!
(i/future (do (Thread/sleep 2000)!
(* 2 n))))!
!
!
(-> (i/bind!
(int-f 10)!
(fn [a] (i/bind!
(int-f a)!
(fn [b] (i/bind!
(int-f b)!
(fn [c] !
(i/pure (+ a b c)))))))
Monadic “do” notation
(i/mdo [a (int-f 10)!
b (int-f a)!
c (int-f b)]!
(i/pure (+ a b c)))
Monadic “do” notation
(i/mdo [a (int-f 10)!
b (int-f a)!
c (int-f b)]!
(i/pure (+ a b c)))
How long does this computation take?
Monadic “do” notation
(i/mdo [a (int-f 10)!
b (int-f a)!
c (int-f b)]!
(i/pure (+ a b c)))
How long does this computation take?
;; "Elapsed time: 6002.39 msecs"
What if the computations don’t
depend on each other?
Monadic “do” notation
(i/mdo [a (int-f 10)!
b (int-f 20)!
c (int-f 30)]!
(i/pure (+ a b c)))
Monadic “do” notation
(i/mdo [a (int-f 10)!
b (int-f 20)!
c (int-f 30)]!
(i/pure (+ a b c)))
How long does this take now?
Monadic “do” notation
(i/mdo [a (int-f 10)!
b (int-f 20)!
c (int-f 30)]!
(i/pure (+ a b c)))
How long does this take now?
;; "Elapsed time: 6002.39 msecs"
?
The ‘do-notation’ is used to sequence monadic
steps so we remain serial, but still asynchronous
Applicative Functor
class Functor f => Applicative f where!
pure :: a -> f a!
(<*>) :: f (a -> b) -> f a -> f b!
Previous example, rewritten in applicative style
(i/<*> (i/map (int-f 10) (curry + 3))!
(int-f 20)!
(int-f 30))
;;"Elapsed time: 2001.509 msecs"
It turns out this pattern is a derived
function from Applicative Functors
Applicative Functor - derived functions
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
Applicative Functor - derived functions
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
(defn alift!
[f]!
(fn [& as]!
{:pre [(seq as)]}!
(let [curried (curry f (count as))]!
(apply <*>!
(fmap curried (first as))!
(rest as)))))
“alift” assumes every Applicative
Functor is also Functor
Previous example, rewritten using “alift"
;;"Elapsed time: 2001.509 msecs"
((i/alift +) (int-f 10) (int-f 20) (int-f 30))
It looks a lot like function application
:)
Applicatives give us the parallel
semantics without giving up convenience
Ok, this is awesome! But we have
core.async!
The movies example, revisited
(defn cast-by-movie [name]!
(let [c (chan)]!
(go (<! (timeout 5000))!
(>! c (:cast movie))!
(close! c))!
c))!
!
(defn movies-by-actor [name]!
(let [c (chan)]!
(go (<! (timeout 2000))!
(>! c (->> actor-movies!
(filter #(= name (:name %)))!
first))!
(close! c))!
c))
The movies example, revisited
(defn spouse-of [name]!
(let [c (chan)]!
(go (<! (timeout 2000))!
(>! c (->> actor-spouse!
(filter #(= name (:name %)))!
first))!
(close! c))!
c))!
!
(defn top-5 []!
(let [c (chan)]!
(go (<! (timeout 5000))!
(>! c top-5-movies)!
(close! c))!
c))!
!
!
(defn async-pmap [f source]!
(go (->> (map f (<! source))!
async/merge!
(async/into [])!
<!)))
The movies example, revisited
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
m-cast (mult cast)!
movies (async-pmap movies-by-actor (tap m-cast (chan)))!
spouses (async-pmap spouse-of (tap m-cast (chan)))!
top-5 (top-5)]!
(prn "Fetching data...")!
(pprint (<!! (go (aggregate-actor-data (<! spouses)!
(<! movies)!
(<! top-5))))))!
!
;; "Elapsed time: 7088.834 msecs"
“mult” and “tap” have no business
being in that code
they are necessary because
channels are single-take containers
Exceptions
core.async swallows them by default
(defn movies-by-actor [name]!
(let [c (chan)]!
(go (<! (timeout 2000))!
(throw (Exception. (str "Error fetching movies for actor " name)))!
(>! c (->> actor-movies!
(filter #(= name (:name %)))!
first))!
(close! c))!
c))
Exceptions
core.async swallows them by default
(defn movies-by-actor [name]!
(let [c (chan)]!
(go (<! (timeout 2000))!
(throw (Exception. (str "Error fetching movies for actor " name)))!
(>! c (->> actor-movies!
(filter #(= name (:name %)))!
first))!
(close! c))!
c))
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
m-cast (mult cast)!
movies (async-pmap movies-by-actor (tap m-cast (chan)))!
spouses (async-pmap spouse-of (tap m-cast (chan)))!
top-5 (top-5)]!
(prn "Fetching data...")!
(pprint (<!! (go (aggregate-actor-data (<! spouses)!
(<! movies)!
(<! top-5))))))!
!
;; nil - WTF???"
Exceptions - workaround
(defn throw-err [e]!
(when (instance? Throwable e) (throw e))!
e)!
!
(defmacro <? [ch]!
`(throw-err (<! ~ch)))!
!
!
(defn movies-by-actor [name]!
(let [c (chan)]!
(go (try (do (<! (timeout 2000))!
(throw (Exception. (str "Error fetching movies for actor " name)))!
(>! c (->> actor-movies!
(filter #(= name (:name %)))!
first))!
(close! c))!
(catch Exception e!
(do (>! c e)!
(close! c)))))!
c))
Exceptions - workaround
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
m-cast (mult cast)!
movies (async-pmap movies-by-actor (tap m-cast (chan)))!
spouses (async-pmap spouse-of (tap m-cast (chan)))!
top-5 (top-5)]!
(prn "Fetching data...")!
(pprint (<!! (go (try!
(aggregate-actor-data (<? spouses)!
(<? movies)!
(<? top-5))!
(catch Exception e!
e)))))))
A lot of effort for not much benefit
Exceptions - the imminent way *
* not really unique to imminent. Other libraries use this same approach
(defn movies-by-actor [name]!
(i/future (do (Thread/sleep 2000)!
(throw (Exception. (str "Error fetching movies for actor
" name)))!
(->> actor-movies!
(filter #(= name (:name %)))!
first))))
Exceptions - the imminent way # 1
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
movies (i/flatmap cast #(i/map-future movies-by-actor %))!
spouses (i/flatmap cast #(i/map-future spouse-of %))!
results (i/sequence [spouses movies (top-5)])!
_ (prn "Fetching data...")!
result (deref (i/await results))]!
!
(i/map result #(pprint (apply aggregate-actor-data %)))!
(i/map-failure result #(pprint (str "Oops: " %)))))
;; Oops: java.lang.Exception: Error fetching movies for actor Cate Blanchett
Exceptions - the imminent way # 1
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
movies (i/flatmap cast #(i/map-future movies-by-actor %))!
spouses (i/flatmap cast #(i/map-future spouse-of %))!
results (i/sequence [spouses movies (top-5)])!
_ (prn "Fetching data...")!
result (deref (i/await results))]!
!
(i/map result #(pprint (apply aggregate-actor-data %)))!
(i/map-failure result #(pprint (str "Oops: " %)))))
imminent results are themselves functors :)
;; Oops: java.lang.Exception: Error fetching movies for actor Cate Blanchett
Exceptions - the imminent way # 2
(let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")!
movies (i/flatmap cast #(i/map-future movies-by-actor %))!
spouses (i/flatmap cast #(i/map-future spouse-of %))!
result (i/sequence [spouses movies (top-5)])]!
(prn "Fetching data...")!
(i/on-success result #(prn-to-repl (apply aggregate-actor-data %)))!
(i/on-failure result #(prn-to-repl (str "Oops: " %))))!
;; Oops: java.lang.Exception: Error fetching movies for actor Cate Blanchett
Final Thoughts
Category Theory helps you design libraries with higher
code reuse due to well known and understood
abstractions
Final Thoughts
Imminent takes advantage of that and provides an
asynchronous and composable Futures library for
Clojure
Final Thoughts
Even when compared to core.async, imminent still makes
sense unless you need the low level granularity of
channels and/or coordination via queues
Questions?
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com

More Related Content

What's hot

A deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio moduleA deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio moduleSaúl Ibarra Corretgé
 
Building native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahBuilding native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahNick Plante
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinAndrey Breslav
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuturekoji lin
 
AST Transformations
AST TransformationsAST Transformations
AST TransformationsHamletDRC
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6Solution4Future
 
Ast transformations
Ast transformationsAst transformations
Ast transformationsHamletDRC
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2José Paumard
 
50 new things we can do with Java 8
50 new things we can do with Java 850 new things we can do with Java 8
50 new things we can do with Java 8José Paumard
 
Riga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with JavassistRiga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with JavassistAnton Arhipov
 
Introduction to Debuggers
Introduction to DebuggersIntroduction to Debuggers
Introduction to DebuggersSaumil Shah
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.boyney123
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016Manoj Kumar
 
Something about Golang
Something about GolangSomething about Golang
Something about GolangAnton Arhipov
 
JavaOne 2015 - Having fun with Javassist
JavaOne 2015 - Having fun with JavassistJavaOne 2015 - Having fun with Javassist
JavaOne 2015 - Having fun with JavassistAnton Arhipov
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeCory Forsyth
 

What's hot (20)

A deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio moduleA deep dive into PEP-3156 and the new asyncio module
A deep dive into PEP-3156 and the new asyncio module
 
Building native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahBuilding native Android applications with Mirah and Pindah
Building native Android applications with Mirah and Pindah
 
JVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in KotlinJVMLS 2016. Coroutines in Kotlin
JVMLS 2016. Coroutines in Kotlin
 
CompletableFuture
CompletableFutureCompletableFuture
CompletableFuture
 
AST Transformations
AST TransformationsAST Transformations
AST Transformations
 
JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6JavaScript - new features in ECMAScript 6
JavaScript - new features in ECMAScript 6
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
50 new things we can do with Java 8
50 new things we can do with Java 850 new things we can do with Java 8
50 new things we can do with Java 8
 
Riga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with JavassistRiga Dev Day 2016 - Having fun with Javassist
Riga Dev Day 2016 - Having fun with Javassist
 
Introduction to Debuggers
Introduction to DebuggersIntroduction to Debuggers
Introduction to Debuggers
 
Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.Introduction into ES6 JavaScript.
Introduction into ES6 JavaScript.
 
ES6 PPT FOR 2016
ES6 PPT FOR 2016ES6 PPT FOR 2016
ES6 PPT FOR 2016
 
Something about Golang
Something about GolangSomething about Golang
Something about Golang
 
node ffi
node ffinode ffi
node ffi
 
JavaOne 2015 - Having fun with Javassist
JavaOne 2015 - Having fun with JavassistJavaOne 2015 - Having fun with Javassist
JavaOne 2015 - Having fun with Javassist
 
ECMAScript 6
ECMAScript 6ECMAScript 6
ECMAScript 6
 
Kotlin
KotlinKotlin
Kotlin
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to Come
 

Viewers also liked

Functional Reactive Programming
Functional Reactive ProgrammingFunctional Reactive Programming
Functional Reactive ProgrammingOlav Haugen
 
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
 
What is Reactive programming?
What is Reactive programming?What is Reactive programming?
What is Reactive programming?Kevin Webber
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsLeonardo Borges
 
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 world functional reactive programming
Real world functional reactive programmingReal world functional reactive programming
Real world functional reactive programmingEric Polerecky
 
Angular, ASP.NET Core, and Visual Studio Code - Oh My!
Angular, ASP.NET Core, and Visual Studio Code - Oh My!Angular, ASP.NET Core, and Visual Studio Code - Oh My!
Angular, ASP.NET Core, and Visual Studio Code - Oh My!Aaron Marisi
 

Viewers also liked (9)

Functional Reactive Programming
Functional Reactive ProgrammingFunctional Reactive Programming
Functional Reactive Programming
 
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
 
What is Reactive programming?
What is Reactive programming?What is Reactive programming?
What is Reactive programming?
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
 
ASP.NET MVC Core
ASP.NET MVC CoreASP.NET MVC Core
ASP.NET MVC Core
 
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
 
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 world functional reactive programming
Real world functional reactive programmingReal world functional reactive programming
Real world functional reactive programming
 
Angular, ASP.NET Core, and Visual Studio Code - Oh My!
Angular, ASP.NET Core, and Visual Studio Code - Oh My!Angular, ASP.NET Core, and Visual Studio Code - Oh My!
Angular, ASP.NET Core, and Visual Studio Code - Oh My!
 

Similar to The algebra of library design

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
 
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
 
Clojure: Simple By Design
Clojure: Simple By DesignClojure: Simple By Design
Clojure: Simple By DesignAll Things Open
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - StockholmJan Kronquist
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Introthnetos
 
Arduino programming of ML-style in ATS
Arduino programming of ML-style in ATSArduino programming of ML-style in ATS
Arduino programming of ML-style in ATSKiwamu Okabe
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMsunng87
 
(first '(Clojure.))
(first '(Clojure.))(first '(Clojure.))
(first '(Clojure.))niklal
 
Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScriptChengHui Weng
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and FutureJohn De Goes
 
Software Dendrology by Brandon Bloom
Software Dendrology by Brandon BloomSoftware Dendrology by Brandon Bloom
Software Dendrology by Brandon BloomHakka Labs
 
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
 
From Python to Scala
From Python to ScalaFrom Python to Scala
From Python to ScalaFFunction inc
 
Go Containers
Go ContainersGo Containers
Go Containersjgrahamc
 
All I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School AlgebraAll I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School AlgebraEric Normand
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchainedEduard Tomàs
 
Testing stateful, concurrent, and async systems using test.check
Testing stateful, concurrent, and async systems using test.checkTesting stateful, concurrent, and async systems using test.check
Testing stateful, concurrent, and async systems using test.checkEric Normand
 
Go Concurrency
Go ConcurrencyGo Concurrency
Go Concurrencyjgrahamc
 

Similar to The algebra of library design (20)

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
 
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
 
Clojure: Simple By Design
Clojure: Simple By DesignClojure: Simple By Design
Clojure: Simple By Design
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - Stockholm
 
Clojure Intro
Clojure IntroClojure Intro
Clojure Intro
 
Music as data
Music as dataMusic as data
Music as data
 
Arduino programming of ML-style in ATS
Arduino programming of ML-style in ATSArduino programming of ML-style in ATS
Arduino programming of ML-style in ATS
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
 
(first '(Clojure.))
(first '(Clojure.))(first '(Clojure.))
(first '(Clojure.))
 
Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScript
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and Future
 
Software Dendrology by Brandon Bloom
Software Dendrology by Brandon BloomSoftware Dendrology by Brandon Bloom
Software Dendrology by Brandon Bloom
 
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
 
From Python to Scala
From Python to ScalaFrom Python to Scala
From Python to Scala
 
Go Containers
Go ContainersGo Containers
Go Containers
 
Go Containers
Go ContainersGo Containers
Go Containers
 
All I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School AlgebraAll I Needed for Functional Programming I Learned in High School Algebra
All I Needed for Functional Programming I Learned in High School Algebra
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchained
 
Testing stateful, concurrent, and async systems using test.check
Testing stateful, concurrent, and async systems using test.checkTesting stateful, concurrent, and async systems using test.check
Testing stateful, concurrent, and async systems using test.check
 
Go Concurrency
Go ConcurrencyGo Concurrency
Go Concurrency
 

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
 
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
 
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
 
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 (16)

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
 
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
 
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
 
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

Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 

Recently uploaded (20)

Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 

The algebra of library design

  • 1. The algebra of library design #cljsyd - October 2014 Leonardo Borges @leonardo_borges www.leonardoborges.com www.thoughtworks.com
  • 3. More specifically… • Algebraic structures, studied in Abstract Algebra • a set with one or more operations on it • Category theory is another way to study these structures
  • 4. Overview • The problem with Clojure futures • A better futures library • Functors, Applicative Functors and Monads • What about core.async (and others?)
  • 5. The beginning… (def age (future (do (Thread/sleep 2000)! 31)))! (prn "fetching age...")! ! (def double-age (* 2 @age))! (prn "age, doubled: " double-age)! ! (prn "doing something else important...")
  • 6. Do you see any issues?
  • 7. The beginning… (def age (future (do (Thread/sleep 2000)! 31)))! (prn "fetching age...")! ! (def double-age (* 2 @age))! (prn "age, doubled: " double-age)! ! (prn "doing something else important...")! ! ;; "fetching age..."! ;; "age, doubled: " 62! ;; "doing something else important..."!
  • 8. It looks like we would like to execute something once the Future has completed
  • 9. A first glance at imminent (require '[imminent.core :as i])! ! (def age (i/future (do (Thread/sleep 2000)! 31)))! (prn "fetching age...")! (def double-age (i/map age #(* % 2)))! (i/on-success double-age #(prn "age, doubled: " %))! ! (prn "doing something else important...")
  • 10. A first glance at imminent (require '[imminent.core :as i])! ! (def age (i/future (do (Thread/sleep 2000)! 31)))! (prn "fetching age...")! (def double-age (i/map age #(* % 2)))! (i/on-success double-age #(prn "age, doubled: " %))! ! (prn "doing something else important...")! ! ;; "fetching age..."! ;; "doing something else important..."! ;; "age, doubled: " 62!
  • 11. Functor class Functor f where! fmap :: (a -> b) -> f a -> f b
  • 12. Another example (def age (future (do (Thread/sleep 2000)! 31)))! (def name (future (do (Thread/sleep 2000)! "Leonardo")))! (prn "fetching name...")! (prn (format "%s is %s years old" @name @age))! (prn "more important things going on...")
  • 13. Same as before, only this time we want to execute the code once both futures have completed
  • 14. Rewriting it in imminent (def age (i/future (do (Thread/sleep 2000)! 31)))! (def name (i/future (do (Thread/sleep 2000)! "Leonardo")))! (prn "fetching name...")! (def both (i/sequence [name age]))! (i/on-success both ! (fn [[name age]]! (prn (format "%s is %s years old" name age))))! ! (prn "more important things going on...")! !
  • 15. Rewriting it in imminent (def age (i/future (do (Thread/sleep 2000)! 31)))! (def name (i/future (do (Thread/sleep 2000)! "Leonardo")))! (prn "fetching name...")! (def both (i/sequence [name age]))! (i/on-success both ! (fn [[name age]]! (prn (format "%s is %s years old" name age))))! ! (prn "more important things going on...")! ! ;; "fetching name..."! ;; "more important things going on..."! ;; "Leonardo is 31 years old"!
  • 16. Monad class Monad m where! (>>=) :: m a -> (a -> m b) -> m b! return :: a -> m a
  • 17. Monad class Monad m where! (>>=) :: m a -> (a -> m b) -> m b! return :: a -> m a (>>=) is also called bind, flatmap, selectMany and mapcat…
  • 18. Monad - derived functions liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
  • 19. Monad - derived functions liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r (defn mlift2! [f]! (fn [ma mb]! (flatmap ma! (fn [a]! (flatmap mb! (fn [b]! (pure (f a b))))))))
  • 20. Monad - derived functions sequence :: Monad m => [m a] -> m [a]
  • 21. Monad - derived functions sequence :: Monad m => [m a] -> m [a] (defn sequence! [ms]! (reduce (mlift2 conj)! (pure [])! ms))
  • 22. Monad - derived functions mapM :: Monad m => (a -> m b) -> [a] -> m [b]
  • 23. Monad - derived functions mapM :: Monad m => (a -> m b) -> [a] -> m [b] (defn mmap! [f vs]! (sequence (map f vs)))
  • 24. Monad - derived functions mapM :: Monad m => (a -> m b) -> [a] -> m [b] (defn mmap! [f vs]! (sequence (map f vs))) plus a bunch of others…
  • 25. Let’s look at a more concrete example
  • 26. Aggregating movie data (defn cast-by-movie [name]! (future (do (Thread/sleep 5000)! (:cast movie))))! ! (defn movies-by-actor [name]! (do (Thread/sleep 2000)! (->> actor-movies! (filter #(= name (:name %)))! first)))! ! (defn spouse-of [name]! (do (Thread/sleep 2000)! (->> actor-spouse! (filter #(= name (:name %)))! first)))! ! (defn top-5 []! (future (do (Thread/sleep 5000)! top-5-movies)))!
  • 27. The output ({:name "Cate Blanchett",! :spouse "Andrew Upton",! :movies! ("Lord of The Rings: The Fellowship of The Ring - (top 5)"...)}! {:name "Elijah Wood",! :spouse "Unknown",! :movies! ("Eternal Sunshine of the Spotless Mind"...)}! ...)
  • 28. One possible solution (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! movies (pmap movies-by-actor @cast)! spouses (pmap spouse-of @cast)! top-5 (top-5)]! (prn "Fetching data...")! (pprint (aggregate-actor-data spouses movies @top-5)))
  • 29. One possible solution (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! movies (pmap movies-by-actor @cast)! spouses (pmap spouse-of @cast)! top-5 (top-5)]! (prn "Fetching data...")! (pprint (aggregate-actor-data spouses movies @top-5))) ;; "Elapsed time: 10049.334 msecs"
  • 30. We face the same problems as before
  • 32. But the point is not having to do so
  • 33. In imminent (defn cast-by-movie [name]! (i/future (do (Thread/sleep 5000)! (:cast movie))))! ! (defn movies-by-actor [name]! (i/future (do (Thread/sleep 2000)! (->> actor-movies! (filter #(= name (:name %)))! first))))! ! (defn spouse-of [name]! (i/future (do (Thread/sleep 2000)! (->> actor-spouse! (filter #(= name (:name %)))! first))))! ! (defn top-5 []! (i/future (do (Thread/sleep 5000)! top-5-movies)))
  • 34. In imminent (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! movies (i/flatmap cast #(i/map-future movies-by-actor %))! spouses (i/flatmap cast #(i/map-future spouse-of %))! result (i/sequence [spouses movies (top-5)])]! (prn "Fetching data...")! (pprint (apply aggregate-actor-data! (i/dderef (i/await result)))))
  • 35. In imminent (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! movies (i/flatmap cast #(i/map-future movies-by-actor %))! spouses (i/flatmap cast #(i/map-future spouse-of %))! result (i/sequence [spouses movies (top-5)])]! (prn "Fetching data...")! (pprint (apply aggregate-actor-data! (i/dderef (i/await result))))) ;; "Elapsed time: 7087.603 msecs"
  • 37. We can optionally block and wait for a result using the “i/await” function
  • 38. Ok, that’s cool! But what about Applicative Functors?
  • 39. Writing this sucks (defn int-f [n]! (i/future (do (Thread/sleep 2000)! (* 2 n))))! ! ! (-> (i/bind! (int-f 10)! (fn [a] (i/bind! (int-f a)! (fn [b] (i/bind! (int-f b)! (fn [c] ! (i/pure (+ a b c)))))))
  • 40. Monadic “do” notation (i/mdo [a (int-f 10)! b (int-f a)! c (int-f b)]! (i/pure (+ a b c)))
  • 41. Monadic “do” notation (i/mdo [a (int-f 10)! b (int-f a)! c (int-f b)]! (i/pure (+ a b c))) How long does this computation take?
  • 42. Monadic “do” notation (i/mdo [a (int-f 10)! b (int-f a)! c (int-f b)]! (i/pure (+ a b c))) How long does this computation take? ;; "Elapsed time: 6002.39 msecs"
  • 43. What if the computations don’t depend on each other?
  • 44. Monadic “do” notation (i/mdo [a (int-f 10)! b (int-f 20)! c (int-f 30)]! (i/pure (+ a b c)))
  • 45. Monadic “do” notation (i/mdo [a (int-f 10)! b (int-f 20)! c (int-f 30)]! (i/pure (+ a b c))) How long does this take now?
  • 46. Monadic “do” notation (i/mdo [a (int-f 10)! b (int-f 20)! c (int-f 30)]! (i/pure (+ a b c))) How long does this take now? ;; "Elapsed time: 6002.39 msecs"
  • 47. ?
  • 48. The ‘do-notation’ is used to sequence monadic steps so we remain serial, but still asynchronous
  • 49. Applicative Functor class Functor f => Applicative f where! pure :: a -> f a! (<*>) :: f (a -> b) -> f a -> f b!
  • 50. Previous example, rewritten in applicative style (i/<*> (i/map (int-f 10) (curry + 3))! (int-f 20)! (int-f 30)) ;;"Elapsed time: 2001.509 msecs"
  • 51. It turns out this pattern is a derived function from Applicative Functors
  • 52. Applicative Functor - derived functions liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
  • 53. Applicative Functor - derived functions liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c (defn alift! [f]! (fn [& as]! {:pre [(seq as)]}! (let [curried (curry f (count as))]! (apply <*>! (fmap curried (first as))! (rest as)))))
  • 54. “alift” assumes every Applicative Functor is also Functor
  • 55. Previous example, rewritten using “alift" ;;"Elapsed time: 2001.509 msecs" ((i/alift +) (int-f 10) (int-f 20) (int-f 30))
  • 56. It looks a lot like function application :)
  • 57. Applicatives give us the parallel semantics without giving up convenience
  • 58. Ok, this is awesome! But we have core.async!
  • 59. The movies example, revisited (defn cast-by-movie [name]! (let [c (chan)]! (go (<! (timeout 5000))! (>! c (:cast movie))! (close! c))! c))! ! (defn movies-by-actor [name]! (let [c (chan)]! (go (<! (timeout 2000))! (>! c (->> actor-movies! (filter #(= name (:name %)))! first))! (close! c))! c))
  • 60. The movies example, revisited (defn spouse-of [name]! (let [c (chan)]! (go (<! (timeout 2000))! (>! c (->> actor-spouse! (filter #(= name (:name %)))! first))! (close! c))! c))! ! (defn top-5 []! (let [c (chan)]! (go (<! (timeout 5000))! (>! c top-5-movies)! (close! c))! c))! ! ! (defn async-pmap [f source]! (go (->> (map f (<! source))! async/merge! (async/into [])! <!)))
  • 61. The movies example, revisited (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! m-cast (mult cast)! movies (async-pmap movies-by-actor (tap m-cast (chan)))! spouses (async-pmap spouse-of (tap m-cast (chan)))! top-5 (top-5)]! (prn "Fetching data...")! (pprint (<!! (go (aggregate-actor-data (<! spouses)! (<! movies)! (<! top-5))))))! ! ;; "Elapsed time: 7088.834 msecs"
  • 62. “mult” and “tap” have no business being in that code
  • 63. they are necessary because channels are single-take containers
  • 64. Exceptions core.async swallows them by default (defn movies-by-actor [name]! (let [c (chan)]! (go (<! (timeout 2000))! (throw (Exception. (str "Error fetching movies for actor " name)))! (>! c (->> actor-movies! (filter #(= name (:name %)))! first))! (close! c))! c))
  • 65. Exceptions core.async swallows them by default (defn movies-by-actor [name]! (let [c (chan)]! (go (<! (timeout 2000))! (throw (Exception. (str "Error fetching movies for actor " name)))! (>! c (->> actor-movies! (filter #(= name (:name %)))! first))! (close! c))! c)) (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! m-cast (mult cast)! movies (async-pmap movies-by-actor (tap m-cast (chan)))! spouses (async-pmap spouse-of (tap m-cast (chan)))! top-5 (top-5)]! (prn "Fetching data...")! (pprint (<!! (go (aggregate-actor-data (<! spouses)! (<! movies)! (<! top-5))))))! ! ;; nil - WTF???"
  • 66. Exceptions - workaround (defn throw-err [e]! (when (instance? Throwable e) (throw e))! e)! ! (defmacro <? [ch]! `(throw-err (<! ~ch)))! ! ! (defn movies-by-actor [name]! (let [c (chan)]! (go (try (do (<! (timeout 2000))! (throw (Exception. (str "Error fetching movies for actor " name)))! (>! c (->> actor-movies! (filter #(= name (:name %)))! first))! (close! c))! (catch Exception e! (do (>! c e)! (close! c)))))! c))
  • 67. Exceptions - workaround (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! m-cast (mult cast)! movies (async-pmap movies-by-actor (tap m-cast (chan)))! spouses (async-pmap spouse-of (tap m-cast (chan)))! top-5 (top-5)]! (prn "Fetching data...")! (pprint (<!! (go (try! (aggregate-actor-data (<? spouses)! (<? movies)! (<? top-5))! (catch Exception e! e)))))))
  • 68. A lot of effort for not much benefit
  • 69. Exceptions - the imminent way * * not really unique to imminent. Other libraries use this same approach (defn movies-by-actor [name]! (i/future (do (Thread/sleep 2000)! (throw (Exception. (str "Error fetching movies for actor " name)))! (->> actor-movies! (filter #(= name (:name %)))! first))))
  • 70. Exceptions - the imminent way # 1 (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! movies (i/flatmap cast #(i/map-future movies-by-actor %))! spouses (i/flatmap cast #(i/map-future spouse-of %))! results (i/sequence [spouses movies (top-5)])! _ (prn "Fetching data...")! result (deref (i/await results))]! ! (i/map result #(pprint (apply aggregate-actor-data %)))! (i/map-failure result #(pprint (str "Oops: " %))))) ;; Oops: java.lang.Exception: Error fetching movies for actor Cate Blanchett
  • 71. Exceptions - the imminent way # 1 (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! movies (i/flatmap cast #(i/map-future movies-by-actor %))! spouses (i/flatmap cast #(i/map-future spouse-of %))! results (i/sequence [spouses movies (top-5)])! _ (prn "Fetching data...")! result (deref (i/await results))]! ! (i/map result #(pprint (apply aggregate-actor-data %)))! (i/map-failure result #(pprint (str "Oops: " %))))) imminent results are themselves functors :) ;; Oops: java.lang.Exception: Error fetching movies for actor Cate Blanchett
  • 72. Exceptions - the imminent way # 2 (let [cast (cast-by-movie "Lord of The Rings: The Fellowship of The Ring")! movies (i/flatmap cast #(i/map-future movies-by-actor %))! spouses (i/flatmap cast #(i/map-future spouse-of %))! result (i/sequence [spouses movies (top-5)])]! (prn "Fetching data...")! (i/on-success result #(prn-to-repl (apply aggregate-actor-data %)))! (i/on-failure result #(prn-to-repl (str "Oops: " %))))! ;; Oops: java.lang.Exception: Error fetching movies for actor Cate Blanchett
  • 73. Final Thoughts Category Theory helps you design libraries with higher code reuse due to well known and understood abstractions
  • 74. Final Thoughts Imminent takes advantage of that and provides an asynchronous and composable Futures library for Clojure
  • 75. Final Thoughts Even when compared to core.async, imminent still makes sense unless you need the low level granularity of channels and/or coordination via queues