1 of 55

Category Theory is not only for mathematicians

Thessaloniki, Voxxed Days 2018

2 of 55

...it is also for Software Developers!

3 of 55

~$ whoami

Thomas Kaliakos

Software Engineer

��

@tkaliakos

thomaska

λ

4 of 55

Agenda

  • History, why Category Theory is relevant
  • Interlude: Types are cool
  • Pure functions
  • What is a Category?
  • Monoid
  • Functor
  • Conclusions

5 of 55

History - Why Category Theory is relevant

6 of 55

Programming is structuring logic

- Composition

- Abstraction

7 of 55

History of programming languages popularity

  • 1940s Assembly language �
  • 1960s and 1970s "structured programming", (no use of "goto")�
  • 1980s and 1990s Object oriented languages (C++ 1980, Java 1995) �
  • Today - Increasing support for functional programming in mainstream languages used commercially

source: https://en.wikipedia.org/wiki/History_of_programming_languages#First_programming_languages

8 of 55

9 of 55

(If you remember this, probably you are not that young)

Strategy pattern in UML

10 of 55

"Science is knowledge which we understand so well that we can teach it to a computer; and if we don't fully understand something, it is an art to deal with it."�...

"Programming is the art of telling another human being what one wants the computer to do."

�Donald Knuth

11 of 55

Why not use the most well known language to communicate ideas...?

12 of 55

Maths!

13 of 55

Even in Maths there are many ways to structure logic

- Formal logic

- Type Theory

- Category Theory

14 of 55

Or maybe not?

Curry - Howard - Lambek Correspondence

�Natural deduction (logic) ~

Simply typed λ Calculus ~

Category theory

15 of 55

Curry-Howard Correspondence

16 of 55

Interlude: Types are cool!

17 of 55

Using types can be very expressive

import scala.util.Try�

def parseInt(s :String) : Try[Int] = { � Try{s.trim.toInt}�}

def parseInt (s: String): Int = {� s.trim.toInt�}

...

try {� parseInt("invalidString")�} catch {� case e: Exception => -1�}

18 of 55

Using types can be very expressive (2)

def safeHead(ss :List[String]) : Option[String] = {� ss match {� case h::t => Some(h)� case Nil => None� }�}

def safeHead(ss: List[String]): String = {� ss match {� case h::t => h� case Nil => null� }�}

19 of 55

But most importantly can help narrowing down the stuff that can go wrong

def isItWeekendYet(day: String): Boolean = { � day match {� case "Saturday" | "Sunday" => true� case _ => false� }�}

def isItWeekendYet(day: DayOfTheWeek): Boolean = {� day match {� case Saturday | Sunday => true� case _ => false� }�}

sealed trait DayOfTheWeek�case object Monday extends DayOfTheWeek� ...�case object Sunday extends DayOfTheWeek

2

27

20 of 55

But most importantly can help narrowing down the stuff that can go wrong in our program (2)

Information flow

Program 1

Test 1

Test 2

Information flow

Program 2

Types

Types

Types

Types

21 of 55

How is everything combined?

- Functional programming is about writing programs using pure functions

- Category theory gives us a way to structure (or "compose") pure functions

- Programming languages with expressive type system make it easy to materialize those abstractions

22 of 55

What is a "pure function"?

Referential Transparency:

If you replace an expression with its bound value, the result does not change

23 of 55

What is a "pure function"? (2)

val s = "low ".toUpperCase

val sTwice = s + s

// ss = LOW LOW

val s = "low ".toUpperCase

val sTwice = "low ".toUpperCase + "low ".toUpperCase

// ss = LOW LOW

24 of 55

What is a "pure function"? (3)

val it = List (1, 2, 3, 4).iterator

val next = it.next()

val res = next + next

// res = 2

val it = List (1, 2, 3, 4).iterator

val res = it.next() + it.next()

// res = 3

25 of 55

What happens with IO?

import scala.io.StdIn

val str = StdIn.readLine()

val res = str + str

// res = VoxxedVoxxed

// Stdin:�// Voxxed�// Days

import scala.io.StdIn

val res = StdIn.readLine() + StdIn.readLine()

// res = VoxxedDays

26 of 55

We can have IO in pure FP

import cats.effect.IO�import scala.io.StdIn�import cats.implicits._

val str = IO(StdIn.readLine())�val res = (str, str).mapN(_ + _)�

// In the end of the world!�// ...�res.unsafeRunSync()

// will read from stdin twice!

27 of 55

Recap

- A Side effect is something that breaks Referential transparency

- Pure Functions do not have side effects

- IO can be done in a purely functional way

- Pure FP means local reasoning, which means compositionality!

28 of 55

What is a Category?

29 of 55

Category

_.toString()

_.toString() compose _ == "2"

Int

String

Boolean

