SlideShare a Scribd company logo
Addendum	to	‘Monads	do	not	Compose’	
a temporary addendum to Part 1 of ‘Monads do not Compose’
illustrating an issue raised by Sergei Winitzki
@philip_schwarz
https://www.slideshare.net/pjschwarz/monads-do-not-compose
It is a mistake to think that a traversable monad can be composed with another monad.
It is true that, given `Traversable`, you can implement the monad's methods (pure and flatMap) for the composition with another
monad (as in your slides 21 to 26), but this is a deceptive appearance.
The laws of the `Traversable` typeclass are far insufficient to guarantee the laws of the resulting composed monad. The only
traversable monads that work correctly are Option, Either, and Writer.
It is true that you can implement the type signature of the `swap` function for any `Traversable` monad. However, the `swap` function
for monads needs to satisfy very different and stronger laws than the `sequence` function from the `Traversable` type class.
I'll have to look at the "Book of Monads"; but, if my memory serves, the FPiS book does not derive any of these laws.Sergei	Winitzki
sergei-winitzki-11a6431
Thank you very much for taking the time to raise this concern.
As seen in Part 1, the Book of Monads says “we definitely need a swap function if we want to combine two
monads, but this is not enough. The reason is that a well-typed implementation may lead to a combined
monad that violates one of the monad laws. The list monad is a well-known example of this.”
So it looks like similar concerns apply when Traversable is used to provide the swap function. In FPiS there is no
example of using composeM to automatically wrap a Traversable Monad in any other Monad, so in Part 1 I had
a go and provided an example by composing the Option Monad with the Traversable List Monad. I need to
check if the resulting Monad satisfies the Monad laws.
In the meantime, see the next two slides for an example of the invalid composition of a Monad with a
Traversable Monad. I compose the List Traversable Monad with itself and while in some cases the resulting
Monad satisfies the monadic associative law, in another case (mentioned in the Book of Monads), it doesn’t.
@philip_schwarz
// sample A => F[B] function
val f: String => List[String] = _.split(" ").toList.map(_.capitalize)
assert(f("dog cat rabbit parrot")
== List("Dog", "Cat", "Rabbit", "Parrot"))
// sample B => F[C] function
val g: String => List[Int] = _.toList.map(_.toInt)
assert(g("Cat") == List(67, 97, 116))
// sample C => F[D] function
val h: Int => List[Char] = _.toString.toList
assert(h(102) == List('1', '0', '2'))
// sample A value
val a = "dog cat rabbit parrot"
// sample B value
val b = "Cat"
// sample C value
val c = 67
// sample D value
val d = '6'
// expected value of applying to "dog cat rabbit parrot"
// the kleisli composition of f, g and h
val expected = List(
/* Dog */ '6', '8', '1', '1', '1', '1', '0', '3',
/* Cat */ '6', '7', '9', '7', '1', '1', '6',
/* Rabbit */ '8', '2', '9', '7', '9', '8', '9', '8', '1', '0', '5', '1', '1', '6',
/* Parrot */ '8', '0', '9', '7', '1', '1', '4', '1', '1', '4', '1', '1', '1', '1', '1', '6')
// monadic associative law: x.flatMap(f).flatMap(g) == x.flatMap(a => f(a).flatMap(g))
// alternative formuation using kleisli composition: compose(compose(f, g), h) == compose(f, compose(g, h))
// the traversable list monad satisfies the associative law because its kleisli composition is associative
assert( traversableListMonad.compose(traversableListMonad.compose(f,g),h)("dog cat rabbit parrot") == expected)
assert( traversableListMonad.compose(f,traversableListMonad.compose(g,h))("dog cat rabbit parrot") == expected)
// Kleisli composition (defined on Monad F)
def compose[A,B,C](f: A => F[B], g: B => F[C]): A => F[C] = {
a => flatMap(f(a))(g)
}
// Monad composition
def composeM[G[_],H[_]](implicit G: Monad[G], H: Monad[H], T: Traverse[H]):
Monad[({type f[x] = G[H[x]]})#f] = new Monad[({type f[x] = G[H[x]]})#f] {
def unit[A](a: => A): G[H[A]] = G.unit(H.unit(a))
override def flatMap[A,B](mna: G[H[A]])(f: A => G[H[B]]): G[H[B]] = {
G.flatMap(mna)(na => G.map(T.traverse(na)(f))(H.join))
}
}
// Let's define a traversable List Monad
val traversableListMonad = new Monad[List] with Traverse[List] {
def unit[A](a: => A): List[A] = List(a)
override def flatMap[A,B](ma: List[A])(f: A => List[B]): List[B] = ma flatMap f
override def map[A,B](m: List[A])(f: A => B): List[B] = m map f
override def join[A](mma: List[List[A]]): List[A] = mma.flatten
override def traverse[M[_],A,B](as: List[A])
(f: A => M[B])(implicit M: Applicative[M]): M[List[B]] = {
as.foldRight(M.unit(List[B]()))((a, fbs) => M.map2(f(a), fbs)(_ :: _))
}
}
// compose traversableListMonad with itself
val listListMonad = composeM(traversableListMonad,traversableListMonad,traversableListMonad)
// Now let’s tweak f, g, and h to return a List of a List rather than just a List, so that they are amenable to
// composing using listListMonad’s kleisli composition, whose signature is
// def compose[A,B,C](f: A => List[List[B]], g: B => List[List[C]]): A => List[List[C]]
val ff: String => List[List[String]] = s => List(f(s),f(s))
val gg: String => List[List[Int]] = s => List(g(s),g(s))
val hh: Int => List[List[Char]] = n => List(h(n))
// listListMonad appears to satisfy the associative law
assert( listListMonad.compose(listListMonad.compose(fff,ggg),hhh)("dog cat rabbit parrot") == List.fill(32)(expected))
assert( listListMonad.compose(fff,listListMonad.compose(ggg,hhh))("dog cat rabbit parrot") == List.fill(32)(expected))
// but it doesn't: here is an example (by Petr Pudlak) of a function for which kleisli composition is not associative
def v(n: Int): List[List[Int]] = n match {
case 0 => List(List(0,1))
case 1 => List(List(0),List(1))
}
// listListMonad's kleisli composition is not associative when we compose function v with itself
assert( listListMonad.compose(listListMonad.compose(v,v),v)(0)
!= listListMonad.compose(v,listListMonad.compose(v,v)))
assert( listListMonad.compose(listListMonad.compose(v,v),v)(0)
== List(List(0,1,0,0,1),List(0,1,1,0,1),List(0,1,0,0),List(0,1,0,1),List(0,1,1,0),List(0,1,1,1)) )
assert( listListMonad.compose(v,listListMonad.compose(v,v))(0)
== List(List(0,1,0,0,1),List(0,1,0,0),List(0,1,0,1),List(0,1,1,0,1),List(0,1,1,0),List(0,1,1,1)) )

