240
范畴

Category theory is general abolute nonsens

Embed Size (px)

Citation preview

Page 1: Category theory is general abolute nonsens

范畴论

Page 2: Category theory is general abolute nonsens

范畴论Fànchóu lùn

Page 3: Category theory is general abolute nonsens
Page 4: Category theory is general abolute nonsens
Page 5: Category theory is general abolute nonsens
Page 6: Category theory is general abolute nonsens
Page 7: Category theory is general abolute nonsens

General nonsense (math.)

Abstract nonsenseFrom Wikipedia, the free encyclopedia

In mathematics, abstract nonsense, general abstract nonsense, and general nonsense are terms used facetiously by some mathematicians to describe certain kinds of arguments and methods related to category theory. (Very) roughly speaking, category theory is the study of the general form of mathematical theories, without regard to their content. As a result, a proof that relies on category theoretic ideas often seems slightly out of context to those who are not used to such abstraction, sometimes to the extent that it resembles a comicalnon sequitur. Such proofs are sometimes dubbed “abstract nonsense” as a light-hearted way of alerting people to their abstract nature.

Page 8: Category theory is general abolute nonsens

General nonsense (math.)

Abstract nonsenseFrom Wikipedia, the free encyclopedia

In mathematics, abstract nonsense, general abstract nonsense, and general nonsense are terms used facetiously by some mathematicians to describe certain kinds of arguments and methods related to category theory. (Very) roughly speaking, category theory is the study of the general form of mathematical theories, without regard to their content. As a result, a proof that relies on category theoretic ideas often seems slightly out of context to those who are not used to such abstraction, sometimes to the extent that it resembles a comicalnon sequitur. Such proofs are sometimes dubbed “abstract nonsense” as a light-hearted way of alerting people to their abstract nature.

Page 9: Category theory is general abolute nonsens

General nonsense (math.)

Abstract nonsenseFrom Wikipedia, the free encyclopedia

In mathematics, abstract nonsense, general abstract nonsense, and general nonsense are terms used facetiously by some mathematicians to describe certain kinds of arguments and methods related to category theory. (Very) roughly speaking, category theory is the study of the general form of mathematical theories, without regard to their content. As a result, a proof that relies on category theoretic ideas often seems slightly out of context to those who are not used to such abstraction, sometimes to the extent that it resembles a comicalnon sequitur. Such proofs are sometimes dubbed “abstract nonsense” as a light-hearted way of alerting people to their abstract nature.

Page 10: Category theory is general abolute nonsens

General nonsense (math.)

Abstract nonsenseFrom Wikipedia, the free encyclopedia

In mathematics, abstract nonsense, general abstract nonsense, and general nonsense are terms used facetiously by some mathematicians to describe certain kinds of arguments and methods related to category theory. (Very) roughly speaking, category theory is the study of the general form of mathematical theories, without regard to their content. As a result, a proof that relies on category theoretic ideas often seems slightly out of context to those who are not used to such abstraction, sometimes to the extent that it resembles a comicalnon sequitur. Such proofs are sometimes dubbed “abstract nonsense” as a light-hearted way of alerting people to their abstract nature.

Page 11: Category theory is general abolute nonsens

General nonsense (math.)

Abstract nonsenseFrom Wikipedia, the free encyclopedia

In mathematics, abstract nonsense, general abstract nonsense, and general nonsense are terms used facetiously by some mathematicians to describe certain kinds of arguments and methods related to category theory. (Very) roughly speaking, category theory is the study of the general form of mathematical theories, without regard to their content. As a result, a proof that relies on category theoretic ideas often seems slightly out of context to those who are not used to such abstraction, sometimes to the extent that it resembles a comicalnon sequitur. Such proofs are sometimes dubbed “abstract nonsense” as a light-hearted way of alerting people to their abstract nature.

Page 12: Category theory is general abolute nonsens

Category theory is absolute general nonsense!

What is all the fuss with all those monoids and semigroups I keep hearing about?

Page 13: Category theory is general abolute nonsens

“Functional Programming is academic phenomenon. Unless your product is purely

mathematical, it’s nothing but a nice idea that has nothing to do with real world”

Page 14: Category theory is general abolute nonsens

Why not FP?

Page 15: Category theory is general abolute nonsens

Why not FP?

● FP might be good nice academic exercise, but ..

Page 16: Category theory is general abolute nonsens

Why not FP?

● FP might be good nice academic exercise, but ..● .. has nothing to do with real world

Page 17: Category theory is general abolute nonsens

Why not FP?

● FP might be good nice academic exercise, but ..● .. has nothing to do with real world● The last three decades proved that OO-programming is

useful & necessary

Page 18: Category theory is general abolute nonsens

Why not FP?

● FP might be good nice academic exercise, but ..● .. has nothing to do with real world● The last three decades proved that OO-programming is

useful & necessary ● OO has some inconveniences, but it is a de facto standard

Page 19: Category theory is general abolute nonsens

Why not FP?

● FP might be good nice academic exercise, but ..● .. has nothing to do with real world● The last three decades proved that OO-programming is

useful & necessary ● OO has some inconveniences, but it is a de facto standard● FP is complex, I don’t understand it, I doubt it will be

applicable to real world, ever!

Page 20: Category theory is general abolute nonsens
Page 21: Category theory is general abolute nonsens

Edsger Dijkstra

Page 22: Category theory is general abolute nonsens

Edsger Dijkstraˈɛtsxər ˈdɛɪkstra

Page 23: Category theory is general abolute nonsens

Edsger Dijkstraˈɛtsxər ˈdɛɪkstra

https://en.wikipedia.org/wiki/Edsger_W._Dijkstra

Page 24: Category theory is general abolute nonsens
Page 25: Category theory is general abolute nonsens
Page 26: Category theory is general abolute nonsens
Page 27: Category theory is general abolute nonsens
Page 28: Category theory is general abolute nonsens
Page 29: Category theory is general abolute nonsens

https://xkcd.com/292/

Page 30: Category theory is general abolute nonsens
Page 31: Category theory is general abolute nonsens
Page 32: Category theory is general abolute nonsens

