---
title: MP in Clojure
tags:  #clojure #関数型プログラミング #monad  
author: [Kent OHASHI](https://convert.docswell.com/user/lagenorhynque)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/KE46X6GVJ1.jpg?width=480
description: Why not try MP (monadic programming) in Clojure?
published: June 17, 17
canonical: https://convert.docswell.com/s/lagenorhynque/KP9271-mp-in-clojure
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/KE46X6GVJ1.jpg)

MP in Clojure
~ herding cats with clj ~


# Page. 2

![Page Image](https://bcdn.docswell.com/page/L71VNVD4JG.jpg)

Self-introduction
lagénorhynque /laʒenɔʁɛ k
̃ / カマイルカ
(defprofile lagénorhynque
:name
&quot;Kent OHASHI&quot;
:languages
[Clojure Haskell Python Scala
English français Deutsch русский]
:interests
[programming language-learning mathematics]
:contributing [github.com/japan-clojurians/clojure-site-ja])


# Page. 3

![Page Image](https://bcdn.docswell.com/page/G7WL4LYZJ2.jpg)

Clojure × MP


# Page. 4

![Page Image](https://bcdn.docswell.com/page/4JZM2MXL73.jpg)

Contents
1. What is MP?
2. Why MP in Clojure?
3. How MP in Clojure?
4. Examples


# Page. 5

![Page Image](https://bcdn.docswell.com/page/YE6NVN4MEV.jpg)

What is MP?


# Page. 6

![Page Image](https://bcdn.docswell.com/page/GE55D5QQE4.jpg)

MP = monadic programming
programming with monads
cf. FP = functional programming


# Page. 7

![Page Image](https://bcdn.docswell.com/page/972N8NPWJR.jpg)

de nition of Monad in Haskell
GHC.Base#Monad
class Applicative m =&gt; Monad m where
(&gt;&gt;=)
:: forall a b. m a -&gt; (a -&gt; m b) -&gt; m b
(&gt;&gt;)
:: forall a b. m a -&gt; m b -&gt; m b
m &gt;&gt; k = m &gt;&gt;= \_ -&gt; k
{-# INLINE (&gt;&gt;) #-}
return
return
:: a -&gt; m a
= pure
fail
fail s
:: String -&gt; m a
= errorWithoutStackTrace s


# Page. 8

![Page Image](https://bcdn.docswell.com/page/DJYP6P59JM.jpg)

monads in Haskell
型クラス Monad のインスタンス
&gt;&gt;= : m a -&gt; (a -&gt; m b) -&gt; m b
return : a -&gt; m a
モナド則(monad laws)を満たす
シンプルで合成可能な構造 → 様々な形で利⽤可能
do 記法というシンタックスシュガー


# Page. 9

![Page Image](https://bcdn.docswell.com/page/V7N5Z5NDE8.jpg)

e.g. java.util.Optional
jshell&gt; Optional&lt;Integer&gt; a = Optional.of(2)
a ==&gt; Optional[2]
jshell&gt; Optional&lt;Integer&gt; b = Optional.of(3)
b ==&gt; Optional[3]
jshell&gt; a.flatMap( x -&gt;
...&gt;
b.map( y -&gt;
...&gt;
x * y
...&gt;
)
...&gt; )
$3 ==&gt; Optional[6]
// with `flatMap` &amp; `map`
※ #渋⾕ java なので⼀応 Java の例から^_^;


# Page. 10

![Page Image](https://bcdn.docswell.com/page/YJ9YZYR873.jpg)

e.g. scala.Option
scala&gt; val a = Some(2)
a: Some[Int] = Some(2)
scala&gt; val b = Some(3)
b: Some[Int] = Some(3)
scala&gt; a.flatMap { x =&gt;
|
b.map { y =&gt;
|
x * y
|
}
| }
res0: Option[Int] = Some(6)
scala&gt; for {
|
x &lt;- a
|
y &lt;- b
| } yield x * y
res1: Option[Int] = Some(6)
// with `flatMap` &amp; `map`
// with `for` expression


# Page. 11

![Page Image](https://bcdn.docswell.com/page/GJ8616WZED.jpg)

e.g. Prelude.Maybe
&gt; a = Just 2
&gt; b = Just 3
&gt; :{
| a &gt;&gt;= \x -&gt;
|
b &gt;&gt;= \y -&gt;
|
return $ x * y
| :}
Just 6
&gt; :{
| do
|
x &lt;- a
|
y &lt;- b
|
return $ x * y
| :}
Just 6
-- with `&gt;&gt;=` &amp; `return`
-- with `do` notation


# Page. 12

![Page Image](https://bcdn.docswell.com/page/LJL9Q9N17R.jpg)

e.g. cats.monad.maybe
user=&gt; (require &#039;[cats.core :as m]
#_=&gt;
&#039;[cats.monad.maybe :as maybe])
nil
user=&gt; (def a (maybe/just 2))
#&#039;user/a
user=&gt; (def b (maybe/just 3))
#&#039;user/b
user=&gt; (m/&gt;&gt;= a (fn [x]
; with `&gt;&gt;=` &amp; `return`
#_=&gt;
(m/&gt;&gt;= b (fn [y]
#_=&gt;
(m/return (* x y))))))
#&lt;Just 6&gt;
user=&gt; (m/mlet [x a
; with `mlet` macro
#_=&gt;
y b]
#_=&gt;
(m/return (* x y)))
#&lt;Just 6&gt;


# Page. 13

![Page Image](https://bcdn.docswell.com/page/47MZ1ZX5JW.jpg)

Why MP in Clojure?


# Page. 14

![Page Image](https://bcdn.docswell.com/page/P7R6L6NZE9.jpg)

MP in Clojure
Clojureでは
モナドは必須の機能ではないが……
静的型付け&amp;純粋関数型の⾔語ではないが……
シンプルで汎⽤的なDSL構築フレームワーク
Haskellなどで有⽤なアイディアが活かせる
⇒ Clojureでも MP してみよう (*&gt; ᴗ •*)ゞ


# Page. 15

![Page Image](https://bcdn.docswell.com/page/PJXMWMN1EX.jpg)

How MP in Clojure?


# Page. 16

![Page Image](https://bcdn.docswell.com/page/3JKGVGNM7D.jpg)

MP libraries in Clojure
clojure/algo.monads
Macros for defining monads, and
definition of the most common
monads
funcool/cats
Category Theory and Algebraic
abstractions for Clojure and
ClojureScript.


# Page. 17

![Page Image](https://bcdn.docswell.com/page/LE3NMNV2E5.jpg)

how to support MP in Clojure
feature
algo.monads
cats
Monad type class
plain Map data
protocol
do notation
macro
macro
context inference
(n/a)
protocol


# Page. 18

![Page Image](https://bcdn.docswell.com/page/8EDW6W867G.jpg)

anatomy of algo.monads
user=&gt; (require &#039;[clojure.algo.monads :as m])
nil
user=&gt; (m/domonad m/maybe-m
#_=&gt;
[x 2
#_=&gt;
y 3]
#_=&gt;
(* x y))
6


# Page. 19

![Page Image](https://bcdn.docswell.com/page/V7P9Y9WZJ8.jpg)

macroexpand-1
user=&gt; (macroexpand-1
#_=&gt; &#039;(m/domonad m/maybe-m
#_=&gt;
[x 2
#_=&gt;
y 3]
#_=&gt;
(* x y)))
(clojure.algo.monads/with-monad m/maybe-m
(m-bind 2 (fn [x]
(m-bind 3 (fn [y]
(m-result (* x y)))))))
clojure.algo.monads/with-monad ?


# Page. 20

![Page Image](https://bcdn.docswell.com/page/2JVMGM8MJQ.jpg)

macroexpand-1 once more
user=&gt; (macroexpand-1 *1)
(clojure.core/let [name__3075__auto__ m/maybe-m
m-bind (:m-bind name__3075__auto__)
m-result (:m-result name__3075__auto__)
m-zero (:m-zero name__3075__auto__)
m-plus (:m-plus name__3075__auto__)]
(clojure.tools.macro/with-symbol-macros
(m-bind 2 (fn [x]
(m-bind 3 (fn [y]
(m-result (* x y))))))))
clojure.algo.monads/maybe-m ?


# Page. 21

![Page Image](https://bcdn.docswell.com/page/5EGG8G5XEL.jpg)

clojure.algo.monads/maybe-m
user=&gt; clojure.algo.monads/maybe-m
{:m-zero nil,
:m-plus #object[clojure.algo.monads$fn__3167$m_plus_maybe__3172 0x77a7
:m-result #object[clojure.algo.monads$fn__3167$m_result_maybe__3168 0x
:m-bind #object[clojure.algo.monads$fn__3167$m_bind_maybe__3170 0x142d
user=&gt; (class clojure.algo.monads/maybe-m)
clojure.lang.PersistentArrayMap
just a keyword-function Map


# Page. 22

![Page Image](https://bcdn.docswell.com/page/4JQX9XZ5EP.jpg)

strategy in algo.monads
1. :m-bind, :m-result をkey、対応する関数を
valueとしたMapを⽤意
2. マクロによってMapから取り出した関数 m-bind,
m-result の組み合わせに変換


# Page. 23

![Page Image](https://bcdn.docswell.com/page/K746X63VE1.jpg)

anatomy of cats
user=&gt; (require &#039;[cats.core :as m]
#_=&gt;
&#039;[cats.monad.maybe :as maybe])
nil
user=&gt; (m/mlet [x (maybe/just 2)
#_=&gt;
y (maybe/just 3)]
#_=&gt;
(m/return (* x y)))
#&lt;Just 6&gt;


# Page. 24

![Page Image](https://bcdn.docswell.com/page/LJ1VNV14EG.jpg)

macroexpand-1
user=&gt; (macroexpand-1
#_=&gt; &#039;(m/mlet [x (maybe/just 2)
#_=&gt;
y (maybe/just 3)]
#_=&gt;
(m/return (* x y))))
(cats.core/bind (maybe/just 2) (clojure.core/fn [x]
(cats.core/bind (maybe/just 3) (clojure.core/fn [y]
(do (m/return (* x y)))))))
cats.core/bind ?
without explicit monad context?


# Page. 25

![Page Image](https://bcdn.docswell.com/page/GJWL4L8ZE2.jpg)

cats.core/bind
user=&gt; (source cats.core/bind)
(defn bind
;; (docstring here)
[mv f]
(let [ctx (ctx/infer mv)]
(p/-mbind ctx mv (fn [v]
(ctx/with-context ctx
(f v))))))
nil
cats.context/infer ?
can infer monad context?


# Page. 26

![Page Image](https://bcdn.docswell.com/page/4EZM2M8LJ3.jpg)

cats.context/infer
user=&gt; (source cats.context/infer)
(defn infer
;; (docstring here)
;; (0-arity pattern here)
([v]
(cond
; blank lines omitted
(not (nil? *context*))
*context*
(satisfies? p/Contextual v)
(p/-get-context v)
:else
(throw-illegal-argument
(str &quot;No context is set and it can not be automatically &quot;
&quot;resolved from provided value&quot;)))))
nil
cats.protocols/Contextual ?


# Page. 27

![Page Image](https://bcdn.docswell.com/page/Y76NVNPM7V.jpg)

cats.protocols/Contextual
user=&gt; (source cats.protocols/Contextual)
(defprotocol Contextual
&quot;Abstraction that establishes a concrete type as a member of a contex
A great example is the Maybe monad type Just. It implements
this abstraction to establish that Just is part of
the Maybe monad.&quot;
(-get-context [_] &quot;Get the context associated with the type.&quot;))
nil
-get-context method


# Page. 28

![Page Image](https://bcdn.docswell.com/page/G755D5KQ74.jpg)

cats.core/bind (again)
user=&gt; (source cats.core/bind)
(defn bind
;; (docstring here)
[mv f]
(let [ctx (ctx/infer mv)]
(p/-mbind ctx mv (fn [v]
(ctx/with-context ctx
(f v))))))
nil
cats.protocols/-mbind ?


# Page. 29

![Page Image](https://bcdn.docswell.com/page/9J2N8NWWER.jpg)

cats.protocols/Monad
user=&gt; (source cats.protocols/Monad))
(defprotocol Monad
&quot;The Monad abstraction.&quot;
(-mreturn [m v])
(-mbind [m mv f]))
nil
-mreturn &amp; -mbind methods


# Page. 30

![Page Image](https://bcdn.docswell.com/page/DEYP6PL9EM.jpg)

cats.core/bind ( nally)
user=&gt; (source cats.core/bind)
(defn bind
;; (docstring here)
[mv f]
(let [ctx (ctx/infer mv)]
(p/-mbind ctx mv (fn [v]
(ctx/with-context ctx
(f v))))))
nil
cats.context/with-context ?


# Page. 31

![Page Image](https://bcdn.docswell.com/page/VJN5Z54D78.jpg)

cats.context/with-context
user=&gt; (source cats.context/with-context)
(defmacro with-context
&quot;Set current context to specific monad.&quot;
[ctx &amp; body]
`(do
(when-not (context? ~ctx)
(throw-illegal-argument
&quot;The provided context does not implements Context.&quot;))
(binding [*context* ~ctx]
~@body)))
nil
user=&gt; (source cats.context/*context*)
(def ^:dynamic *context* nil)
nil
dynamic Var *context*


# Page. 32

![Page Image](https://bcdn.docswell.com/page/YE9YZYQ8J3.jpg)

strategy in cats
1. Monad プロトコル(-mreturn, -mbind)を実装した
コンテキストオブジェクトを⽤意
2. Monad 値は Contextual プロトコルによってコン
テキストオブジェクトを取り出せる
3. マクロで関数 bind, return の組み合わせに変換
4. bind は第1引数の Monad 値からコンテキストオブ
ジェクトを取り出す(コンテキストの推論)
5. with-context で⼀度推論したコンテキストオブ
ジェクトを動的スコープで再利⽤


# Page. 33

![Page Image](https://bcdn.docswell.com/page/GE8616GZ7D.jpg)

Examples


# Page. 34

![Page Image](https://bcdn.docswell.com/page/LEL9Q9G1JR.jpg)

example code repositories
lagenorhynque/mp-in-clojure
cf. lagenorhynque/mp-in-haskell


# Page. 35

![Page Image](https://bcdn.docswell.com/page/4JMZ1ZQ5EW.jpg)

using monads:
safe RPN calculator
from Learn You a Haskell for Great Good!
10.1 Reverse Polish Notation Calculator
14.6 Making a Safe RPN Calculator


# Page. 36

![Page Image](https://bcdn.docswell.com/page/PJR6L68Z79.jpg)

RPN: reverse Polish notation
861-*2+
↓ with parentheses
((8 (6 1 -) *) 2 +)
↓ evaluate
42


# Page. 37

![Page Image](https://bcdn.docswell.com/page/PEXMWM817X.jpg)

without monads
(defn- folding-function [[x y &amp; ys :as xs] s]
(cond
(and x y (= s &quot;*&quot;)) (conj ys (* y x))
(and x y (= s &quot;+&quot;)) (conj ys (+ y x))
(and x y (= s &quot;-&quot;)) (conj ys (- y x))
:else (conj xs (Double/parseDouble s))))
(defn solve-rpn [s]
(as-&gt; s v
(str/split v #&quot;\s+&quot;)
(reduce folding-function () v)
(first v)))
naïve implementation


# Page. 38

![Page Image](https://bcdn.docswell.com/page/3EKGVGKMJD.jpg)

;; valid RPN
user=&gt; (solve-rpn &quot;8 6 1 - * 2 +&quot;)
42.0
;; unsupported operator
user=&gt; (solve-rpn &quot;8 6 1 - * 2 /&quot;)
NumberFormatException For input string: &quot;/&quot;
;; invalid number
user=&gt; (solve-rpn &quot;8 6 1 - * a +&quot;)
sun.misc.FloatingDecimal.r
NumberFormatException For input string: &quot;a&quot;
;; invalid RPN
user=&gt; (solve-rpn &quot;8 6 1 - * 2&quot;)
2.0
sun.misc.FloatingDecimal.r


# Page. 39

![Page Image](https://bcdn.docswell.com/page/L73NMNZ275.jpg)

with Maybe monad
(defn- read-maybe [s]
(try
(maybe/just (Double/parseDouble s))
(catch NumberFormatException _
(maybe/nothing))))
(defn- folding-function&#039; [[x y &amp; ys :as xs] s]
(cond
(and x y (= s &quot;*&quot;)) (maybe/just (conj ys (* y x)))
(and x y (= s &quot;+&quot;)) (maybe/just (conj ys (+ y x)))
(and x y (= s &quot;-&quot;)) (maybe/just (conj ys (- y x)))
:else ((m/lift-m 1 #(conj xs %))
(read-maybe s))))
valid ⇒ just x ; invalid ⇒ nothing
lift-m for lifting conj function


# Page. 40

![Page Image](https://bcdn.docswell.com/page/87DW6WR6JG.jpg)

(defn solve-rpn&#039; [s]
(m/mlet [result (m/foldm folding-function&#039;
()
(str/split s #&quot;\s+&quot;))
:when (= (count result) 1)]
(m/return (first result))))
reduce with monadic function using foldm
length of result sequence ≠ 1 ⇒ nothing
MonadZero
cf. MonadPlus, Alternative


# Page. 41

![Page Image](https://bcdn.docswell.com/page/VJP9Y9MZE8.jpg)

;; valid RPN
user=&gt; (solve-rpn&#039; &quot;8 6
#&lt;Just 42.0&gt;
;; unsupported operator
user=&gt; (solve-rpn&#039; &quot;8 6
#&lt;Nothing&gt;
;; invalid number
user=&gt; (solve-rpn&#039; &quot;8 6
#&lt;Nothing&gt;
;; invalid RPN
user=&gt; (solve-rpn&#039; &quot;8 6
#&lt;Nothing&gt;
1 - * 2 +&quot;)
1 - * 2 /&quot;)
1 - * a +&quot;)
1 - * 2&quot;)


# Page. 42

![Page Image](https://bcdn.docswell.com/page/2EVMGM9MEQ.jpg)

making monads:
probability distribution
from Learn You a Haskell for Great Good!
14.8 Making Monads


# Page. 43

![Page Image](https://bcdn.docswell.com/page/57GG8GZX7L.jpg)

probability distribution
e.g. 6-sided die
n
p
1
1/6
2
1/6
3
1/6
4
1/6
5
1/6
6
1/6


# Page. 44

![Page Image](https://bcdn.docswell.com/page/4EQX9XL57P.jpg)

implementing Prob monad
(deftype Prob [v]
p/Contextual
(-get-context [_] context)
p/Extract
(-extract [_] v)
p/Printable
(-repr [_]
(str &quot;#&lt;Prob &quot; (pr-str v) &quot;&gt;&quot;))
Object
(equals [this obj]
(= (.v this) (.v obj))))
define the data type Prob


# Page. 45

![Page Image](https://bcdn.docswell.com/page/KJ46X6DV71.jpg)

(def context
(reify
;; (other protocol implementations here)
p/Monad
(-mreturn [m v]
(p/-pure m v))
(-mbind [_ mv f]
(assert (prob? mv)
(str &quot;Context mismatch: &quot; (p/-repr mv)
&quot; is not allowed to use with prob context.&quot;))
(-&gt;Prob (for [[x p] (p/-extract mv)
[y q] (p/-extract (f x))]
[y (* p q)])))
;; (below omitted)
define the context object for Prob


# Page. 46

![Page Image](https://bcdn.docswell.com/page/LE1VNVZ47G.jpg)

(defn uniform [s]
; sequence
(let [n (count s)] ;
-&gt; Prob value of uniform distribution
(-&gt;&gt; s
(map (fn [x] [x (/ 1 n)]))
-&gt;Prob)))
(defn prob-&gt;dist [prob] ; Prob value -&gt; Map of distribution
(letfn [(add-prob [d [x p]]
(update d x (fnil #(+ % p) 0)))]
(reduce add-prob {} (p/-extract prob))))
define factory/conversion functions


# Page. 47

![Page Image](https://bcdn.docswell.com/page/GEWL4L9Z72.jpg)

sum of 2 dice
user=&gt; (def die (range 1 (inc 6)))
#&#039;user/die
user=&gt; (def prob
#_=&gt;
(m/mlet [d1 (uniform die)
#_=&gt;
d2 (uniform die)]
#_=&gt;
(m/return (+ d1 d2))))
#&#039;user/prob
user=&gt; prob
#&lt;Prob ([2 1/36] [3 1/36] [4 1/36] [5 1/36] [6 1/36] [7 1/36] [3 1/36]
user=&gt; (prob-&gt;dist prob)
{7 1/6, 4 1/12, 6 5/36, 3 1/18, 12 1/36, 2 1/36, 11 1/18,
9 1/9, 5 1/9, 10 1/12, 8 5/36}


# Page. 48

![Page Image](https://bcdn.docswell.com/page/47ZM2M9LE3.jpg)

Monty Hall problem
user=&gt; (def doors #{:a :b :c})
#&#039;user/doors
user=&gt; (prob-&gt;dist
#_=&gt; (m/mlet [prize (uniform doors)
#_=&gt;
choice (uniform doors)]
#_=&gt;
(m/return (if (= choice prize)
#_=&gt;
:win
#_=&gt;
:lose))))
{:win 1/3, :lose 2/3}


# Page. 49

![Page Image](https://bcdn.docswell.com/page/YJ6NVNKMJV.jpg)

user=&gt; (prob-&gt;dist
#_=&gt; (m/mlet [prize (uniform doors)
#_=&gt;
choice (uniform doors)
#_=&gt;
opened (uniform (disj doors prize choice))
#_=&gt;
choice&#039; (uniform (disj doors opened choice))]
#_=&gt;
(m/return (if (= choice&#039; prize)
#_=&gt;
:win
#_=&gt;
:lose))))
{:lose 1/3, :win 2/3}


# Page. 50

![Page Image](https://bcdn.docswell.com/page/GJ55D5PQJ4.jpg)

Vive les S-expressions !
Long live S-expressions!


# Page. 51

![Page Image](https://bcdn.docswell.com/page/LE3NMN3ZE5.jpg)

Further Reading
clojure/algo.monads
khinsen/monads-in-clojure
funcool/cats
独習 Scalaz / learning Scalaz
猫番 / herding cats
モナド (プログラミング) - Wikipedia


# Page. 52

![Page Image](https://bcdn.docswell.com/page/8EDW6W447G.jpg)

『すごいHaskellたのしく学ぼう！』/ Learn You a
Haskell for Great Good!
第14章 もうちょっとだけモナド / For a Few
Monads More
10.1 逆ポーランド記法電卓 / Reverse Polish
Notation Calculator
14.6 安全な逆ポーランド記法電卓を作ろう /
Making a Safe RPN Calculator
14.8 モナドを作る / Making Monads


# Page. 53

![Page Image](https://bcdn.docswell.com/page/V7P9Y9MVJ8.jpg)

Haskell の Monad とは⾔語内DSLのフレームワー
クである
Functor, Applicative, Monadのシンプルな定式化
継承によらないポリモーフィズム実現⼿法
思ったほど怖くない！ Haskell on JVM 超⼊⾨
MP in Scala
cf. MP in Haskell
Free Monads Getting Started