More Related Content

PDF
Abstracting over the Monad yielded by a for comprehension and its generators
PDF
Sequence and Traverse - Part 3
PDF
Monad Transformers - Part 1
PPTX
Kleisli composition, flatMap, join, map, unit - implementation and interrelation
PDF
Functor Composition
PDF
Monads do not Compose
PDF
Sequence and Traverse - Part 1
PDF
Sequence and Traverse - Part 2
Abstracting over the Monad yielded by a for comprehension and its generators
Sequence and Traverse - Part 3
Monad Transformers - Part 1
Kleisli composition, flatMap, join, map, unit - implementation and interrelation
Functor Composition
Monads do not Compose
Sequence and Traverse - Part 1
Sequence and Traverse - Part 2

What's hot (20)

PDF
Monoids - Part 2 - with examples using Scalaz and Cats
PDF
Functors
PDF
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
PDF
Monoids - Part 1 - with examples using Scalaz and Cats
PDF
Monad Fact #2
PDF
Scala collection methods flatMap and flatten are more powerful than monadic f...
PDF
Scala 3 enum for a terser Option Monad Algebraic Data Type
PDF
Monad Fact #4
PDF
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
PDF
Simple IO Monad in 'Functional Programming in Scala'
PDF
Big picture of category theory in scala with deep dive into contravariant and...
PDF
Real World Haskell: Lecture 5
PDF
Left and Right Folds - Comparison of a mathematical definition and a programm...
PDF
Real World Haskell: Lecture 4
PDF
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - with ...
PDF
Linear Types in Haskell
PDF
Real World Haskell: Lecture 2
PDF
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part 5
PDF
Fp in scala part 1
PDF
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...
Monoids - Part 2 - with examples using Scalaz and Cats
Functors
Quicksort - a whistle-stop tour of the algorithm in five languages and four p...
Monoids - Part 1 - with examples using Scalaz and Cats
Monad Fact #2
Scala collection methods flatMap and flatten are more powerful than monadic f...
Scala 3 enum for a terser Option Monad Algebraic Data Type
Monad Fact #4
Functional Core and Imperative Shell - Game of Life Example - Haskell and Scala
Simple IO Monad in 'Functional Programming in Scala'
Big picture of category theory in scala with deep dive into contravariant and...
Real World Haskell: Lecture 5
Left and Right Folds - Comparison of a mathematical definition and a programm...
Real World Haskell: Lecture 4
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - with ...
Linear Types in Haskell
Real World Haskell: Lecture 2
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part 5
Fp in scala part 1
Folding Unfolded - Polyglot FP for Fun and Profit - Haskell and Scala - Part ...
Ad