_ == "2"

Option(_)

Option[String]

30 of 55

Category (2)

a

b

d

c

Category C

  • Objects�
  • Arrows

31 of 55

Category (3)

a

b

d

c

Category C

  • Identity
  • Composition

f

ida

g o f

g

idc

idb

idd

h o f

h

32 of 55

Category (4)

a

b

d

c

  • Identity

ida o f = f o ida= f��

  • (associative) Composition

(f o g) o h = f o (g o h) = f o g o h

Category C

f

ida

h o g

g

idc

idb

idd

h

g o f

h o g o f

33 of 55

Category (5)

Category of Types and Functions

  • Identity

def id[A](a:A) = a�

  • Composition�f compose g

_.toString()

ida

_.toString() compose _ == "2"

idc

idb

idd

Int

String

Boolean

_ == "2"

Option(_)

Option[String]

34 of 55

Monoid?

35 of 55

Is there a pattern here?

- String concatenation: "str1" + "str2" + "str2"

and the empty string ("")

- Integer addition: 1 + 2 + 4�and number zero (0)�

- Integer multiplication: 1 * 2 * 4�and number one (1)

- List concatenation: List(1, 2) ++ List(3, 4) ++ List(5,6)�and the empty list (Nil)

36 of 55

Monoid (2)

In Set theory:

- A set �

- An associative binary operator � (eg "+")

- A Unit (identity - eg "0")

2

9

0

7

4

8

37 of 55

Monoid (3)

a

ida

  • Category with only one element

f

g

38 of 55

Monoid (4)

+0

+4

+2

Int

  • Identity

id(a) = a + 0�

  • Composition�f o g => 4 + 2 = 6 �+6 is also part of the Int Monoid's arrows!

+6

39 of 55

Monoid (5)

trait Monoid[A] {� val id: A

def compose(a: A, b: A) : A

}

val intMonoid = new Monoid[Int] {

val id = 0

def compose(a: Int, b: Int): Int = a + b

}

40 of 55

Monoid (6)

You have definitely seen them!

val listSum = List(1, 2, 3, 4).fold(0)((a,b) => a + b)

def foldNew[A](list: List[A], m:Monoid[A]): A = { � list match => {� case Nil => m.id� case h::t => m.compose(h, foldNew(t, m))

}

}

41 of 55

Monoid (7)

case class Crate(weight: Int, canBeStacked: Boolean)

val crateMonoid = new Monoid[Crate] {

override val id = Crate(0, true)

override def compose(a: Crate, b: Crate) = {

Crate(a.weight + b.weight,

a.canBeStacked && b.canBeStacked)

}

}

42 of 55

Functors!

43 of 55

Adding "context" into an existing type

Context ��Type

Something might be or not be there

Something we might get in the future

Something might have exploded or not

Boolean

Option[Boolean]

Future[Boolean]

Try[Boolean]

Integer

Option[Integer]

Future[Integer]

Try[Integer]

String

Option[String]

Future[String]

Try[String]

44 of 55

How do we use all this functions when we use a "Container"

�def stringLength(str: String): Int = str.length

def isEven(num: Int): Boolean = num % 2 == 0

def toString(num: Int): String = num.toString

45 of 55

With map!

Functors are essentially type constructors!

�trait Functor[F[_]] {

def map[A, B] (f: A=>B) (v: F[A]) => F[B]

}

46 of 55

Functors

"A mapping between categories that preserves structure"

a

b

idb

ida

idFb

idFa

D

C

Ff

f

Fb

Fa

F

47 of 55

Functors (2)

a

b

idb

ida

idFb

idFa

D

C

Ff

f

The laws must be satisfied here too!

F(f o g) = Ff o Fg

F id = id F�

Fb

Fa

48 of 55

Functors (3)

a

b

idb

ida

idFb

idFa

D

C

_.map(_.toString)

_.toString

Int

String

ListF

List[Int]

List[String]

Fb

Fa

49 of 55

Conclusions

- Develop deep intuitions about abstractions

- Powerful vocabulary to communicate

- Takes time to built

- See how algebraic structures relate to each other

50 of 55

Where to go next? (1)

51 of 55

Where to go next? (2)

  • A Pragmatic Introduction to Category Theory - Daniela Sfregola

https://www.youtube.com/watch?v=Ss149MsZluI

  • Functional Programming in Scala, book�https://www.manning.com/books/functional-programming-in-scala�
  • Scala with Cats, book �https://underscore.io/books/scala-with-cats/
  • Compose your program flow with Stream - Fabio Labella

https://www.youtube.com/watch?v=x3GLwl1FxcA

52 of 55

We 're hiring!

https://www.ovoenergy.com/careers/vacancies

53 of 55

Special mention

54 of 55

This is a job for...

55 of 55

Thank you!

Questions?