SlideShare a Scribd company logo
1 of 75
Download to read offline
Monads in Clojure
Or why burritos shouldn’t be scary [I]
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com

[I] http://blog.plover.com/prog/burritos.html
Tuesday, 4 March 14
Monads in Clojure
The plan:
Type Signatures in Haskell
The Monad Type Class
A few useful monads

This presentation is a super condensed version of my blog post
series on monads [II]

[II] http://bit.ly/monads-part-i
Tuesday, 4 March 14
Prelude

Type signatures in Haskell

Tuesday, 4 March 14
Type signatures in Haskell
Vectors as maps
import qualified Data.Map as Map -- just giving Data.Map an alias
mkVec :: a -> a -> Map.Map [Char] a -- this is the type signature

This is a function of two
arguments of type a

Tuesday, 4 March 14
Type signatures in Haskell
Vectors as maps
import qualified Data.Map as Map -- just giving Data.Map an alias
mkVec :: a -> a -> Map.Map [Char] a -- this is the type signature

It returns a Map where
keys are of type [Char]
and values are of type a

Tuesday, 4 March 14
Type signatures in Haskell
Vectors as maps
import qualified Data.Map as Map -- just giving Data.Map an alias
mkVec :: a -> a -> Map.Map [Char] a -- this is the type signature
mkVec x y = Map.fromList [("x", x), ("y", y)] -- this is the implementation.
You can ignore this part.

-- using it
myVec = mkVec 10 15
Map.lookup "x" myVec -- Just 10

Tuesday, 4 March 14
Type signatures in Haskell
Multiplication

(*) :: Num a => a -> a -> a

This is also a function of
two arguments of type a
Tuesday, 4 March 14
Type signatures in Haskell
Multiplication
Num a is a type
constraint
(*) :: Num a => a -> a -> a

In this case, the type constraint tells the compiler
that (*)works on any value a as long as a is an
instance of Num
Tuesday, 4 March 14
Monads
what on earth are they?

They’re simply an abstraction
...with a funny name to confuse people.

Tuesday, 4 March 14
Monads
what on earth are they?

They are not however....
... a burrito
... an elephant
... a space suit
... or a writing desk.

Tuesday, 4 March 14
Monads
what on earth are they?

Every monad has an associated “context”
It can be useful to think of them as “wrapping” some value

Tuesday, 4 March 14
The Monad Type Class
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
x >> y = x >>= _ -> y

Let’s understand those type signatures!
Tuesday, 4 March 14
The Monad Type Class
return :: a -> m a

Single argument of type a

Tuesday, 4 March 14
The Monad Type Class
return :: a -> m a

returns a in a “context” m

Tuesday, 4 March 14
The Monad Type Class
return :: a -> m a
This is how we turn plain values into monadic values

Tuesday, 4 March 14
The Monad Type Class
return :: a -> m a
return

is an unfortunate name as it is confusing. It has
nothing to do with the return keywords in languages like Java.
return is sometimes called unit

Tuesday, 4 March 14
The Monad Type Class
(>>=) :: m a -> (a -> m b) -> m b
>>=

Tuesday, 4 March 14

is pronounced bind and takes two arguments
The Monad Type Class
(>>=) :: m a -> (a -> m b) -> m b

A monad

Tuesday, 4 March 14

m a
The Monad Type Class
(>>=) :: m a -> (a -> m b) -> m b

and a function from values of type a
to monads of type m

Tuesday, 4 March 14

b
The Monad Type Class
(>>=) :: m a -> (a -> m b) -> m b

Somehow each monad knows how to extract values from
its context and “bind” them to the given function

Tuesday, 4 March 14
The Monad Type Class
(>>=) :: m a -> (a -> m b) -> m b

and it returns b in a
“context” m

Tuesday, 4 March 14
The Monad Type Class
(>>) :: m a -> m b -> m b
x >> y = x >>= _ -> y
You can work out the type signature all by yourself now :)

Tuesday, 4 March 14
The Monad Type Class
(>>) :: m a -> m b -> m b
x >> y = x >>= _ -> y
>> is pronounced then

and includes a default

implementation in terms of bind

Tuesday, 4 March 14

(>>=)
The Monad Type Class
(>>) :: m a -> m b -> m b
x >> y = x >>= _ -> y

Its second argument to bind is a
function which ignores its argument

Tuesday, 4 March 14
The Monad Type Class
(>>) :: m a -> m b -> m b
x >> y = x >>= _ -> y

It simply returns the value yielded by
“unwrapping” the context of y

Tuesday, 4 March 14
Example I
Calculating all combinations between elements of two lists using the
list monad
combinations :: [(Int,Int)]
combinations =
[1, 2, 3] >>= a -> [4, 5]
>>= b -> return (a,b)
-- [(1,4),(1,5),(2,4),(2,5),(3,4),(3,5)]

Tuesday, 4 March 14
Example I
Calculating all combinations between elements of two lists using the
list monad

meh. It’s damn hard to read.
And we don’t want to type that much.
There’s a better way

Tuesday, 4 March 14
Example I
Calculating all combinations between elements of two lists using the
list monad (using do notation)
combinations' :: [(Int,Int)]
combinations' = do
a <- [1, 2, 3]
b <- [4, 5]
return (a,b)

-- [(1,4),(1,5),(2,4),(2,5),(3,4),(3,5)]

Tuesday, 4 March 14
You’ve just seen your first monad, the list monad!

Tuesday, 4 March 14
The Monad Type Class *
As if it worked for lists only

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

* this isn’t valid Haskell. It’s just to illustrate the concept
Tuesday, 4 March 14
Now let’s learn how it does its thing...
...in Clojure!

Tuesday, 4 March 14
The List Monad
Let’s do it together