This paper tries to convince us that the well-known goto statement should be eliminated from our programming languages or, at least (since I don’t think that it will ever be eliminated), that programmers should not use it. (...)

Page 33: Category theory is general abolute nonsens

This paper tries to convince us that the well-known goto statement should be eliminated from our programming languages or, at least (since I don’t think that it will ever be eliminated), that programmers should not use it. (...) The author is a proponent of the socalled “structured programming” style, in which, if I get it right, gotos are replaced by indentation.

Page 34: Category theory is general abolute nonsens

This paper tries to convince us that the well-known goto statement should be eliminated from our programming languages or, at least (since I don’t think that it will ever be eliminated), that programmers should not use it. (...) The author is a proponent of the socalled “structured programming” style, in which, if I get it right, gotos are replaced by indentation. Structured programming is a nice academic exercise, which works well for small examples, but I doubt that any real-world program will ever be written in such a style.

Page 35: Category theory is general abolute nonsens

This paper tries to convince us that the well-known goto statement should be eliminated from our programming languages or, at least (since I don’t think that it will ever be eliminated), that programmers should not use it. (...) The author is a proponent of the socalled “structured programming” style, in which, if I get it right, gotos are replaced by indentation. Structured programming is a nice academic exercise, which works well for small examples, but I doubt that any real-world program will ever be written in such a style. More than 10 years of industrial experience with Fortran have proved conclusively to everybody concerned that, in the real world, the goto is useful and necessary:

Page 36: Category theory is general abolute nonsens

This paper tries to convince us that the well-known goto statement should be eliminated from our programming languages or, at least (since I don’t think that it will ever be eliminated), that programmers should not use it. (...) The author is a proponent of the socalled “structured programming” style, in which, if I get it right, gotos are replaced by indentation. Structured programming is a nice academic exercise, which works well for small examples, but I doubt that any real-world program will ever be written in such a style. More than 10 years of industrial experience with Fortran have proved conclusively to everybody concerned that, in the real world, the goto is useful and necessary: its presence might cause some inconveniences in debugging, but it is a de facto standard and we must live with it.

Page 37: Category theory is general abolute nonsens

This paper tries to convince us that the well-known goto statement should be eliminated from our programming languages or, at least (since I don’t think that it will ever be eliminated), that programmers should not use it. (...) The author is a proponent of the socalled “structured programming” style, in which, if I get it right, gotos are replaced by indentation. Structured programming is a nice academic exercise, which works well for small examples, but I doubt that any real-world program will ever be written in such a style. More than 10 years of industrial experience with Fortran have proved conclusively to everybody concerned that, in the real world, the goto is useful and necessary: its presence might cause some inconveniences in debugging, but it is a de facto standard and we must live with it. It will take more than the academic elucubrations of a purist to remove it from our languages. (...)

Page 38: Category theory is general abolute nonsens

“Semigroup, monoid, typeclass… It sounds so abstract”

Page 39: Category theory is general abolute nonsens

“Semigroup, monoid, typeclass… It sounds so abstract”“Yes, but so do all OO-patterns!”

Page 40: Category theory is general abolute nonsens
Page 41: Category theory is general abolute nonsens

“The Story of a Blackout”

In 5 acts

Page 42: Category theory is general abolute nonsens

Act.1: “Loss & Grief”

Page 43: Category theory is general abolute nonsens
Page 44: Category theory is general abolute nonsens

Our goal:

● DRY principle● Separation of concerns● Epic decoupling● Clean API● Minimal Boilerplate

Page 45: Category theory is general abolute nonsens
Page 46: Category theory is general abolute nonsens
Page 47: Category theory is general abolute nonsens
Page 48: Category theory is general abolute nonsens
Page 49: Category theory is general abolute nonsens

503 Service Temporarily Unavailablenginx

Page 50: Category theory is general abolute nonsens

503 Service Temporarily Unavailablenginx

Page 51: Category theory is general abolute nonsens
Page 52: Category theory is general abolute nonsens
Page 53: Category theory is general abolute nonsens

The 5 Stages of Loss and Grief

Page 54: Category theory is general abolute nonsens

The 5 Stages of Loss and Grief

1. Denial

Page 55: Category theory is general abolute nonsens

The 5 Stages of Loss and Grief

1. Denial2. Anger

Page 56: Category theory is general abolute nonsens

The 5 Stages of Loss and Grief

1. Denial2. Anger3. Bargaining

Page 57: Category theory is general abolute nonsens

The 5 Stages of Loss and Grief

1. Denial2. Anger3. Bargaining4. Depression

Page 58: Category theory is general abolute nonsens

The 5 Stages of Loss and Grief

1. Denial2. Anger3. Bargaining4. Depression5. Acceptance

Page 59: Category theory is general abolute nonsens
Page 60: Category theory is general abolute nonsens

Act.2: “The Mess”

Page 61: Category theory is general abolute nonsens

auction

Page 62: Category theory is general abolute nonsens

auctionify

Page 63: Category theory is general abolute nonsens

auctionify.io

Page 64: Category theory is general abolute nonsens

Domain & Feature RequestsDomain:

● Users place Orders in the auction system

Order

Page 65: Category theory is general abolute nonsens

Domain & Feature RequestsDomain:

● Users place Orders in the auction system● Orders can be:

○ General - contain list of Products○ Complex - combined from two or more

other Orders○ Cancelled - used to be fully fledged

Orders, but now are cancelled

Order

General Complex Cancelled

Page 66: Category theory is general abolute nonsens

Domain & Feature RequestsDomain:

● Users place Orders in the auction system● Orders can be:

○ General - contain list of Products○ Complex - combined from two or more

other Orders○ Cancelled - used to be fully fledged

Orders, but now are cancelled● Products can be:

○ Basic - id & price○ Discounted - wrapped Product &

discount○ OutOfStock - used to be in warehouse, but

now gone (sorry)

Order

General Complex Cancelled

Product

Basic Discounter Out of Stock

Page 67: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 68: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 69: Category theory is general abolute nonsens

