37
THE ORIGINS OF FREE Adam Warski, SoftwareMill 27 May 2017, LambdaConf

Origins of Free

Embed Size (px)

Citation preview

Page 1: Origins of Free

THE ORIGINS OF FREEAdam Warski, SoftwareMill 27 May 2017, LambdaConf

Page 2: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

THE PLAN

➤ Why bother?

➤ Universal algebra

➤ Free algebras

➤ The meaning of life free

➤ Monads & free monads

➤ Free monads in Haskell, Cats and Scalaz

➤ It’s simpler than it sounds

Page 3: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

WHY BOTHER WITH FREE?

➤ Free monads:

➤ programs as values

➤ separate definition from interpretation

➤ testing

➤ composability

➤ use a high-level language

➤ hide low-level concerns

Page 4: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

WHAT IS AN ALGEBRA?

“algebra is the study of mathematical symbols and the rules for manipulating these symbols" Wikipedia, 2017

“the part of mathematics in which letters and other general symbols are used to represent numbers and quantities in formulae and equations."

Google Search, 2017

y = ax + b

E = mc2

f(10◊x) = K(▸9)def sum(l: List[L]) = l.fold(_ + _)

main = getCurrentTime >>= print

Page 5: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

UNIVERSAL ALGEBRA: SIGNATURE

➤ Goal: Model programs as algebras

➤ Let’s generalise!

➤ Studies algebraic structures, rather than concrete models

algebraic signature ⌃ = (S,⌦)

set S

family ⌦ of sets indexed by S⇤ ⇥ S

➤ Syntax:

➤ type names:

➤ operation names:

Page 6: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

UNIVERSAL ALGEBRA: SIGNATURE EXAMPLE

toString(succ(0) + succ(succ(0)))

S = {int, str}⌦✏,int = {0}⌦int,int = {succ}⌦(int,int),int = {+}⌦(str,str),str = {++}⌦int,str = {toString}

Page 7: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

UNIVERSAL ALGEBRA: SIGNATURE EXAMPLE

S = {v}⌦✏,v = {1}⌦(v,v),v = {⇤}

(1 ⇤ 1) ⇤ (1 ⇤ (1 ⇤ 1))

Page 8: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

UNIVERSAL ALGEBRA: ALGEBRA

➤ A specific interpretation of the signature

➤ for each type, a set

➤ for each operation, a function between appropriate sets⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

We can define a ⌃-algebra A:

|A|int = {0, 1, 2, ...} = N|A|str = {”a”, ”aa”, ..., ”b”, ”ab”, ...}

succA = �x.x+ 1+A = �xy.x+ y

. . .

Page 9: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

UNIVERSAL ALGEBRA: ALGEBRA

➤ As a side-note, F-algebras:are a generalisation of single-sorted algebras presented here

type Algebra[F[_], A] = F[A] => A

// or

type Algebra f a = f a -> a

Page 10: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

TERM ALGEBRA

➤ Can we build an algebra out of pure syntax?

➤ Expressions (terms) that can be built from the signature

➤ Rather boring, no interpretation at all

|T⌃|int = {0, succ(0), succ(succ(0)), ..., 0 + 0, 0 + succ(0), ...}|T⌃|str = {toString(0), toString(succ(0)), ..., toString(0)++toString(0), ...}

succT⌃(t) = succ(t), e.g. succT⌃(succ(0)) = succ(succ(0))+T⌃(t1, t2) = t1 + t2...

⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

We define the term algebra T⌃:

Page 11: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

TERM ALGEBRA

➤ Defined inductively

➤ base: all constants are terms

➤ step: any functions we can apply on previous terms

⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

{0}{0, 0 + 0, succ(0), toString(0)}{0, 0 + 0, succ(0), 0 + succ(0), succ(0) + 0, succ(0) + succ(0),toString(0), toString(succ(0)), toString(0) + +toString(0)}

Page 12: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

TERM ALGEBRA

⌃ = (S,⌦), S = {v} and ⌦ = {1, ⇤}

1, 1 ⇤ 1, (1 ⇤ 1) ⇤ 1, 1 ⇤ (1 ⇤ 1), 1 ⇤ ((1 ⇤ 1) ⇤ 1), ...

Page 13: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

HOMOMORPHISM

➤ Homomorphism is a function between algebras

➤ For each type, functions between type interpretations

➤ Such that operations are preserved

⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

When A and B are ⌃-algebras, f : A ! B is a homomorphism when:

fint : |A|int ! |B|intfstr : |A|str ! |B|str