(def list-m {
:return (fn [v] ...
:bind
(fn [mv f]
...
})

Tuesday, 4 March 14

)
)
The List Monad
Let’s do it together

(def list-m {
:return (fn [v] (list v))
:bind
(fn [mv f]
...
)
})

Tuesday, 4 March 14
The List Monad
Let’s do it together

(def list-m {
:return (fn [v] (list v))
:bind
(fn [mv f]
(mapcat f mv))
})

Tuesday, 4 March 14
The List Monad
Now we’re ready to use it
(defn combinations []
(let [bind
(:bind list-m)
return (:return list-m)]
(bind [1 2 3]
(fn [a]
(bind [4 5]
(fn [b]
(return [a b])))))))
;; ([1 4] [1 5] [2 4] [2 5] [3 4] [3 5])
Tuesday, 4 March 14
The List Monad
Now we’re ready to use it

ugh. Just as ugly.
But we know there’s a better way.
Can we use the do notation in Clojure?

Tuesday, 4 March 14
Macros to the rescue
Haskell’s do notation in Clojure
(defn m-steps [m [name val & bindings] body]
(if (seq bindings)
`(-> ~val
((:bind ~m) (fn [~name]
~(m-steps m bindings body))))
`(-> ~val
((:bind ~m) (fn [~name]
((:return ~m) ~body))))))
(defmacro do-m [m bindings body]
(m-steps m bindings body))
Tuesday, 4 March 14
Macros to the rescue
Haskell’s do notation in Clojure

Ignore the implementation. You can study it later :)

Tuesday, 4 March 14
The List Monad
Now we’re ready to use it
(defn combinations []
(do-m list-m
[a [1 2 3]
b [4 5]]
[a b]))
;; ([1 4] [1 5] [2 4] [2 5] [3 4] [3 5])

Tuesday, 4 March 14
Familiar?
List comprehension

(defn combinations []
(for [a [1 2 3]
b [4 5]]
[a b]))
;; ([1 4] [1 5] [2 4] [2 5] [3 4] [3 5])

Tuesday, 4 March 14
Example II
Adding two numbers
(defn add [a b]
(+ a b))
(add 1 2) ;; 3

(add 1 nil)
;; NullPointerException

Tuesday, 4 March 14
Example II
[Maybe]Adding two numbers
(defn m-add [ma mb]
(do-m maybe-m [a ma
b mb]
(+ a b)))
(m-add 1 2) ;; 3
(m-add nil 1) ;; nil

Tuesday, 4 March 14
The Maybe Monad
Again, everyone together

(def maybe-m {
:return (fn [v] ...)
:bind (fn [mv f]
...
)
})

Tuesday, 4 March 14
The Maybe Monad
Again, everyone together

(def maybe-m {
:return (fn [v] v)
:bind (fn [mv f]
...
)
})

Tuesday, 4 March 14
The Maybe Monad
Again, everyone together

(def maybe-m {
:return (fn [v] v)
:bind (fn [mv f]
(when mv
(f mv)))
})

Tuesday, 4 March 14
Not too bad, huh? Ready for more?

Tuesday, 4 March 14
Example III
Application configuration
(defn connect-to-db [env]
(let [db-uri (:db-uri env)]
(prn (format "Connected to db at %s" db-uri))))
(defn connect-to-api [env]
(let [api-key (:api-key env)
env (ask)]
(prn (format "Connected to api with key %s" api-key))))

Tuesday, 4 March 14
Example III
Application configuration
(defn run-app [env]
(do
(connect-to-db env)
(connect-to-api env)
"Done."))

(run-app {:db-uri "user:passwd@host/dbname"
:api-key "AF167"})
;; "Connected to db at user:passwd@host/dbname"
;; "Connected to api with key AF167"
;; "Done."

Tuesday, 4 March 14
Example III
Application configuration

Passing env on to every single function that
depends on it can be cumbersome.
Obviously we don’t want to resort to global
vars. Can monads help?

Tuesday, 4 March 14
Example III
Application configuration with the Reader Monad
(defn connect-to-db []
(do-m reader-m
[db-uri (asks :db-uri)]
(prn (format "Connected to db at %s" db-uri))))
(defn connect-to-api []
(do-m reader-m
[api-key (asks :api-key)
env (ask)]
(prn (format "Connected to api with key %s" api-key))))

Bear with me for now. These will be
explained soon.
Tuesday, 4 March 14
Example III
Application configuration with the Reader Monad
(defn run-app []
(do-m reader-m
[_ (m-connect-to-db)
_ (m-connect-to-api)]
(prn "Done.")))

Note the env parameter disappeared.
The Reader monad somehow feeds that
into our functions.

((run-app) {:db-uri "user:passwd@host/dbname"
:api-key "AF167"})
;; "Connected to db at user:passwd@host/dbname"
;; "Connected to api with key AF167"
;; "Done."
Also this is now a function call as
run-app is now pure
Tuesday, 4 March 14
Example III
Application configuration with the Reader Monad

But, how how does it work?!

Tuesday, 4 March 14
The Reader Monad
Tricky one, but not that tricky

(defn ask [] identity)
(defn asks [f]
(fn [env]
(f env)))

The function names come from
Haskell. They are defined in the
MonadReader type class.
Tuesday, 4 March 14
The Reader Monad
Tricky one, but not that tricky