sealed trait Order

case class GeneralOrder(products: List[Product]) extends Order

case object CancelledOrder extends Order

case class ComplexOrder(orders: List[Order]) extends Order

sealed trait Product

case class BasicProduct(id: Int, price: BigDecimal) extends Product

case class DiscountedProduct(product: Product,

discount: Double) extends Product

case object OutOfStock extends Product

Page 70: Category theory is general abolute nonsens

test("should evaluate order") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = GeneralOrder(DiscountedProduct(

product = BasicProduct(11, BigDecimal("1")),

discount = 0.2) :: Nil)

val o3 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)

order.evaluate should equal (BigDecimal("11.0"))

}

Page 71: Category theory is general abolute nonsens

test("should evaluate order") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = GeneralOrder(DiscountedProduct(

product = BasicProduct(11, BigDecimal("1")),

discount = 0.2) :: Nil)

val o3 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)

order.evaluate should equal (BigDecimal("11.0"))

}

[error] OrderTest.scala evaluate is not a member of jw.ComplexOrder

[error] order.evaluate should equal (BigDecimal("11.0"))

[error] ^

[error] one error found

Page 72: Category theory is general abolute nonsens
Page 73: Category theory is general abolute nonsens
Page 74: Category theory is general abolute nonsens
Page 75: Category theory is general abolute nonsens
Page 76: Category theory is general abolute nonsens
Page 77: Category theory is general abolute nonsens
Page 78: Category theory is general abolute nonsens

Subtype Polymorphism

Page 79: Category theory is general abolute nonsens

test("should evaluate order") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = GeneralOrder(DiscountedProduct(

product = BasicProduct(11, BigDecimal("1")),

discount = 0.2) :: Nil)

val o3 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)

order.evaluate should equal (BigDecimal("11.0"))

}

[error] OrderTest.scala evaluate is not a member of jw.ComplexOrder

[error] order.evaluate should equal (BigDecimal("11.0"))

[error] ^

[error] one error found

Page 80: Category theory is general abolute nonsens

test("should evaluate order") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = GeneralOrder(DiscountedProduct(

product = BasicProduct(11, BigDecimal("1")),

discount = 0.2) :: Nil)

val o3 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)

order.evaluate should equal (BigDecimal("11.0"))

}

Page 81: Category theory is general abolute nonsens

sealed trait Order

case class GeneralOrder(products: List[Product]) extends Order

case object CancelledOrder extends Order

case class ComplexOrder(orders: List[Order]) extends Order

sealed trait Product

case class BasicProduct(id: Int, price: BigDecimal) extends Product

case class DiscountedProduct(product: Product,

discount: Double) extends Product

case object OutOfStock extends Product

Page 82: Category theory is general abolute nonsens

trait Evaluatable[T] { def evaluate: T }

sealed trait Order extends Evaluatable[BigDecimal]

case object CancelledOrder extends Order {

def evaluate: BigDecimal = BigDecimal("0.0")

}

case class ComplexOrder(orders: List[Order]) extends Order {

def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {

case (acc, o) => acc + o.evaluate

}

}

case class GeneralOrder(products: List[Product]) extends Order {

def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {

case (acc, p) => acc + p.evaluate

}

}

Page 83: Category theory is general abolute nonsens

trait Evaluatable[T] { def evaluate: T }

sealed trait Product extends Evaluatable[BigDecimal]

case class BasicProduct(id: Int, price: BigDecimal) extends Product {

def evaluate: BigDecimal = price

}

case class DiscountedProduct(product: Product, discount: Double) extends Product {

def evaluate: BigDecimal = product.evaluate * (1 - discount)

}

case object OutOfStock extends Product {

def evaluate: BigDecimal = BigDecimal("0.0")

}

Page 84: Category theory is general abolute nonsens

test("should evaluate order") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = GeneralOrder(DiscountedProduct(

product = BasicProduct(11, BigDecimal("1")),

discount = 0.2) :: Nil)

val o3 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)

order.evaluate should equal (BigDecimal("11.0"))

}

Page 85: Category theory is general abolute nonsens

test("should evaluate order") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = GeneralOrder(DiscountedProduct(

product = BasicProduct(11, BigDecimal("1")),

discount = 0.2) :: Nil)

val o3 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: o3 :: Nil)

order.evaluate should equal (BigDecimal("11.0"))

}

[info] OrderTest:

[info] - should evaluate order

Page 86: Category theory is general abolute nonsens
Page 87: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 88: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 89: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 90: Category theory is general abolute nonsens

test("should calculate average") {

val o1 = GeneralOrder(DiscountedProduct(product =

BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)

val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)

val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))

}

Page 91: Category theory is general abolute nonsens

test("should calculate average") {

val o1 = GeneralOrder(DiscountedProduct(product =

BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)

val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)

val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))

}

[error] OrderTest.scala average is not a member of jw.Order

[error] Order.average should equal (BigDecimal("5.0"))

[error] ^

[error] one error found

Page 92: Category theory is general abolute nonsens

object Stat {

def mean(xs: Seq[BigDecimal]): BigDecimal =

xs.reduce(_ + _) / xs.size

}

Page 93: Category theory is general abolute nonsens

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

object Stat {

def mean(xs: Seq[BigDecimal]): BigDecimal =

xs.reduce(_ + _) / xs.size

}

Page 94: Category theory is general abolute nonsens
Page 95: Category theory is general abolute nonsens

AWESOME!I just need it to work for

Doubles and Ints as well! Can you make it

more generic?

Page 96: Category theory is general abolute nonsens

object Stat {

def mean(xs: Seq[BigDecimal]): BigDecimal =

xs.reduce(_ + _) / xs.size

}

Page 97: Category theory is general abolute nonsens

object Stat {

def mean(xs: Seq[Number]): Number =

xs.reduce(_ + _) / xs.size

}

Page 98: Category theory is general abolute nonsens
Page 99: Category theory is general abolute nonsens
Page 100: Category theory is general abolute nonsens