8x2|A|int

f

int

(succA

(x)) = succ

B

(fint

(x))8xy2|A|int

f(x+A

y) = f(x) +B

f(y)8x2|A|int

f

str

(toStringA

(x)) = toString

B

(fint

(x))

Page 14: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

INITIAL ALGEBRA

Theorem 1 T⌃ is initial

⌃-algebra I is initial when for any other

⌃-algebra A there is exactly one

homomorphism from I to A.

Page 15: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

INITIAL ALGEBRA

Theorem 1 T⌃ is initial

⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

|A|int = {0, 1, 2, ...} = N|A|str = {”a”, ”aa”, ..., ”b”, ”ab”, ...}

succA = �x.x+ 1+A = �xy.x+ y

. . .

We can define a ⌃-algebra A:

f : T⌃ ! A

f(0T⌃) = 0Af(succT⌃(t)) = succA(f(t))...

Page 16: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

INITIAL ALGEBRA

➤ Only one way to interpret a term

➤ no junk: term algebra contains only what’s absolutely necessary

➤ no confusion: no two values are combined if they don’t need to be

➤ There’s only one initial algebra (up to isomorphism)

⌃-algebra I is initial when for any other

⌃-algebra A there is exactly one

homomorphism between them.

Theorem 1 T⌃ is initial

Page 17: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

INITIAL ALGEBRA

➤ This algebra is definitely not initial:

⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

➤ Junk: strings “a”, “b”, …

➤ Confusion: 0+succ(0) is same as succ(0)+0

We can define a ⌃-algebra A:

|A|int = {0, 1, 2, ...} = N|A|str = {”a”, ”aa”, ..., ”b”, ”ab”, ...}

Page 18: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

TERMS WITH VARIABLES

For any set X, T⌃(X) is the term algebra with X added as ”constants”

(but called variables)

⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

Xint = {i, j, k}Xstr = {s1, s2}

succ(i) + j + succ(succ(k))s1 ++toString(0)toString(succ(0) + k) + +s2

Page 19: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

TERMS WITH VARIABLES

For any set X, T⌃(X) is the term algebra with X added as ”constants”

(but called variables)

⌃ = (S,⌦), S = {v} and ⌦ = {1, ⇤}

Xv = {x, y, z, ...}

1 ⇤ xx ⇤ (y ⇤ z)(x ⇤ y) ⇤ z)(x ⇤ 1) ⇤ (y ⇤ (1 ⇤ 1))

Page 20: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE ALGEBRA

➤ An interpretation of the variables determines an interpretation of any term

Theorem 1 For any variable set X, T⌃(X) is free

For any set X, T⌃(X) is the term algebra with X added as ”constants”

(but called variables)

⌃-algebra I is free over X (X ⇢ I) when for any other

⌃-algebra A, any function f : X ! |A| extends uniquely

to a homomorphism f#: I ! A between them.

Page 21: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE ALGEBRA EXAMPLE⌃ = (S,⌦), S = {int, str} and ⌦ = {0, succ,+,++, toString}

Xint = {i, j, k}Xstr = {s1, s2}|A|int = N, |A|str = {”a”, ”aa”, ..., ”b”, ”ab”, ...}

succA = �x.x+ 1+A = �xy.x+ y

. . .

f : X ! |A|f(i) = 10, f(j) = 5, f(k) = 42f(s1) = ”lambda”, f(s2) = ”conf”

f

# : T⌃(X) ! A

f

#(toString(succ(j) + succ(0)) + +s1) = ”7lambda”f

#(s2 ++toString(k) + +s2) = ”lambda42conf”

Page 22: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

MEANING OF FREE

➤ Free to interpret in any way

➤ no constraints

➤ Free of additional structure

➤ only what’s absolutely necessary

➤ No junk, no confusion

Page 23: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

ALGEBRAS WITH EQUATIONS

➤ Let’s add constraints on interpretations of a signature

➤ that is, on the algebras

�➤ And let’s focus only algebras satisfying a set of equations

⌃-equation: 8X.t = t0

X: variables, with sorts

t, t0 2 T⌃(X): terms with these variables

➤ Equations:

Page 24: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

ALGEBRAS WITH EQUATIONS

⌃ = (S,⌦), S = {v} and ⌦ = {1, ⇤}

8{x, y, z}x ⇤ (y ⇤ z) = (x ⇤ y) ⇤ z8{x}x ⇤ 1 = x

8{x}1 ⇤ x = x

� :

Page 25: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