Similar to Addendum to ‘Monads do not Compose’ (20)

PDF
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...
PDF
Template Haskell
PDF
Monad Laws Must be Checked
PDF
Programming in Scala - Lecture Four
PPTX
PDF
And now you have two problems. Ruby regular expressions for fun and profit by...
PPT
Expresiones regulares, sintaxis y programación en JAVA
PDF
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
PPT
16 Java Regex
PDF
Introduction to Functional Languages
PDF
Buacm 2
PPTX
Unit 1-array,lists and hashes
PDF
List-based Monadic Computations for Dynamic Languages
PDF
Practical cats
PPT
Introduction to regular expressions
PDF
Why is Haskell so hard! (And how to deal with it?)
PDF
Programming in Scala - Lecture Three
PDF
Fp in scala part 2
PDF
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfol...
PDF
Lambda? You Keep Using that Letter
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit - Haskell and...
Template Haskell
Monad Laws Must be Checked
Programming in Scala - Lecture Four
And now you have two problems. Ruby regular expressions for fun and profit by...
Expresiones regulares, sintaxis y programación en JAVA
N-Queens Combinatorial Problem - Polyglot FP for Fun and Profit – Haskell and...
16 Java Regex
Introduction to Functional Languages
Buacm 2
Unit 1-array,lists and hashes
List-based Monadic Computations for Dynamic Languages
Practical cats
Introduction to regular expressions
Why is Haskell so hard! (And how to deal with it?)
Programming in Scala - Lecture Three
Fp in scala part 2
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfol...
Lambda? You Keep Using that Letter
Ad

More from Philip Schwarz (20)

PDF
ApplicativeError functions handling and recovering from errors: A mnemonic to...
PDF
Folding Cheat Sheet Series Titles - a series of 9 decks
PDF
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
PDF
Drawing Heighway’s Dragon - Part 4 - Interactive and Animated Dragon Creation
PDF
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
PDF
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
PDF
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
PDF
The Open-Closed Principle - Part 1 - The Original Version
PDF
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
PDF
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
PDF
Fibonacci Function Gallery - Part 2 - One in a series
PDF
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
PDF
Fibonacci Function Gallery - Part 1 (of a series)
PDF
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
PDF
Folding Cheat Sheet Series Titles (so far)
PDF
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
PDF
Folding Cheat Sheet #8 - eighth in a series
PDF
Function Applicative for Great Good of Leap Year Function
PDF
Folding Cheat Sheet #7 - seventh in a series
PDF
Folding Cheat Sheet #6 - sixth in a series
ApplicativeError functions handling and recovering from errors: A mnemonic to...
Folding Cheat Sheet Series Titles - a series of 9 decks
Folding Cheat Sheet # 9 - List Unfolding 𝑢𝑛𝑓𝑜𝑙𝑑 as the Computational Dual of ...
Drawing Heighway’s Dragon - Part 4 - Interactive and Animated Dragon Creation
The Nature of Complexity in John Ousterhout’s Philosophy of Software Design
Drawing Heighway’s Dragon - Part 3 - Simplification Through Separation of Con...
The Open-Closed Principle - Part 2 - The Contemporary Version - An Introduction
The Open-Closed Principle - Part 1 - The Original Version
Drawing Heighway’s Dragon - Part II - Recursive Function Simplification - Fro...
Drawing Heighway’s Dragon - Recursive Function Rewrite - From Imperative Styl...
Fibonacci Function Gallery - Part 2 - One in a series
Fibonacci Function Gallery - Part 1 (of a series) - with minor corrections
Fibonacci Function Gallery - Part 1 (of a series)
The Debt Metaphor - Ward Cunningham in his 2009 YouTube video
Folding Cheat Sheet Series Titles (so far)
From Subtype Polymorphism To Typeclass-based Ad hoc Polymorphism - An Example
Folding Cheat Sheet #8 - eighth in a series
Function Applicative for Great Good of Leap Year Function
Folding Cheat Sheet #7 - seventh in a series
Folding Cheat Sheet #6 - sixth in a series