trait Number[A] {

def value: A

def +(other: Number[A]): Number[A]

def /(other: Number[A]): Number[A]

def /(other: Int): Number[A]

}

Page 101: Category theory is general abolute nonsens

trait Number[A] {

def value: A

def +(other: Number[A]): Number[A]

def /(other: Number[A]): Number[A]

def /(other: Int): Number[A]

}

case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {

def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)

def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)

def /(other: Int) = BigDecimalNumber(value / other)

}

Page 102: Category theory is general abolute nonsens

trait Number[A] {

def value: A

def +(other: Number[A]): Number[A]

def /(other: Number[A]): Number[A]

def /(other: Int): Number[A]

}

case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {

def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)

def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)

def /(other: Int) = BigDecimalNumber(value / other)

}

Page 103: Category theory is general abolute nonsens

trait Number[A] {

def value: A

def +(other: Number[A]): Number[A]

def /(other: Number[A]): Number[A]

def /(other: Int): Number[A]

}

case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {

def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)

def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)

def /(other: Int) = BigDecimalNumber(value / other)

}

case class IntNumber(value: Int) extends Number[Int] {

def +(other: Number[Int]) = IntNumber(value + other.value)

def /(other: Number[Int]) = IntNumber(value / other.value)

def /(other: Int) = IntNumber(value / other)

}

Page 104: Category theory is general abolute nonsens

trait Number[A] {

def value: A

def +(other: Number[A]): Number[A]

def /(other: Number[A]): Number[A]

def /(other: Int): Number[A]

}

case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {

def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)

def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)

def /(other: Int) = BigDecimalNumber(value / other)

}

case class IntNumber(value: Int) extends Number[Int] {

def +(other: Number[Int]) = IntNumber(value + other.value)

def /(other: Number[Int]) = IntNumber(value / other.value)

def /(other: Int) = IntNumber(value / other)

}

case class DoubleNumber(value: Double) extends Number[Double] {

def +(other: Number[Double]) = DoubleNumber(value + other.value)

def /(other: Number[Double]) = DoubleNumber(value / other.value)

def /(other: Int) = DoubleNumber(value / other)

}

Page 105: Category theory is general abolute nonsens

object Stat {

def mean(xs: Seq[BigDecimal]): BigDecimal =

xs.reduce(_ + _) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 106: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[Number[A]]): Number[A] =

xs.reduce(_ + _) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value

}

Page 107: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[Number[A]]): Number[A] =

xs.reduce(_ + _) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value

}

Page 108: Category theory is general abolute nonsens

test("should calculate average") {

val o1 = GeneralOrder(DiscountedProduct(product =

BasicProduct(11, BigDecimal("1")), discount = 0.2) :: Nil)

val o2 = GeneralOrder(BasicProduct(10, BigDecimal("4")) :: Nil)

val o3 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

Order.average(o1 :: o2 :: o3 :: Nil) should equal(BigDecimal("5.0"))

}

[info] OrderTest:

[info] - should evaluate order

[info] - should calculate average

Page 109: Category theory is general abolute nonsens
Page 110: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 111: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 112: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 113: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

JsonSerializer.write(order) should equal(expectedJson)

}

Page 114: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

JsonSerializer.write(order) should equal(expectedJson)

}

[error] OrderTest.scala not found: value JsonSerializer

[error] JsonSerializer.write(order) should equal(expectedJson)

[error] ^

Page 115: Category theory is general abolute nonsens

object JsonSerializer {

def write(order: Order): String = ...

}

Page 116: Category theory is general abolute nonsens
Page 117: Category theory is general abolute nonsens
Page 118: Category theory is general abolute nonsens

I have few objects I also need to serialize to JSON. Can you make

your code a bit more generic? Thanks!!!

Page 119: Category theory is general abolute nonsens

object JsonSerializer {

def write(order: Order): String = ...

}

Page 120: Category theory is general abolute nonsens

object JsonSerializer {

def write(sth: ???): String = ...

}

Page 121: Category theory is general abolute nonsens

object JsonSerializer {

def write(serializable: JsonSerializable) = ...

}

Page 122: Category theory is general abolute nonsens

object JsonSerializer {

def write(serializable: JsonSerializable) = ...

}

trait JsonSerializable {

def toJson: JsonValue

}

Page 123: Category theory is general abolute nonsens

object JsonSerializer {

def write(serializable: JsonSerializable) =

JsonWriter.write(serializable.toJson)

}

trait JsonSerializable {

def toJson: JsonValue

}

Page 124: Category theory is general abolute nonsens

object JsonSerializer {

def write(serializable: JsonSerializable) =

JsonWriter.write(serializable.toJson)

}

trait JsonSerializable {

def toJson: JsonValue

}

Page 125: Category theory is general abolute nonsens

sealed trait JsonValue

Page 126: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

Page 127: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String =

Page 128: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = json match {

Page 129: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = json match {

case JsonNumber(value) => value.toString

}

}

Page 130: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = json match {

case JsonString(value) => s""""$value""""

case JsonNumber(value) => value.toString

}

}

Page 131: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = json match {

case JsonArray(elems) => "[" + elems.map(write).mkString(", ") + "]"

case JsonString(value) => s""""$value""""

case JsonNumber(value) => value.toString

}

}

Page 132: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = json match {

case JsonObject(elems) =>

val entries = for {

(key, value) <- elems

} yield s""""$key: ${write(value)}""""

"{" + entries.mkString(", ") + "}"

case JsonArray(elems) => "[" + elems.map(write).mkString(", ") + "]"

case JsonString(value) => s""""$value""""

case JsonNumber(value) => value.toString

}

}

Page 133: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = ...

}

Page 134: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = ...

}

trait JsonSerializable {

def toJson: JsonValue

}

object JsonSerializer {

def write(serializable: JsonSerializable) =

JsonWriter.write(serializable.toJson)

}

Page 135: Category theory is general abolute nonsens

sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable {

def evaluate: BigDecimal

}

Page 136: Category theory is general abolute nonsens

sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable {

def evaluate: BigDecimal

}