TERM ALGEBRAS WITH EQUATIONS

➤ usually doesn’t satisfy the equations

➤ Some terms need to be “combined”

➤ Equivalence relation generated by

➤ Instead of terms, sets of terms

➤ equivalent wrt equations from

T⌃(X)

�: ⌘�

Page 26: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

TERM ALGEBRAS WITH EQUATIONS

⌃ = (S,⌦), S = {v} and ⌦ = {1, ⇤}

8{x, y, z}x ⇤ (y ⇤ z) = (x ⇤ y) ⇤ z8{x}x ⇤ 1 = x

8{x}1 ⇤ x = x

� :

T⌃(X)/ ⌘�: {1}{x, x ⇤ 1, 1 ⇤ x}{x ⇤ (y ⇤ z), (x ⇤ y) ⇤ z, (1 ⇤ x) ⇤ (y ⇤ z), 1 ⇤ (x ⇤ (y ⇤ z)), ...}

Page 27: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE ALGEBRAS WITH EQUATIONS

Theorem 1 For any variable set X and equations �, T⌃(X)/ ⌘� is free in the

class of algebras satisfying �

➤ Homomorphism to any other algebra

➤ how to interpret a set of terms?

➤ interpret any of them

Page 28: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE ALGEBRAS WITH EQUATIONS

⌃ = (S,⌦), S = {v} and ⌦ = {1, ⇤}

8{x, y, z}x ⇤ (y ⇤ z) = (x ⇤ y) ⇤ z8{x}x ⇤ 1 = x

8{x}1 ⇤ x = x

� :

T⌃(X)/ ⌘�: {1}{x, x ⇤ 1, 1 ⇤ x}{x ⇤ (y ⇤ z), (x ⇤ y) ⇤ z, (1 ⇤ x) ⇤ (y ⇤ z), 1 ⇤ (x ⇤ (y ⇤ z)), ...}

➤ Is there a simpler representation?[][x][x, y, z]

Page 29: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE RECAP

➤ Algebraic signature:

➤ All possible interpretations: algebras

➤ For any variable set

➤ The term algebra is free

➤ any interpretation of the variables

➤ determines an interpretation of any term

➤ A general construction

⌃ = (S,⌦)

X

T⌃(X)

f : X ! |A|

f# : T⌃(X) ! A

Page 30: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

MODELLING SEQUENTIAL PROGRAMS: MONADS

➤ A sequential program can:

➤ return a value (pure)

➤ compute what to do next basing on previous result (flatMap)

➤ People decided to call an object with such operations a Monad

➤ Hence, we’ll use Monads to represent programs as data

➤ + sanity laws

Page 31: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE MONAD

➤ Signature ~ pure + flatMap

➤ Variables ~ operations (our DSL)

➤ Free Monad ~ terms built out of pure, flatMap, our DSL

➤ modulo monad laws!

➤ e.g. flatMap(pure(x), f) = f(x)

Interpretation of the DSL determines the interpretation of the whole program

Page 32: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE IN CATS/SCALAZ

trait Free[F[_], A] object Free { case class Pure[F[_], A](a: A) extends Free[F, A] case class Suspend[F[_], A](a: F[A]) extends Free[F, A] case class FlatMapped[F[_], B, C]( c: Free[F, C], f: C => Free[F, B]) extends Free[F, B] }

Page 33: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FREE IN HASKELL

data Free f r = Free (f (Free f r)) | Pure r

trait Free[F[_], A] object Free { case class Pure[F[_], A](a: A) extends Free[F, A] case class Join[F[_], A](f: F[Free[F, A]]) extends Free[S, A] }

f/F[_] must be a functor!

Page 34: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

SUMMING UP

➤ Direct construction of free algebras

➤ Hand-wavy construction of free monad

➤ Free

➤ free to interpret in any way

➤ free of constraints

➤ no junk, no confusion

➤ Free in Haskell is the same free as in Scala

Page 35: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

ABOUT ME

➤ Software Engineer, co-founder @

➤ Custom software development; Scala/Java/Kafka/Cassandra/…

➤ Open-source: Quicklens, MacWire, ElasticMQ, ScalaClippy, …

➤ Long time ago: student of Category Theory

Page 36: Origins of Free

@adamwarski, SoftwareMill, LambdaConf 2017

FURTHER READING

➤ “Foundations of Algebraic Specification and Formal Software Development” by Donald Sannella and Andrzej Tarlecki

➤ The Internet

Page 37: Origins of Free

THANK YOU!