(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

There’s a lot going on in bind.
Let’s unravel it.
Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
This:
(defn connect-to-db []
(do-m reader-m
[db-uri (asks :db-uri)]
(prn (format "Connected to db at %s" db-uri))))

Expands into:
((:bind reader-m)
(asks :db-uri)
(fn* ([db-uri]
((:return reader-m) (prn "Connected to db at " db-uri)))))

Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

(let [m (fn [env] (:db-uri env))
k (fn* ([db-uri]
((:return reader-m) (prn "Connected to db at " db-uri))))]
((fn [r]
((k (m r)) r))
{:db-uri "user:passwd@host/dbname"
:api-key "AF167"}))
Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

(let [m (fn [env] (:db-uri env))
k (fn* ([db-uri]
((:return reader-m) (prn "Connected to db at " db-uri))))]
(let [r {:db-uri "user:passwd@host/dbname"
:api-key "AF167"}]
((k (m r)) r)))

Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

(let [m (fn [env] (:db-uri env))
k (fn* ([db-uri]
((:return reader-m) (prn "Connected to db at " db-uri))))]
(let [r {:db-uri "user:passwd@host/dbname"
:api-key "AF167"}]
((k "user:passwd@host/dbname") r)))

Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

(let [m (fn [env] (:db-uri env))
k (fn* ([db-uri]
((:return reader-m) nil)))]
(let [r {:db-uri "user:passwd@host/dbname"
:api-key "AF167"}]
((k "user:passwd@host/dbname") r)))

Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

(let [m (fn [env] (:db-uri env))
k (fn* ([db-uri]
((fn [a] (fn [_] a) nil)))]
(let [r {:db-uri "user:passwd@host/dbname"
:api-key "AF167"}]
((k "user:passwd@host/dbname") r)))

Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

(let [m (fn [env] (:db-uri env))
k (fn* ([db-uri]
((fn [a] (fn [_] a) nil)))]
(let [r {:db-uri "user:passwd@host/dbname"
:api-key "AF167"}]
((fn [_] nil) r)))

Tuesday, 4 March 14
The Reader Monad
Expanding connect-to-db
(def reader-m
{:return (fn [a]
(fn [_] a))
:bind (fn [m k]
(fn [r]
((k (m r)) r)))})

(let [m (fn [env] (:db-uri env))
k (fn* ([db-uri]
((fn [a] (fn [_] a) nil)))]
(let [r {:db-uri "user:passwd@host/dbname"
:api-key "AF167"}]
nil))

Tuesday, 4 March 14
The Reader Monad

Simple, right? :)

Tuesday, 4 March 14
Example IV
Dependency Injection

(require '[app.repository :as repository])
(defn clone! [id user]
(let [old-user (repository/fetch-by-id id {})
cloned-user (repository/create! (compute-clone old-user) user)
updated-user (assoc old-user :clone-id (:id cloned-user))]
(repository/update! old-user updated-user user)))

See the problem?
Tuesday, 4 March 14
Example IV
Dependency Injection: the problem

• clone! is tightly coupled to the repository namespace
• It can’t be tested in isolation without resorting to heavy
mocking of the involved functions
• It’s limited to a single repository implementation - makes
experimenting at the REPL harder
• ...
Basically, good software
engineering principles apply
Tuesday, 4 March 14
Example IV
Dependency Injection using the Reader Monad

Let’s start by turning our
repository into a module that can
be injected into our function

Tuesday, 4 March 14
Example IV
Dependency Injection using the Reader Monad

There’s a couple of ways in
which we can do that
I’ll use protocols as they have
added performance benefits

Tuesday, 4 March 14
Example IV
Dependency Injection using the Reader Monad
(defprotocol UserRepository
(fetch-by-id! [this id])
(create! [this user username])
(update! [this old-user new-user username]))
(defn mk-user-repo []
(reify UserRepository
(fetch-by-id! [this id]
(prn "Fetched user id " id))
(create! [this user username]
(prn "Create user triggered by " username))
(update! [this old-user new-user username]
(prn "Updated user triggered by " username))))

Tuesday, 4 March 14
Example IV
Dependency Injection using the Reader Monad

Remember: One of the advantages of the reader
monad is not having to pass parameters around to
every single function that needs it

Tuesday, 4 March 14
Example IV
Dependency Injection using the Reader Monad

With that in mind, let’s rewrite clone!

Tuesday, 4 March 14
Example IV
Dependency Injection using the Reader Monad
It can be helpful to think of clone as having this type signature:
;;
clone! :: Number -> String -> Reader UserRepository Number
(defn clone! [id user]
(do-m reader-m [repo (ask)]
(let [old-user (fetch-by-id! repo id)
cloned-user (create! repo (compute-clone old-user) user)
updated-user (assoc old-user :clone-id (:id cloned-user))]
(update! repo old-user updated-user user))))

Tuesday, 4 March 14
Example IV
Dependency Injection using the Reader Monad
And this is how we might use it:
(defn run-clone []
(do-m reader-m
[_ (clone! 10 "leo")]
(prn "Cloned.")))
((run-clone) (mk-user-repo))

;;
;;
;;
;;
;;
Tuesday, 4 March 14

"Fetched user id " 10
"Compute clone for user"
"Create user triggered by " "leo"
"Updated user triggered by " "leo"
"Cloned."
The Reader Monad
A few observations from a clojure perspective

• Useful abstraction for computations that read values from a shared
environment
• As we saw, it has multiple use cases such as configuration and
dependency injection
• I’ve cheated in the examples:
• Each function using the reader monad also performed IO - via prn
• In Haskell, IO is a monad so we would need to use monad
transformers to compose them - beyond the scope of this
presentation

Tuesday, 4 March 14
Monads: Summary
• Lots of useful abstractions through a common interface
• Some monads, such as Maybe and Either, are a lot more powerful in
a statically typed language like Haskell or Scala due to its usage being
encoded in the type system, as well as native support to pattern
matching
• Others, such as the Reader monad, can be very useful in a dynamic
setting - though you don’t have the type system to tell you when you
stuff up at compile time
• In such cases, type annotations in comments can be useful

Tuesday, 4 March 14
Questions?
Leonardo Borges
@leonardo_borges
www.leonardoborges.com
www.thoughtworks.com

Tuesday, 4 March 14

More Related Content

What's hot

Árvores: Conceitos e binárias
Árvores:  Conceitos e bináriasÁrvores:  Conceitos e binárias
Árvores: Conceitos e bináriasSérgio Souza Costa
 
Encontrar o MAIOR e o MENOR elemento da Lista Encadeada
Encontrar o MAIOR e o MENOR elemento da Lista EncadeadaEncontrar o MAIOR e o MENOR elemento da Lista Encadeada
Encontrar o MAIOR e o MENOR elemento da Lista EncadeadaElaine Cecília Gatto
 
fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...
fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...
fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...Fermacell BV
 
Inserindo em Ordem Crescente na Lista Encadeada
Inserindo em Ordem Crescente na Lista EncadeadaInserindo em Ordem Crescente na Lista Encadeada
Inserindo em Ordem Crescente na Lista EncadeadaElaine Cecília Gatto
 
18 hashing
18 hashing18 hashing
18 hashingdeonnash
 
EGGER Worktops Premium Collection
EGGER Worktops Premium CollectionEGGER Worktops Premium Collection
EGGER Worktops Premium CollectionEGGER UK
 
Algoritmos de ordenação - heapsort
Algoritmos de ordenação - heapsortAlgoritmos de ordenação - heapsort
Algoritmos de ordenação - heapsortBruno Bitencourt Luiz
 
Análise de Algoritmos - Método Guloso
Análise de Algoritmos - Método GulosoAnálise de Algoritmos - Método Guloso
Análise de Algoritmos - Método GulosoDelacyr Ferreira
 
Functional programming
Functional programmingFunctional programming
Functional programmingijcd
 
PHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de DadosPHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de DadosDaniel Brandão
 
tmn - Introdução ao JavaScript
tmn - Introdução ao JavaScripttmn - Introdução ao JavaScript
tmn - Introdução ao JavaScriptClaudio Gamboa
 
N Queen Algorithm
N Queen AlgorithmN Queen Algorithm
N Queen AlgorithmA.I. Tazib
 

What's hot (16)

Árvores: Conceitos e binárias
Árvores:  Conceitos e bináriasÁrvores:  Conceitos e binárias
Árvores: Conceitos e binárias
 
Catalan
CatalanCatalan
Catalan
 
Encontrar o MAIOR e o MENOR elemento da Lista Encadeada
Encontrar o MAIOR e o MENOR elemento da Lista EncadeadaEncontrar o MAIOR e o MENOR elemento da Lista Encadeada
Encontrar o MAIOR e o MENOR elemento da Lista Encadeada
 
fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...
fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...
fermacell Montagehandboek - Integrale oplossingen voor de totale binnenafbouw...
 
Arrays em java
Arrays em javaArrays em java
Arrays em java
 
Carta de crédito
Carta de créditoCarta de crédito
Carta de crédito
 
Inserindo em Ordem Crescente na Lista Encadeada
Inserindo em Ordem Crescente na Lista EncadeadaInserindo em Ordem Crescente na Lista Encadeada
Inserindo em Ordem Crescente na Lista Encadeada
 
Red black tree
Red black treeRed black tree
Red black tree
 
18 hashing
18 hashing18 hashing
18 hashing
 
EGGER Worktops Premium Collection
EGGER Worktops Premium CollectionEGGER Worktops Premium Collection
EGGER Worktops Premium Collection
 
Algoritmos de ordenação - heapsort
Algoritmos de ordenação - heapsortAlgoritmos de ordenação - heapsort
Algoritmos de ordenação - heapsort
 
Análise de Algoritmos - Método Guloso
Análise de Algoritmos - Método GulosoAnálise de Algoritmos - Método Guloso
Análise de Algoritmos - Método Guloso
 
Functional programming
Functional programmingFunctional programming
Functional programming
 
PHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de DadosPHP Aula07 - conexão Com Banco de Dados
PHP Aula07 - conexão Com Banco de Dados
 
tmn - Introdução ao JavaScript
tmn - Introdução ao JavaScripttmn - Introdução ao JavaScript
tmn - Introdução ao JavaScript
 
N Queen Algorithm
N Queen AlgorithmN Queen Algorithm
N Queen Algorithm
 

Viewers also liked

Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Leonardo Borges
 
Functional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptFunctional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptLeonardo Borges
 
The mystique of erlang
The mystique of erlangThe mystique of erlang
The mystique of erlangCarob Cherub
 
Erlang Developments: The Good, The Bad and The Ugly
Erlang Developments: The Good, The Bad and The UglyErlang Developments: The Good, The Bad and The Ugly
Erlang Developments: The Good, The Bad and The Uglyenriquepazperez
 
Deep Learning and Text Mining
Deep Learning and Text MiningDeep Learning and Text Mining
Deep Learning and Text MiningWill Stanton
 
1 hour dive into Erlang/OTP
1 hour dive into Erlang/OTP1 hour dive into Erlang/OTP
1 hour dive into Erlang/OTPJordi Llonch
 
Crossing the Chasm - What's New, What's Not
Crossing the Chasm - What's New, What's NotCrossing the Chasm - What's New, What's Not
Crossing the Chasm - What's New, What's NotGeoffrey Moore
 
Lego Serious Play Introduction
Lego Serious Play IntroductionLego Serious Play Introduction
Lego Serious Play Introductionmartinsandberg
 
Programmation fonctionnelle avec f#
Programmation fonctionnelle avec f#Programmation fonctionnelle avec f#
Programmation fonctionnelle avec f#Ernst Perpignand
 
3 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 20173 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 2017Drift
 
How to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your NicheHow to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your NicheLeslie Samuel
 

Viewers also liked (13)

Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012Clojure Reducers / clj-syd Aug 2012
Clojure Reducers / clj-syd Aug 2012
 
Functional Reactive Programming in Clojurescript
Functional Reactive Programming in ClojurescriptFunctional Reactive Programming in Clojurescript
Functional Reactive Programming in Clojurescript
 
The mystique of erlang
The mystique of erlangThe mystique of erlang
The mystique of erlang
 
Erlang Developments: The Good, The Bad and The Ugly
Erlang Developments: The Good, The Bad and The UglyErlang Developments: The Good, The Bad and The Ugly
Erlang Developments: The Good, The Bad and The Ugly
 
Elixir basics
Elixir basicsElixir basics
Elixir basics
 
Deep Learning and Text Mining
Deep Learning and Text MiningDeep Learning and Text Mining
Deep Learning and Text Mining
 
1 hour dive into Erlang/OTP
1 hour dive into Erlang/OTP1 hour dive into Erlang/OTP
1 hour dive into Erlang/OTP
 
Crossing the Chasm - What's New, What's Not
Crossing the Chasm - What's New, What's NotCrossing the Chasm - What's New, What's Not
Crossing the Chasm - What's New, What's Not
 
Lego Serious Play Introduction
Lego Serious Play IntroductionLego Serious Play Introduction
Lego Serious Play Introduction
 
Coder F#nctionnel
Coder F#nctionnelCoder F#nctionnel
Coder F#nctionnel
 
Programmation fonctionnelle avec f#
Programmation fonctionnelle avec f#Programmation fonctionnelle avec f#
Programmation fonctionnelle avec f#
 
3 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 20173 Things Every Sales Team Needs to Be Thinking About in 2017
3 Things Every Sales Team Needs to Be Thinking About in 2017
 
How to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your NicheHow to Become a Thought Leader in Your Niche
How to Become a Thought Leader in Your Niche
 

Similar to Monads in Clojure

Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Philip Schwarz
 
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...Philip Schwarz
 
Monoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and CatsMonoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and CatsPhilip Schwarz
 
하스켈 프로그래밍 입문 4
하스켈 프로그래밍 입문 4하스켈 프로그래밍 입문 4
하스켈 프로그래밍 입문 4Kwang Yul Seo
 
Abstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generatorsAbstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generatorsPhilip Schwarz
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg MürkPlanet OS
 
Functional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedFunctional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedSusan Potter
 
Monad as things to do
Monad as things to doMonad as things to do
Monad as things to do悠滋 山本
 
Humble introduction to category theory in haskell
Humble introduction to category theory in haskellHumble introduction to category theory in haskell
Humble introduction to category theory in haskellJongsoo Lee
 
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...Philip Schwarz
 
C++ Advanced Features (TCF 2014)
C++ Advanced Features (TCF 2014)C++ Advanced Features (TCF 2014)
C++ Advanced Features (TCF 2014)Michael Redlich
 

Similar to Monads in Clojure (17)

Sequence and Traverse - Part 2
Sequence and Traverse - Part 2Sequence and Traverse - Part 2
Sequence and Traverse - Part 2
 
Practical cats
Practical catsPractical cats
Practical cats
 
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...
 
Monoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and CatsMonoids - Part 2 - with examples using Scalaz and Cats
Monoids - Part 2 - with examples using Scalaz and Cats
 
하스켈 프로그래밍 입문 4
하스켈 프로그래밍 입문 4하스켈 프로그래밍 입문 4
하스켈 프로그래밍 입문 4
 
MP in Clojure
MP in ClojureMP in Clojure
MP in Clojure
 
Why Haskell
Why HaskellWhy Haskell
Why Haskell
 
Abstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generatorsAbstracting over the Monad yielded by a for comprehension and its generators
Abstracting over the Monad yielded by a for comprehension and its generators
 
Advance Scala - Oleg Mürk
Advance Scala - Oleg MürkAdvance Scala - Oleg Mürk
Advance Scala - Oleg Mürk
 
09. haskell Context
09. haskell Context09. haskell Context
09. haskell Context
 
Functional Algebra: Monoids Applied
Functional Algebra: Monoids AppliedFunctional Algebra: Monoids Applied
Functional Algebra: Monoids Applied
 
Monad as things to do
Monad as things to doMonad as things to do
Monad as things to do
 
Humble introduction to category theory in haskell
Humble introduction to category theory in haskellHumble introduction to category theory in haskell
Humble introduction to category theory in haskell
 
08. haskell Functions
08. haskell Functions08. haskell Functions
08. haskell Functions
 
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
 
Fluent14
Fluent14Fluent14
Fluent14
 
C++ Advanced Features (TCF 2014)
C++ Advanced Features (TCF 2014)C++ Advanced Features (TCF 2014)
C++ Advanced Features (TCF 2014)
 

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
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library designLeonardo 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
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsLeonardo 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
 
Clojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsClojure/West 2013 in 30 mins
Clojure/West 2013 in 30 minsLeonardo 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
 
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
 
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
 
The algebra of library design
The algebra of library designThe algebra of library design
The algebra of library design
 
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
 
Functional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event SystemsFunctional Reactive Programming / Compositional Event Systems
Functional Reactive Programming / Compositional Event Systems
 
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
 
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
 
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
 
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
 
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

Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
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
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
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
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 

Recently uploaded (20)

Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
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
 
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort ServiceHot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
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?
 
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
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 

Monads in Clojure

  • 1. Monads in Clojure Or why burritos shouldn’t be scary [I] Leonardo Borges @leonardo_borges www.leonardoborges.com www.thoughtworks.com [I] http://blog.plover.com/prog/burritos.html Tuesday, 4 March 14
  • 2. Monads in Clojure The plan: Type Signatures in Haskell The Monad Type Class A few useful monads This presentation is a super condensed version of my blog post series on monads [II] [II] http://bit.ly/monads-part-i Tuesday, 4 March 14
  • 3. Prelude Type signatures in Haskell Tuesday, 4 March 14
  • 4. Type signatures in Haskell Vectors as maps import qualified Data.Map as Map -- just giving Data.Map an alias mkVec :: a -> a -> Map.Map [Char] a -- this is the type signature This is a function of two arguments of type a Tuesday, 4 March 14
  • 5. Type signatures in Haskell Vectors as maps import qualified Data.Map as Map -- just giving Data.Map an alias mkVec :: a -> a -> Map.Map [Char] a -- this is the type signature It returns a Map where keys are of type [Char] and values are of type a Tuesday, 4 March 14
  • 6. Type signatures in Haskell Vectors as maps import qualified Data.Map as Map -- just giving Data.Map an alias mkVec :: a -> a -> Map.Map [Char] a -- this is the type signature mkVec x y = Map.fromList [("x", x), ("y", y)] -- this is the implementation. You can ignore this part. -- using it myVec = mkVec 10 15 Map.lookup "x" myVec -- Just 10 Tuesday, 4 March 14
  • 7. Type signatures in Haskell Multiplication (*) :: Num a => a -> a -> a This is also a function of two arguments of type a Tuesday, 4 March 14
  • 8. Type signatures in Haskell Multiplication Num a is a type constraint (*) :: Num a => a -> a -> a In this case, the type constraint tells the compiler that (*)works on any value a as long as a is an instance of Num Tuesday, 4 March 14
  • 9. Monads what on earth are they? They’re simply an abstraction ...with a funny name to confuse people. Tuesday, 4 March 14
  • 10. Monads what on earth are they? They are not however.... ... a burrito ... an elephant ... a space suit ... or a writing desk. Tuesday, 4 March 14
  • 11. Monads what on earth are they? Every monad has an associated “context” It can be useful to think of them as “wrapping” some value Tuesday, 4 March 14
  • 12. The Monad Type Class class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b x >> y = x >>= _ -> y Let’s understand those type signatures! Tuesday, 4 March 14
  • 13. The Monad Type Class return :: a -> m a Single argument of type a Tuesday, 4 March 14
  • 14. The Monad Type Class return :: a -> m a returns a in a “context” m Tuesday, 4 March 14
  • 15. The Monad Type Class return :: a -> m a This is how we turn plain values into monadic values Tuesday, 4 March 14
  • 16. The Monad Type Class return :: a -> m a return is an unfortunate name as it is confusing. It has nothing to do with the return keywords in languages like Java. return is sometimes called unit Tuesday, 4 March 14
  • 17. The Monad Type Class (>>=) :: m a -> (a -> m b) -> m b >>= Tuesday, 4 March 14 is pronounced bind and takes two arguments
  • 18. The Monad Type Class (>>=) :: m a -> (a -> m b) -> m b A monad Tuesday, 4 March 14 m a
  • 19. The Monad Type Class (>>=) :: m a -> (a -> m b) -> m b and a function from values of type a to monads of type m Tuesday, 4 March 14 b
  • 20. The Monad Type Class (>>=) :: m a -> (a -> m b) -> m b Somehow each monad knows how to extract values from its context and “bind” them to the given function Tuesday, 4 March 14
  • 21. The Monad Type Class (>>=) :: m a -> (a -> m b) -> m b and it returns b in a “context” m Tuesday, 4 March 14
  • 22. The Monad Type Class (>>) :: m a -> m b -> m b x >> y = x >>= _ -> y You can work out the type signature all by yourself now :) Tuesday, 4 March 14
  • 23. The Monad Type Class (>>) :: m a -> m b -> m b x >> y = x >>= _ -> y >> is pronounced then and includes a default implementation in terms of bind Tuesday, 4 March 14 (>>=)
  • 24. The Monad Type Class (>>) :: m a -> m b -> m b x >> y = x >>= _ -> y Its second argument to bind is a function which ignores its argument Tuesday, 4 March 14
  • 25. The Monad Type Class (>>) :: m a -> m b -> m b x >> y = x >>= _ -> y It simply returns the value yielded by “unwrapping” the context of y Tuesday, 4 March 14
  • 26. Example I Calculating all combinations between elements of two lists using the list monad combinations :: [(Int,Int)] combinations = [1, 2, 3] >>= a -> [4, 5] >>= b -> return (a,b) -- [(1,4),(1,5),(2,4),(2,5),(3,4),(3,5)] Tuesday, 4 March 14
  • 27. Example I Calculating all combinations between elements of two lists using the list monad meh. It’s damn hard to read. And we don’t want to type that much. There’s a better way Tuesday, 4 March 14
  • 28. Example I Calculating all combinations between elements of two lists using the list monad (using do notation) combinations' :: [(Int,Int)] combinations' = do a <- [1, 2, 3] b <- [4, 5] return (a,b) -- [(1,4),(1,5),(2,4),(2,5),(3,4),(3,5)] Tuesday, 4 March 14
  • 29. You’ve just seen your first monad, the list monad! Tuesday, 4 March 14
  • 30. The Monad Type Class * As if it worked for lists only class Monad [] where return :: a -> [a] (>>=) :: [a] -> (a -> [b]) -> [b] (>>) :: [a] -> [b] -> [b] * this isn’t valid Haskell. It’s just to illustrate the concept Tuesday, 4 March 14
  • 31. Now let’s learn how it does its thing... ...in Clojure! Tuesday, 4 March 14
  • 32. The List Monad Let’s do it together (def list-m { :return (fn [v] ... :bind (fn [mv f] ... }) Tuesday, 4 March 14 ) )
  • 33. The List Monad Let’s do it together (def list-m { :return (fn [v] (list v)) :bind (fn [mv f] ... ) }) Tuesday, 4 March 14
  • 34. The List Monad Let’s do it together (def list-m { :return (fn [v] (list v)) :bind (fn [mv f] (mapcat f mv)) }) Tuesday, 4 March 14
  • 35. The List Monad Now we’re ready to use it (defn combinations [] (let [bind (:bind list-m) return (:return list-m)] (bind [1 2 3] (fn [a] (bind [4 5] (fn [b] (return [a b]))))))) ;; ([1 4] [1 5] [2 4] [2 5] [3 4] [3 5]) Tuesday, 4 March 14
  • 36. The List Monad Now we’re ready to use it ugh. Just as ugly. But we know there’s a better way. Can we use the do notation in Clojure? Tuesday, 4 March 14
  • 37. Macros to the rescue Haskell’s do notation in Clojure (defn m-steps [m [name val & bindings] body] (if (seq bindings) `(-> ~val ((:bind ~m) (fn [~name] ~(m-steps m bindings body)))) `(-> ~val ((:bind ~m) (fn [~name] ((:return ~m) ~body)))))) (defmacro do-m [m bindings body] (m-steps m bindings body)) Tuesday, 4 March 14
  • 38. Macros to the rescue Haskell’s do notation in Clojure Ignore the implementation. You can study it later :) Tuesday, 4 March 14
  • 39. The List Monad Now we’re ready to use it (defn combinations [] (do-m list-m [a [1 2 3] b [4 5]] [a b])) ;; ([1 4] [1 5] [2 4] [2 5] [3 4] [3 5]) Tuesday, 4 March 14
  • 40. Familiar? List comprehension (defn combinations [] (for [a [1 2 3] b [4 5]] [a b])) ;; ([1 4] [1 5] [2 4] [2 5] [3 4] [3 5]) Tuesday, 4 March 14
  • 41. Example II Adding two numbers (defn add [a b] (+ a b)) (add 1 2) ;; 3 (add 1 nil) ;; NullPointerException Tuesday, 4 March 14
  • 42. Example II [Maybe]Adding two numbers (defn m-add [ma mb] (do-m maybe-m [a ma b mb] (+ a b))) (m-add 1 2) ;; 3 (m-add nil 1) ;; nil Tuesday, 4 March 14
  • 43. The Maybe Monad Again, everyone together (def maybe-m { :return (fn [v] ...) :bind (fn [mv f] ... ) }) Tuesday, 4 March 14
  • 44. The Maybe Monad Again, everyone together (def maybe-m { :return (fn [v] v) :bind (fn [mv f] ... ) }) Tuesday, 4 March 14
  • 45. The Maybe Monad Again, everyone together (def maybe-m { :return (fn [v] v) :bind (fn [mv f] (when mv (f mv))) }) Tuesday, 4 March 14
  • 46. Not too bad, huh? Ready for more? Tuesday, 4 March 14
  • 47. Example III Application configuration (defn connect-to-db [env] (let [db-uri (:db-uri env)] (prn (format "Connected to db at %s" db-uri)))) (defn connect-to-api [env] (let [api-key (:api-key env) env (ask)] (prn (format "Connected to api with key %s" api-key)))) Tuesday, 4 March 14
  • 48. Example III Application configuration (defn run-app [env] (do (connect-to-db env) (connect-to-api env) "Done.")) (run-app {:db-uri "user:passwd@host/dbname" :api-key "AF167"}) ;; "Connected to db at user:passwd@host/dbname" ;; "Connected to api with key AF167" ;; "Done." Tuesday, 4 March 14
  • 49. Example III Application configuration Passing env on to every single function that depends on it can be cumbersome. Obviously we don’t want to resort to global vars. Can monads help? Tuesday, 4 March 14
  • 50. Example III Application configuration with the Reader Monad (defn connect-to-db [] (do-m reader-m [db-uri (asks :db-uri)] (prn (format "Connected to db at %s" db-uri)))) (defn connect-to-api [] (do-m reader-m [api-key (asks :api-key) env (ask)] (prn (format "Connected to api with key %s" api-key)))) Bear with me for now. These will be explained soon. Tuesday, 4 March 14
  • 51. Example III Application configuration with the Reader Monad (defn run-app [] (do-m reader-m [_ (m-connect-to-db) _ (m-connect-to-api)] (prn "Done."))) Note the env parameter disappeared. The Reader monad somehow feeds that into our functions. ((run-app) {:db-uri "user:passwd@host/dbname" :api-key "AF167"}) ;; "Connected to db at user:passwd@host/dbname" ;; "Connected to api with key AF167" ;; "Done." Also this is now a function call as run-app is now pure Tuesday, 4 March 14
  • 52. Example III Application configuration with the Reader Monad But, how how does it work?! Tuesday, 4 March 14
  • 53. The Reader Monad Tricky one, but not that tricky (defn ask [] identity) (defn asks [f] (fn [env] (f env))) The function names come from Haskell. They are defined in the MonadReader type class. Tuesday, 4 March 14
  • 54. The Reader Monad Tricky one, but not that tricky (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) There’s a lot going on in bind. Let’s unravel it. Tuesday, 4 March 14
  • 55. The Reader Monad Expanding connect-to-db This: (defn connect-to-db [] (do-m reader-m [db-uri (asks :db-uri)] (prn (format "Connected to db at %s" db-uri)))) Expands into: ((:bind reader-m) (asks :db-uri) (fn* ([db-uri] ((:return reader-m) (prn "Connected to db at " db-uri))))) Tuesday, 4 March 14
  • 56. The Reader Monad Expanding connect-to-db (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) (let [m (fn [env] (:db-uri env)) k (fn* ([db-uri] ((:return reader-m) (prn "Connected to db at " db-uri))))] ((fn [r] ((k (m r)) r)) {:db-uri "user:passwd@host/dbname" :api-key "AF167"})) Tuesday, 4 March 14
  • 57. The Reader Monad Expanding connect-to-db (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) (let [m (fn [env] (:db-uri env)) k (fn* ([db-uri] ((:return reader-m) (prn "Connected to db at " db-uri))))] (let [r {:db-uri "user:passwd@host/dbname" :api-key "AF167"}] ((k (m r)) r))) Tuesday, 4 March 14
  • 58. The Reader Monad Expanding connect-to-db (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) (let [m (fn [env] (:db-uri env)) k (fn* ([db-uri] ((:return reader-m) (prn "Connected to db at " db-uri))))] (let [r {:db-uri "user:passwd@host/dbname" :api-key "AF167"}] ((k "user:passwd@host/dbname") r))) Tuesday, 4 March 14
  • 59. The Reader Monad Expanding connect-to-db (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) (let [m (fn [env] (:db-uri env)) k (fn* ([db-uri] ((:return reader-m) nil)))] (let [r {:db-uri "user:passwd@host/dbname" :api-key "AF167"}] ((k "user:passwd@host/dbname") r))) Tuesday, 4 March 14
  • 60. The Reader Monad Expanding connect-to-db (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) (let [m (fn [env] (:db-uri env)) k (fn* ([db-uri] ((fn [a] (fn [_] a) nil)))] (let [r {:db-uri "user:passwd@host/dbname" :api-key "AF167"}] ((k "user:passwd@host/dbname") r))) Tuesday, 4 March 14
  • 61. The Reader Monad Expanding connect-to-db (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) (let [m (fn [env] (:db-uri env)) k (fn* ([db-uri] ((fn [a] (fn [_] a) nil)))] (let [r {:db-uri "user:passwd@host/dbname" :api-key "AF167"}] ((fn [_] nil) r))) Tuesday, 4 March 14
  • 62. The Reader Monad Expanding connect-to-db (def reader-m {:return (fn [a] (fn [_] a)) :bind (fn [m k] (fn [r] ((k (m r)) r)))}) (let [m (fn [env] (:db-uri env)) k (fn* ([db-uri] ((fn [a] (fn [_] a) nil)))] (let [r {:db-uri "user:passwd@host/dbname" :api-key "AF167"}] nil)) Tuesday, 4 March 14
  • 63. The Reader Monad Simple, right? :) Tuesday, 4 March 14
  • 64. Example IV Dependency Injection (require '[app.repository :as repository]) (defn clone! [id user] (let [old-user (repository/fetch-by-id id {}) cloned-user (repository/create! (compute-clone old-user) user) updated-user (assoc old-user :clone-id (:id cloned-user))] (repository/update! old-user updated-user user))) See the problem? Tuesday, 4 March 14
  • 65. Example IV Dependency Injection: the problem • clone! is tightly coupled to the repository namespace • It can’t be tested in isolation without resorting to heavy mocking of the involved functions • It’s limited to a single repository implementation - makes experimenting at the REPL harder • ... Basically, good software engineering principles apply Tuesday, 4 March 14
  • 66. Example IV Dependency Injection using the Reader Monad Let’s start by turning our repository into a module that can be injected into our function Tuesday, 4 March 14
  • 67. Example IV Dependency Injection using the Reader Monad There’s a couple of ways in which we can do that I’ll use protocols as they have added performance benefits Tuesday, 4 March 14
  • 68. Example IV Dependency Injection using the Reader Monad (defprotocol UserRepository (fetch-by-id! [this id]) (create! [this user username]) (update! [this old-user new-user username])) (defn mk-user-repo [] (reify UserRepository (fetch-by-id! [this id] (prn "Fetched user id " id)) (create! [this user username] (prn "Create user triggered by " username)) (update! [this old-user new-user username] (prn "Updated user triggered by " username)))) Tuesday, 4 March 14
  • 69. Example IV Dependency Injection using the Reader Monad Remember: One of the advantages of the reader monad is not having to pass parameters around to every single function that needs it Tuesday, 4 March 14
  • 70. Example IV Dependency Injection using the Reader Monad With that in mind, let’s rewrite clone! Tuesday, 4 March 14
  • 71. Example IV Dependency Injection using the Reader Monad It can be helpful to think of clone as having this type signature: ;; clone! :: Number -> String -> Reader UserRepository Number (defn clone! [id user] (do-m reader-m [repo (ask)] (let [old-user (fetch-by-id! repo id) cloned-user (create! repo (compute-clone old-user) user) updated-user (assoc old-user :clone-id (:id cloned-user))] (update! repo old-user updated-user user)))) Tuesday, 4 March 14
  • 72. Example IV Dependency Injection using the Reader Monad And this is how we might use it: (defn run-clone [] (do-m reader-m [_ (clone! 10 "leo")] (prn "Cloned."))) ((run-clone) (mk-user-repo)) ;; ;; ;; ;; ;; Tuesday, 4 March 14 "Fetched user id " 10 "Compute clone for user" "Create user triggered by " "leo" "Updated user triggered by " "leo" "Cloned."
  • 73. The Reader Monad A few observations from a clojure perspective • Useful abstraction for computations that read values from a shared environment • As we saw, it has multiple use cases such as configuration and dependency injection • I’ve cheated in the examples: • Each function using the reader monad also performed IO - via prn • In Haskell, IO is a monad so we would need to use monad transformers to compose them - beyond the scope of this presentation Tuesday, 4 March 14
  • 74. Monads: Summary • Lots of useful abstractions through a common interface • Some monads, such as Maybe and Either, are a lot more powerful in a statically typed language like Haskell or Scala due to its usage being encoded in the type system, as well as native support to pattern matching • Others, such as the Reader monad, can be very useful in a dynamic setting - though you don’t have the type system to tell you when you stuff up at compile time • In such cases, type annotations in comments can be useful Tuesday, 4 March 14