case class GeneralOrder(products: List[Product]) extends Order {

def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {

case (acc, p) => acc + p.evaluate

}

def toJson: JsonValue = JsonObject(Map(

"type" -> JsonString("general"),

"products" -> JsonArray(products.map(_.toJson))

))

}

Page 137: Category theory is general abolute nonsens

sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable {

def evaluate: BigDecimal

}

case object CancelledOrder extends Order {

def evaluate: BigDecimal = BigDecimal("0.0")

def toJson: JsonValue = JsonString("cancelled order")

}

Page 138: Category theory is general abolute nonsens

sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable {

def evaluate: BigDecimal

}

case class ComplexOrder(orders: List[Order]) extends Order {

def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {

case (acc, o) => acc + o.evaluate

}

override def toJson: JsonValue = JsonObject(Map(

"type" -> JsonString("complex"),

"orders" -> JsonArray(orders.map(_.toJson)))

)

}

Page 139: Category theory is general abolute nonsens

sealed trait Product extends Evaluatable[BigDecimal] with JsonSerializable {

def evaluate: BigDecimal

}

case class BasicProduct(id: Int, price: BigDecimal) extends Product {

def evaluate: BigDecimal = price

def toJson: JsonValue = JsonObject(Map(

"type" -> JsonString("basic"),

"id" -> JsonNumber(BigDecimal(id)),

"price" -> JsonNumber(price)

))

}

Page 140: Category theory is general abolute nonsens

sealed trait Product extends Evaluatable[BigDecimal] with JsonSerializable {

def evaluate: BigDecimal

}

case class DiscountedProduct(product: Product, discount: Double) extends Product {

def evaluate: BigDecimal = product.evaluate * (1 - discount)

def toJson: JsonValue = JsonObject(Map(

"type" -> JsonString("discounted"),

"product" -> product.toJson,

"discount" -> JsonNumber(discount)

))

}

Page 141: Category theory is general abolute nonsens

sealed trait Product extends Evaluatable[BigDecimal] with JsonSerializable {

def evaluate: BigDecimal

}

case object OutOfStock extends Product {

def evaluate: BigDecimal = BigDecimal("0.0")

def toJson: JsonValue = JsonString("out of stock")

}

Page 142: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

JsonSerializer.write(order) should equal(expectedJson)

}

[info] OrderTest:

[info] - should evaluate order

[info] - should calculate average

[info] - should serialize to json

Page 143: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 144: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 145: Category theory is general abolute nonsens
Page 146: Category theory is general abolute nonsens
Page 147: Category theory is general abolute nonsens
Page 148: Category theory is general abolute nonsens
Page 149: Category theory is general abolute nonsens

Our goal:

● DRY principle● Separation of concerns● Epic decoupling● Clean API● Minimal Boilerplate

Page 150: Category theory is general abolute nonsens

Act.3: “Re-inventing the Wheel”

Page 151: Category theory is general abolute nonsens

trait Number[A] {

def value: A

def +(other: Number[A]): Number[A]

def /(other: Number[A]): Number[A]

def /(other: Int): Number[A]

}

case class BigDecimalNumber(value: BigDecimal) extends Number[BigDecimal] {

def +(other: Number[BigDecimal]) = BigDecimalNumber(value + other.value)

def /(other: Number[BigDecimal]) = BigDecimalNumber(value / other.value)

def /(other: Int) = BigDecimalNumber(value / other)

}

case class IntNumber(value: Int) extends Number[Int] {

def +(other: Number[Int]) = IntNumber(value + other.value)

def /(other: Number[Int]) = IntNumber(value / other.value)

def /(other: Int) = IntNumber(value / other)

}

case class DoubleNumber(value: Double) extends Number[Double] {

def +(other: Number[Double]) = DoubleNumber(value + other.value)

def /(other: Number[Double]) = DoubleNumber(value / other.value)

def /(other: Int) = DoubleNumber(value / other)

}

Page 152: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[Number[A]]): Number[A] =

xs.reduce(_ + _) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value

}

Page 153: Category theory is general abolute nonsens

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(o => BigDecimalNumber(o.evaluate))).value

}

Page 154: Category theory is general abolute nonsens

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 155: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[Number[A]]): Number[A] =

xs.reduce(_ + _) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 156: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A]): A =

xs.reduce(_ + _) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 157: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

number.divide(xs.reduce(number.plus),xs.size)

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 158: Category theory is general abolute nonsens

trait Number[A] {

def plus(n1: A, n2: A): A

def divide(n1: A, n2: A): A

def divide(n1: A, n2: Int): A

}

Page 159: Category theory is general abolute nonsens

trait Number[A] {

def plus(n1: A, n2: A): A

def divide(n1: A, n2: A): A

def divide(n1: A, n2: Int): A

}