Recently uploaded (20)

PPTX
ai tools demonstartion for schools and inter college
PDF
Digital Strategies for Manufacturing Companies
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
top salesforce developer skills in 2025.pdf
PDF
Softaken Excel to vCard Converter Software.pdf
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PPTX
L1 - Introduction to python Backend.pptx
ai tools demonstartion for schools and inter college
Digital Strategies for Manufacturing Companies
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
2025 Textile ERP Trends: SAP, Odoo & Oracle
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Odoo Companies in India – Driving Business Transformation.pdf
Upgrade and Innovation Strategies for SAP ERP Customers
How to Choose the Right IT Partner for Your Business in Malaysia
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Design an Analysis of Algorithms I-SECS-1021-03
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
CHAPTER 2 - PM Management and IT Context
top salesforce developer skills in 2025.pdf
Softaken Excel to vCard Converter Software.pdf
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Odoo POS Development Services by CandidRoot Solutions
Wondershare Filmora 15 Crack With Activation Key [2025
Which alternative to Crystal Reports is best for small or large businesses.pdf
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
L1 - Introduction to python Backend.pptx

Addendum to ‘Monads do not Compose’

  • 1. Addendum to ‘Monads do not Compose’ a temporary addendum to Part 1 of ‘Monads do not Compose’ illustrating an issue raised by Sergei Winitzki @philip_schwarz https://www.slideshare.net/pjschwarz/monads-do-not-compose
  • 2. It is a mistake to think that a traversable monad can be composed with another monad. It is true that, given `Traversable`, you can implement the monad's methods (pure and flatMap) for the composition with another monad (as in your slides 21 to 26), but this is a deceptive appearance. The laws of the `Traversable` typeclass are far insufficient to guarantee the laws of the resulting composed monad. The only traversable monads that work correctly are Option, Either, and Writer. It is true that you can implement the type signature of the `swap` function for any `Traversable` monad. However, the `swap` function for monads needs to satisfy very different and stronger laws than the `sequence` function from the `Traversable` type class. I'll have to look at the "Book of Monads"; but, if my memory serves, the FPiS book does not derive any of these laws.Sergei Winitzki sergei-winitzki-11a6431 Thank you very much for taking the time to raise this concern. As seen in Part 1, the Book of Monads says “we definitely need a swap function if we want to combine two monads, but this is not enough. The reason is that a well-typed implementation may lead to a combined monad that violates one of the monad laws. The list monad is a well-known example of this.” So it looks like similar concerns apply when Traversable is used to provide the swap function. In FPiS there is no example of using composeM to automatically wrap a Traversable Monad in any other Monad, so in Part 1 I had a go and provided an example by composing the Option Monad with the Traversable List Monad. I need to check if the resulting Monad satisfies the Monad laws. In the meantime, see the next two slides for an example of the invalid composition of a Monad with a Traversable Monad. I compose the List Traversable Monad with itself and while in some cases the resulting Monad satisfies the monadic associative law, in another case (mentioned in the Book of Monads), it doesn’t. @philip_schwarz
  • 3. // sample A => F[B] function val f: String => List[String] = _.split(" ").toList.map(_.capitalize) assert(f("dog cat rabbit parrot") == List("Dog", "Cat", "Rabbit", "Parrot")) // sample B => F[C] function val g: String => List[Int] = _.toList.map(_.toInt) assert(g("Cat") == List(67, 97, 116)) // sample C => F[D] function val h: Int => List[Char] = _.toString.toList assert(h(102) == List('1', '0', '2')) // sample A value val a = "dog cat rabbit parrot" // sample B value val b = "Cat" // sample C value val c = 67 // sample D value val d = '6' // expected value of applying to "dog cat rabbit parrot" // the kleisli composition of f, g and h val expected = List( /* Dog */ '6', '8', '1', '1', '1', '1', '0', '3', /* Cat */ '6', '7', '9', '7', '1', '1', '6', /* Rabbit */ '8', '2', '9', '7', '9', '8', '9', '8', '1', '0', '5', '1', '1', '6', /* Parrot */ '8', '0', '9', '7', '1', '1', '4', '1', '1', '4', '1', '1', '1', '1', '1', '6') // monadic associative law: x.flatMap(f).flatMap(g) == x.flatMap(a => f(a).flatMap(g)) // alternative formuation using kleisli composition: compose(compose(f, g), h) == compose(f, compose(g, h)) // the traversable list monad satisfies the associative law because its kleisli composition is associative assert( traversableListMonad.compose(traversableListMonad.compose(f,g),h)("dog cat rabbit parrot") == expected) assert( traversableListMonad.compose(f,traversableListMonad.compose(g,h))("dog cat rabbit parrot") == expected) // Kleisli composition (defined on Monad F) def compose[A,B,C](f: A => F[B], g: B => F[C]): A => F[C] = { a => flatMap(f(a))(g) } // Monad composition def composeM[G[_],H[_]](implicit G: Monad[G], H: Monad[H], T: Traverse[H]): Monad[({type f[x] = G[H[x]]})#f] = new Monad[({type f[x] = G[H[x]]})#f] { def unit[A](a: => A): G[H[A]] = G.unit(H.unit(a)) override def flatMap[A,B](mna: G[H[A]])(f: A => G[H[B]]): G[H[B]] = { G.flatMap(mna)(na => G.map(T.traverse(na)(f))(H.join)) } } // Let's define a traversable List Monad val traversableListMonad = new Monad[List] with Traverse[List] { def unit[A](a: => A): List[A] = List(a) override def flatMap[A,B](ma: List[A])(f: A => List[B]): List[B] = ma flatMap f override def map[A,B](m: List[A])(f: A => B): List[B] = m map f override def join[A](mma: List[List[A]]): List[A] = mma.flatten override def traverse[M[_],A,B](as: List[A]) (f: A => M[B])(implicit M: Applicative[M]): M[List[B]] = { as.foldRight(M.unit(List[B]()))((a, fbs) => M.map2(f(a), fbs)(_ :: _)) } }
  • 4. // compose traversableListMonad with itself val listListMonad = composeM(traversableListMonad,traversableListMonad,traversableListMonad) // Now let’s tweak f, g, and h to return a List of a List rather than just a List, so that they are amenable to // composing using listListMonad’s kleisli composition, whose signature is // def compose[A,B,C](f: A => List[List[B]], g: B => List[List[C]]): A => List[List[C]] val ff: String => List[List[String]] = s => List(f(s),f(s)) val gg: String => List[List[Int]] = s => List(g(s),g(s)) val hh: Int => List[List[Char]] = n => List(h(n)) // listListMonad appears to satisfy the associative law assert( listListMonad.compose(listListMonad.compose(fff,ggg),hhh)("dog cat rabbit parrot") == List.fill(32)(expected)) assert( listListMonad.compose(fff,listListMonad.compose(ggg,hhh))("dog cat rabbit parrot") == List.fill(32)(expected)) // but it doesn't: here is an example (by Petr Pudlak) of a function for which kleisli composition is not associative def v(n: Int): List[List[Int]] = n match { case 0 => List(List(0,1)) case 1 => List(List(0),List(1)) } // listListMonad's kleisli composition is not associative when we compose function v with itself assert( listListMonad.compose(listListMonad.compose(v,v),v)(0) != listListMonad.compose(v,listListMonad.compose(v,v))) assert( listListMonad.compose(listListMonad.compose(v,v),v)(0) == List(List(0,1,0,0,1),List(0,1,1,0,1),List(0,1,0,0),List(0,1,0,1),List(0,1,1,0),List(0,1,1,1)) ) assert( listListMonad.compose(v,listListMonad.compose(v,v))(0) == List(List(0,1,0,0,1),List(0,1,0,0),List(0,1,0,1),List(0,1,1,0,1),List(0,1,1,0),List(0,1,1,1)) )