object Number {

implicit object BigDecimalNumber extends Number[BigDecimal] {

def plus(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 + n2

def divide(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 / n2

def divide(n1: BigDecimal, n2: Int): BigDecimal = n1 / n2

}

Page 160: Category theory is general abolute nonsens

trait Number[A] {

def plus(n1: A, n2: A): A

def divide(n1: A, n2: A): A

def divide(n1: A, n2: Int): A

}

object Number {

implicit object BigDecimalNumber extends Number[BigDecimal] {

def plus(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 + n2

def divide(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 / n2

def divide(n1: BigDecimal, n2: Int): BigDecimal = n1 / n2

}

implicit object IntNumber extends Number[Int] {

def plus(n1: Int, n2: Int): Int = n1 + n2

def divide(n1: Int, n2: Int): Int = n1 / n2

}

}

Page 161: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

number.divide(xs.reduce(number.plus),xs.size)

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 162: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

number.divide(xs.reduce(number.plus),xs.size)

}

object Order {

def average(orders: Seq[Order])(BigDecimalNumber): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 163: Category theory is general abolute nonsens

trait Number[A] {

def plus(n1: A, n2: A): A

def divide(n1: A, n2: A): A

def divide(n1: A, n2: Int): A

}

object Number {

implicit object BigDecimalNumber extends Number[BigDecimal] {

def plus(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 + n2

def divide(n1: BigDecimal, n2: BigDecimal): BigDecimal = n1 / n2

def divide(n1: BigDecimal, n2: Int): BigDecimal = n1 / n2

}

implicit object IntNumber extends Number[Int] {

def plus(n1: Int, n2: Int): Int = n1 + n2

def divide(n1: Int, n2: Int): Int = n1 / n2

}

}

Page 164: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

number.divide(xs.reduce(number.plus),xs.size)

}

object Order {

def average(orders: Seq[Order])(BigDecimalNumber): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 165: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

number.divide(xs.reduce(number.plus),xs.size)

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 166: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

number.divide(xs.reduce(number.plus),xs.size)

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 167: Category theory is general abolute nonsens

implicit class NumberOps[A](a: A)(implicit number: Number[A]) {

def +(other: A) = number.plus(a, other)

def /(other: A) = number.divide(a, other)

def /(other: Int) = number.divide(a, other)

}

}

Page 168: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

number.divide(xs.reduce(number.plus),xs.size)

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 169: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

xs.reduce(number.plus) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 170: Category theory is general abolute nonsens

object Stat {

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

xs.reduce(_ + _) / xs.size

}

object Order {

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

}

Page 171: Category theory is general abolute nonsens

[info] OrderTest:

[info] - should evaluate order

[info] - should calculate average

[info] - should serialize to json

Page 172: Category theory is general abolute nonsens
Page 173: Category theory is general abolute nonsens
Page 174: Category theory is general abolute nonsens

sealed trait JsonValue

case class JsonObject(elem: Map[String, JsonValue]) extends JsonValue

case class JsonArray(elems: List[JsonValue]) extends JsonValue

case class JsonString(value: String) extends JsonValue

case class JsonNumber(value: BigDecimal) extends JsonValue

object JsonWriter {

def write(json: JsonValue): String = ...

}

trait JsonSerializable {

def toJson: JsonValue

}

object JsonSerializer {

def write(serializable: JsonSerializable) =

JsonWriter.write(serializable.toJson)

}

Page 175: Category theory is general abolute nonsens

sealed trait Order extends Evaluatable[BigDecimal] with JsonSerializable

case class GeneralOrder(products: List[Product]) extends Order {

def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {

case (acc, p) => acc + p.evaluate

}

def toJson: JsonValue = JsonObject(Map(

"type" -> JsonString("general"),

"products" -> JsonArray(products.map(_.toJson))

))

}

Page 176: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

JsonSerializer.write(order) should equal(expectedJson)

}

Page 177: Category theory is general abolute nonsens

trait JsonSerializable {

def toJson: JsonValue

}

object JsonSerializer {

def write(serializable: JsonSerializable) =

JsonWriter.write(serializable.toJson)

}

Page 178: Category theory is general abolute nonsens

trait Json[-A] {

def toJson(a: A): JsonValue

}

object JsonSerializer {

def write(serializable: JsonSerializable) =

JsonWriter.write(serializable.toJson)

}

Page 179: Category theory is general abolute nonsens

trait Json[-A] {

def toJson(a: A): JsonValue

}

object JsonSerializer {

def write[A](a: A)(implicit json: Json[A]) =

JsonWriter.write(json.toJson(a))

}

Page 180: Category theory is general abolute nonsens

object OrderJson {

implicit object ProductToJson extends Json[Product] {

def toJson(product: Product): JsonValue = ...

}

implicit object OrderToJson extends Json[Order] {

def toJson(order: Order): JsonValue = ...

}

}

Page 181: Category theory is general abolute nonsens

implicit object ProductToJson extends Json[Product] {

def toJson(product: Product): JsonValue = product match {

case BasicProduct(id, price) =>

JsonObject(Map(

"type" -> JsonString("basic"),

"id" -> JsonNumber(BigDecimal(id)),

"price" -> JsonNumber(price)

))

case DiscountedProduct(product, discount) =>

JsonObject(Map(

"type" -> JsonString("discounted"),

"product" -> toJson(product),

"discount" -> JsonNumber(discount)

))

case OutOfStock() =>

JsonString("out of stock")

}

}

implicit object OrderToJson extends Json[Order] {

def toJson(order: Order): JsonValue = order match {

case GeneralOrder(products) =>

JsonObject(Map(

"type" -> JsonString("general"),

"products" -> JsonArray(products.map(ProductToJson.toJson))

))

case ComplexOrder(orders) =>

JsonObject(Map(

"type" -> JsonString("complex"),

"orders" -> JsonArray(orders.map(toJson))

))

case CancelledOrder() =>

JsonString("cancelled order")

}

}

Page 182: Category theory is general abolute nonsens

implicit object OrderToJson extends Json[Order] {

def toJson(order: Order): JsonValue = order match {

case GeneralOrder(products) =>

JsonObject(Map(

"type" -> JsonString("general"),

"products" -> JsonArray(products.map(ProductToJson.toJson))

))

case ComplexOrder(orders) =>

JsonObject(Map(

"type" -> JsonString("complex"),

"orders" -> JsonArray(orders.map(toJson))

))

case CancelledOrder() =>

JsonString("cancelled order")

}

}

Page 183: Category theory is general abolute nonsens

object OrderJson {

implicit object ProductToJson extends Json[Product] {

def toJson(product: Product): JsonValue = ...

}

implicit object OrderToJson extends Json[Order] {

def toJson(order: Order): JsonValue = ...

}

}

Page 184: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

JsonSerializer.write(order) should equal(expectedJson)

}

Page 185: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

JsonSerializer.write(order) should equal(expectedJson)

}

[error] OrderTest.scala could not find implicit value for parameter json: json.Json[jw.

ComplexOrder]

[error] JsonSerializer.write(order) should equal(expectedJson)

Page 186: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

JsonSerializer.write(order) should equal(expectedJson)

}

Page 187: Category theory is general abolute nonsens

test("should serialize to json") {

val o1 = GeneralOrder(BasicProduct(10, BigDecimal("10.2")) :: Nil)

val o2 = CancelledOrder

val order = ComplexOrder(o1 :: o2 :: Nil)

val expectedJson = """{

"type: "complex"",

"orders: [{

"type: "general"",

"products: [{"type: "basic"", "id: 10", "price: 10.2"}]"

},

"cancelled order"]"

}"""

import OrderJson._

JsonSerializer.write(order) should equal(expectedJson)

}

[info] OrderTest:

[info] - should evaluate order

[info] - should calculate average

[info] - should serialize to json

Page 188: Category theory is general abolute nonsens
Page 189: Category theory is general abolute nonsens

sealed trait Product extends Evaluatable[BigDecimal]

case class BasicProduct(id: Int, price: BigDecimal) extends Product {

def evaluate: BigDecimal = price

}

case class DiscountedProduct(product: Product, discount: Double) extends Product {

def evaluate: BigDecimal = product.evaluate * (1 - discount)

}

case class OutOfStock() extends Product {

def evaluate: BigDecimal = BigDecimal("0.0")

}

Page 190: Category theory is general abolute nonsens

sealed trait Order extends Evaluatable[BigDecimal]

case class GeneralOrder(products: List[Product]) extends Order {

def evaluate: BigDecimal = products.foldLeft(BigDecimal("0.0")) {

case (acc, p) => acc + p.evaluate

}

}

case class CancelledOrder() extends Order {

def evaluate: BigDecimal = BigDecimal("0.0")

}

case class ComplexOrder(orders: List[Order]) extends Order {

def evaluate: BigDecimal = orders.foldLeft(BigDecimal("0.0")) {

case (acc, o) => acc + o.evaluate

}

Page 191: Category theory is general abolute nonsens

trait Evaluate[-A, T] { def evaluate(a: A): T }

object Order {

implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] {

def evaluate(product: Product): BigDecimal = product match {

case BasicProduct(id, price) => price

case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount)

case OutOfStock() => BigDecimal("0.0")

}}

implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] {

def evaluate(order: Order): BigDecimal = order match {

case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) {

case (acc, p) => acc + ProductEvaluate.evaluate(p)

}

case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) {

case (acc, o) => acc + evaluate(o)

}

case CancelledOrder() => BigDecimal("0.0")

}}}

Page 192: Category theory is general abolute nonsens

trait Evaluate[-A, T] { def evaluate(a: A): T }

object Evaluate {

implicit class EvaluateOps[-A, T](a: A)(implicit ev: Evaluate[A, T]) {

def evaluate = ev.evaluate(a)

}

}

import Evaluate._

def average(orders: Seq[Order]): BigDecimal =

Stat.mean(orders.map(_.evaluate))

Page 193: Category theory is general abolute nonsens
Page 194: Category theory is general abolute nonsens

sealed trait Order

case class GeneralOrder(products: List[Product]) extends Order

case object CancelledOrder extends Order

case class ComplexOrder(orders: List[Order]) extends Order

sealed trait Product

case class BasicProduct(id: Int, price: BigDecimal) extends Product

case class DiscountedProduct(product: Product,

discount: Double) extends Product

case object OutOfStock extends Product

Page 195: Category theory is general abolute nonsens

Act.4: “Renaissance”

Page 196: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 197: Category theory is general abolute nonsens

Domain & Feature RequestsFeature Requests:

● Present current state of orders (JSON)● Calculate final checkout● Calculate average Order price● “Simplify” Orders

Page 198: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) { ?? }

Page 199: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) {

case (acc, o) => acc + o

}

Page 200: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) {

case (acc, o) => acc + o

}

trait Addable[A] {

def add(a1: A, a2: A): A

}

Page 201: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) {

case (acc, o) => acc + o

}

trait Addable[A] {

def add(a1: A, a2: A): A

}

implicit object OrderAddable extends Addable[Order] {

def add(o1: Order, o2: Order): Order = (o1, o2) match {

case (CancelledOrder(), o2) => o2

case (o1, CancelledOrder()) => o1

case (GeneralOrder(ps1), GeneralOrder(ps2)) => GeneralOrder(ps1 ++ ps2)

case (ComplexOrder(os1), ComplexOrder(os2)) => ComplexOrder(os1 ++ os2)

case (o1, ComplexOrder(orders)) => ComplexOrder(o1 :: orders)

case (ComplexOrder(orders), o2) => ComplexOrder(o2 :: orders)

}

}

Page 202: Category theory is general abolute nonsens

import Addable._

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) {

case (acc, o) => acc + o

}

trait Addable[A] {

def add(a1: A, a2: A): A

}

Page 203: Category theory is general abolute nonsens

import Addable._

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) {

case (acc, o) => acc + o

}

trait Addable[A] {

def add(a1: A, a2: A): A

}

object Addable {

implicit class AddableOps[A](a: A) {

def |+|(other: A)(implicit addable: Addable[A]) = addable.add(a, other)

}

}

Page 204: Category theory is general abolute nonsens

import Addable._

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) {

case (acc, o) => acc |+| o

}

trait Addable[A] {

def add(a1: A, a2: A): A

}

object Addable {

implicit class AddableOps[A](a: A) {

def |+|(other: A)(implicit addable: Addable[A]) = addable.add(a, other)

}

}

Page 205: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order =

orders.foldLeft(CancelledOrder()) {

case (acc, o) => acc |+| o

}

Page 206: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order = fold(orders)

Page 207: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order = fold(orders)

trait AddableWithZero[A] {

def zero: A

def add(a1: A, a2: A): A

}

Page 208: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order = fold(orders)

trait AddableWithZero[A] {

def zero: A

def add(a1: A, a2: A): A

}

object AddableWithZero {

def fold[A](values: Seq[A])(implicit addableWithZ: AddableWithZero[A]): A = {

values.fold(addableWithZ.zero){

case (acc, v) => addableWithZ.add(acc, v)

}

}

}

Page 209: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order = fold(orders)

trait AddableWithZero[A] {

def zero: A

def add(a1: A, a2: A): A

}

Page 210: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order = fold(orders)

trait AddableWithZero[A] {

def zero: A

def add(a1: A, a2: A): A

}

implicit object OrderAddableWithZero extends AddableWithZero[Order] {

def zero = CancelledOrder()

def add(o1: Order, o2: Order): Order = OrderAddable.add(o1,o2)

}

Page 211: Category theory is general abolute nonsens

def simplify(orders: Seq[Order]): Order = fold(orders)

trait AddableWithZero[A] {

def zero: A

def add(a1: A, a2: A): A

}

object AddableWithZero {

def fold[A](values: Seq[A])(implicit addableWithZ: AddableWithZero[A]): A = {

values.fold(addableWithZ.zero){

case (acc, v) => addableWithZ.add(acc, v)

}

}

}

Page 212: Category theory is general abolute nonsens
Page 213: Category theory is general abolute nonsens

trait Evaluate[-A, T] { def evaluate(a: A): T }

object Order {

implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] {

def evaluate(product: Product): BigDecimal = product match {

case BasicProduct(id, price) => price

case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount)

case OutOfStock() => BigDecimal("0.0")

}}

implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] {

def evaluate(order: Order): BigDecimal = order match {

case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) {

case (acc, p) => acc + ProductEvaluate.evaluate(p)

}

case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) {

case (acc, o) => acc + evaluate(o)

}

case CancelledOrder() => BigDecimal("0.0")

}}}

Page 214: Category theory is general abolute nonsens

trait Evaluate[-A, T] { def evaluate(a: A): T }

object Order {

implicit object ProductEvaluate extends Evaluate[Product, BigDecimal] {

def evaluate(product: Product): BigDecimal = product match {

case BasicProduct(id, price) => price

case DiscountedProduct(discounted, discount) => evaluate(discounted) * (1 - discount)

case OutOfStock() => BigDecimal("0.0")

}}

implicit object OrderEvaluate extends Evaluate[Order, BigDecimal] {

def evaluate(order: Order): BigDecimal = order match {

case GeneralOrder(products) => products.foldLeft(BigDecimal("0.0")) {

case (acc, p) => acc + ProductEvaluate.evaluate(p)

}

case ComplexOrder(orders) => orders.foldLeft(BigDecimal("0.0")) {

case (acc, o) => acc + evaluate(o)

}

case CancelledOrder() => BigDecimal("0.0")

}}}

Page 215: Category theory is general abolute nonsens
Page 216: Category theory is general abolute nonsens

Act.5: “Enlightenment”

Page 217: Category theory is general abolute nonsens

Research

Page 218: Category theory is general abolute nonsens

Definitions

Page 219: Category theory is general abolute nonsens

Definitions● Type classes

Page 220: Category theory is general abolute nonsens

Definitions● Type classes

○ Ad-hoc polymorphism

Page 221: Category theory is general abolute nonsens

Definitions● Type classes● Abstract Data Type (ADT)

Page 222: Category theory is general abolute nonsens

Definitions● Type classes● Abstract Data Type (ADT)● Addable → Semigroup

Page 223: Category theory is general abolute nonsens

Definitions● Type classes● Abstract Data Type (ADT)● Addable → Semigroup● AddableWithZero → Monoid

Page 224: Category theory is general abolute nonsens

Definitions● Type classes● Abstract Data Type (ADT)● Addable → Semigroup● AddableWithZero → Monoid● Type classes come with laws!

Page 225: Category theory is general abolute nonsens

Where to go next1. Functor2. Applicative3. Monad!

All are just type classes with some laws. That’s it!

Page 226: Category theory is general abolute nonsens

Before we go, a bit of history...

Page 227: Category theory is general abolute nonsens
Page 228: Category theory is general abolute nonsens

Links & Resources● https://github.com/rabbitonweb/scala_typeclasses ● https://inoio.de/blog/2014/07/19/type-class-101-semigroup/ ● http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-

part-12-type-classes.html ● https://www.youtube.com/watch?v=sVMES4RZF-8 ● http://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf● https://www.destroyallsoftware.com/misc/reject.pdf● http://southpark.cc.com/avatar ● http://www.tandemic.com/wp-content/uploads/Definition.png

Page 229: Category theory is general abolute nonsens

And that’s all folks!

Page 230: Category theory is general abolute nonsens

And that’s all folks!

Paweł Szulc

Page 231: Category theory is general abolute nonsens

And that’s all folks!

Paweł Szulc twitter: @rabbitonweb

Page 232: Category theory is general abolute nonsens

And that’s all folks!

Paweł Szulc twitter: @rabbitonweb

blog: http://rabbitonweb.com

Page 233: Category theory is general abolute nonsens

And that’s all folks!

Paweł Szulc twitter: @rabbitonweb

blog: http://rabbitonweb.com

github: https://github.com/rabbitonweb

Page 234: Category theory is general abolute nonsens

And that’s all folks!

Paweł Szulc twitter: @rabbitonweb

blog: http://rabbitonweb.com

github: https://github.com/rabbitonweb

Questions?

Page 235: Category theory is general abolute nonsens

Thank you!

Page 236: Category theory is general abolute nonsens

Thank you!Bonus?

Page 237: Category theory is general abolute nonsens

object Stat {

import Number._

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

xs.reduce(_ + _) / xs.size

}

Page 238: Category theory is general abolute nonsens

object Stat {

import Number._

def mean[A](xs: Seq[A])(implicit number: Number[A]): A =

xs.reduce(_ + _) / xs.size

}

object Stat {

import Number._

def mean[A : Number](xs: Seq[A]): A =

xs.reduce(_ + _) / xs.size

}

Page 239: Category theory is general abolute nonsens

object JsonSerializer {

def write[A](a: A)(implicit json: Json[A]) =

JsonWriter.write(json.toJson(a))

}

Page 240: Category theory is general abolute nonsens

object JsonSerializer {

def write[A](a: A)(implicit json: Json[A]) =

JsonWriter.write(json.toJson(a))

}

object JsonSerializer {

def write[A : Json](a: A) =

JsonWriter.write(implicitly[Json[A]].toJson(a))

}