# data types

Alexander Konovalov, Compellon Inc

alex.knvl@gmail.com @alexknvl

# The goal

• Briefly go over type isomorphisms and type algebra.
• Show the connection between final tagless, "initial encoding", and recursion schemes.
• Brief introduction to Free monads.
• Show the connection between Free monads, MTL, and Final Tagless.

final tagless、initial encoding、再帰スキームのつながりを証明する

Free モナド、MTL、final tagless のつながりを証明する

## Isomorphisms

​A and B are isomorphic when there exist two morphisms,

to: A → B and from: B → A, such that both

from (to a) = a

and

to (from b) = b

## Type Isomorphisms

Can't be faithfully implemented except in Dependently typed languages (Idris, Agda, Coq).

trait Iso[A, B] {
def to(a: A): B
def from(b: B): A
def fromTo(x: A): (from(to(x))).type =:= x.type
def toFrom(x: B): (to(from(x))).type =:= x.type
}

Iso を忠実に型で表現するには依存型言語が要る

trait Iso[A, B] {
def to(a: A): B
def from(b: B): A

// make sure that (to andThen from) == id
// and (from andThen to) == id
}

So let's just manually check the necessary laws.

type A = Either[Boolean, Unit]
sealed trait B
case object One extends B
case object Two extends B
case object Three extends B

Are these isomorphic?

def to(a: A): B = a match {
case Left(true)  => One
case Left(false) => Two
case Right(())   => Three
}

def from(b: B): A = b match {
case One   => Left(true)
case Two   => Left(false)
case Three => Right(())
}

Yes, here is an isomorphism:

type A = Boolean => Boolean
sealed trait B
case object One   extends B
case object Two   extends B
case object Three extends B
case object Four  extends B

Are these isomorphic?

Conceptually, a function A ⇒ B can be represented as a tuple (B, B, ...) ("A" times)

A ⇒ B 関数は「A回」続く (B, B, ...) というタプルで表現できる

def to(f: A): B = (f(true), f(false)) match {
case (false, false) => One
case (false, true)  => Two
case (true,  true)   => Three
case (true,  true)   => Four
}

def from(b: B): A = b match {
case One   => x => if (x) false else false
case Two   => x => if (x) false else true
case Three => x => if (x) true  else true
case Four  => x => if (x) true  else true
}

Yes.

そうだ

type A = Boolean => Unit
type B = Nothing => Int
type C = Unit

Are these isomorphic?

Consider the "tuple representation" of the above two functions.

One is a tuple of two units,

and the other is an empty tuple of ints.

def to(f: Boolean => Unit): Nothing => Int =
(a: Nothing) => a
def from(f: Nothing => Int): Boolean => Unit =
(a: Boolean) => ()

def to(f: Nothing => Int): Unit = ()
def from(f: Unit): Nothing => Int =
(a: Nothing) => a

But if we construct the necessary functions...

We don't seem to be really using the arguments!

Is there some other way to understand what is going on?

しかし、実際に必要な関数を作ってみると...

## A surprising detour

• When are two things equal?

1729

12³+1

"the first number expressible as a sum of two cubes in two different ways"

• When are two things equal?

2つのものが等しいのは、どういうときだろう?

1729、「2組の異なる 2つの3乗数の和として表すことができる最初の数」

Gottfried Wilhelm Leibniz, 1646-1716:

For any x and y, if x is identical to y, then x and y have all the same properties.

For any x and y, if x and y have all the same properties, then x is identical to y.

x と y が同一ならば、x と y は全ての属性が同じである

x と y の全ての属性が同じならば、x と y は同一である

x = y ⟺ ∀ P. P x ↔ P y

Where P is quantified over all properties of an object.

ここで P はあるオブジェクトの全ての属性によって量化される

x = y ⟺ ∀ P. P x ↔ P y

If 1729 and 12³+1 are expressions, they are different.

sealed trait Expr
case class Lit(i: Int) extends Expr
case class Pow(a: Int, b: Int) extends Expr
case class Add(a: Int, b: Int) extends Expr

val x = Lit(1729)
val y = Add(Pow(12, 3), 1)

これらを式で表すと、別物の扱いとなる

x = y ⟺ ∀ P. P x ↔ P y

If 1729 and 12³+1 are integers, they are the same.

type Expr = Int

val x = 1729
val y = 12 * 12 * 12 + 1

これらを整数で表すと、同じものとなる

## Type Isomorphisms

type A = Boolean => Unit
type B = Nothing => Int

def to(f: Boolean => Unit): Nothing => Int =
(a: Nothing) => a
def from(f: Nothing => Int): Boolean => Unit =
(a: Boolean) => ()

Are these isomorphic?

A と B は同型だろうか?

def property(f: Boolean => Unit): Boolean = ???

property { _ => () }
property { case true => ()
case false => () }

def property(f: Nothing => Int): Boolean = ???

property(_ => 1)
property(_ => 2)
property(x => x)

What properties of them can we observe?

None!

どんな属性か観測できますか？

We can't see the difference of them

as values within a pure functional language.

We can see the difference between

the actual expression trees.

We don't really care about the latter as since it does not affect the semantics.

どんな属性か観測できますか？

type A = Boolean => Unit
type B = Nothing => Int

def to(f: Boolean => Unit): Nothing => Int =
(a: Nothing) => a
def from(f: Nothing => Int): Boolean => Unit =
(a: Boolean) => ()

So are these isomorphic? Yes, both from the counting perspective, and from the Identity of Indiscernibles argument.

An interesting result:

If A and B are isomorphic,
(a₁: A) and (a₂: A) map to (b₁: A) and (b₂: A) respectively,
then a₁ = a₂ ⟺ b₁ = b₂.

In other words, discernible objects are mapped to discernible objects.

Equal objects are mapped to equal objects.

If A and B are isomorphic,
(a₁: A) and (a₂: A) map to (b₁: A) and (b₂: A) respectively,
then a₁ = a₂ ⟺ b₁ = b₂.

a₁ = a₂

to a₁ = to a₂

b₁ = b₂

from b₁ = from b₂

## Type Algebra

A few more important isomorphisms:

(a, b) ≈ (b, a)
(a, (b, c)) ≈ ((a, b), c)
(a, Either[b, c]) ≈ Either[(a, b), (a, c)]
Either[a, b] ≈ Either[b, a]
Either[Nothing, a] ≈ a
(Unit, a) ≈ a

(a, b) ≈ (b, a)
(a, (b, c)) ≈ ((a, b), c)
(a, Either[b, c]) ≈ Either[(a, b), (a, c)]
Either[a, b] ≈ Either[b, a]
Either[Nothing, a] ≈ a
(Unit, a) ≈ a

What if we replace Either with +, (,) with *, Unit with 1, and Nothing with 0?..

Either を和、タプルを積、Unit を 1、Nothing を 0 と置き換える

(a, b) ≈ (b, a)
(a, (b, c)) ≈ ((a, b), c)
(a, Either[b, c]) ≈ Either[(a, b), (a, c)]
Either[a, b] ≈ Either[b, a]
Either[Nothing, a] ≈ a
(Unit, a) ≈ a

a * b ≈ b * a
a * (b * c) ≈ (a * b) * c
a * (b + c) ≈ a * b + a * c
a + b ≈ b + a
0 + a ≈ a
1 * a ≈ a

Amusingly, we get something very similar to the regular algebra of natural numbers...

(a + b) c ≈ (a c, b c)
a b c ≈ (a, b) c

def curry[A, B, C](f: A => B => C): ((A, B)) => C =
{ case (a, b) => f(a)(b) }

def uncurry[A, B, C](f: ((A, B)) => C): A => B => C =
a => b => f((a, b))

def undiag[A, B, C](f: Either[A, B] => C): (A => C, B => C) =
(a => f(Left(a)), b => f(Right(b)))

def diag[A, B, C](f: (A => C, B => C)): Either[A, B] => C =
{ case Left(a)  => f._1(a)
case Right(b) => f._2(b) }

A couple very important results about functions:

(a + b) c ≈ (a c, b c)
a b c ≈ (a, b) c

c^(a + b) ≈ c^a * c^b
(c^b)^a ≈ c ^ (a * b)

Turns out that similarly to how Either is + and (,) is *, functions correspond to exponentiation:

## Type Algebra

Summing it all up:

Either[a, b] is +

Tuple2[a, b] or (a, b) is A * B

Function1[a, b] or (a → b) is b ^ a

Nothing is 0

Unit is 1

Bool is 2

One more important theorem that we will need.

a ≈ b, then f a ≈ f b for any functor f

Including phantom, covariant, contravariant, or invariant functors.

phantom, covariant など変化球ファンクターなどでも成り立つ

a ≈ b, then f a ≈ f b for any functor f

to' = map to

from' = map from

map to . map from =

map (to . from) = map id = id

## Just one more thing

We will be using the following type synonym to save some horizontal space:

type ⊥ = Nothing

ページの都合上 ⊥ をもって Nothing とする

## Let's talk recursion

Say we have a data type

sealed trait List[+A]
case object  Nil                             extends List[⊥]
case class   Cons[A](head: A, tail: List[A]) extends List[A]
def foldr[A, Z](this: List[A])(seed: Z)(combine: (A, Z) => Z): Z =
this match {
case Nil        => seed
case Cons(h, t) => combine(h, t.foldr(seed)(combine))
}

and we would like to fold over it

sealed trait List[+A]
case object  Nil                             extends List[⊥]
case class   Cons[A](head: A, tail: List[A]) extends List[A]

def foldr[A, Z](this: List[A])(seed: Z)(combine: (A, Z) => Z): Z =
this match {
case Nil        => seed
case Cons(h, t) => combine(h, t.foldr(seed)(combine))
}

Why do we want fold?

Turns out that every function on list can be written in terms of foldr!

def sum(list: List[Int]): Int =
foldr(list)(0)(_ + _)
def map[A, B](list: List[A])(f: A => B): List[B] =
foldr(list)(Nil)((h, t) => Cons(f(h), t))
def isEmpty[A](list: List[A]): Boolean =
foldr(list)(true)((_, _) => false)

リストの全ての関数は foldr で表現できる!

Let's look at a slightly more realistic example:

sealed trait Expr
case class Lit(i: Int)           extends Expr
case class Add(l: Expr, r: Expr) extends Expr
case class Mul(l: Expr, r: Expr) extends Expr

def foldr[Z](this: Expr)(lit: Int => Z)(add: (Z, Z) => Z)(mul: (Z, Z) => Z): Z =
this match {
case Lit(i)    => lit(i)
}

We can reinterpret our expressions in different ways:

val expr = Mul(Lit(3), Add(Lit(2), Lit(3))

def eval(expr: Expr): Int =
foldr(expr)(i => i)(_ + _)(_ * _)
val res = eval(expr) // 3 * (2 + 3) = 15

def print(expr: Expr): String =
foldr(expr)(i => i.toString)((l, r) => s"($l +$r)")((l, r) => s"($l *$r)")
val str = print(expr) // "(3 * (2 + 3))"

もう少し現実的な例を見てみよう

\forall z. \text{Expr} \rightarrow (Int \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow z
def foldr[Z](this: Expr)(lit: Int => Z)(add: (Z, Z) => Z)(mul: (Z, Z) => Z): Z =
this match {
case Lit(i)    => lit(i)
}

Let's look at the type of foldr:

\forall z. \text{Expr} \rightarrow ((Int + (z, z) + (z, z)) \rightarrow z) \rightarrow z

Let's combine the arguments together:

There are two important concepts here, an algebra, and a pattern/signature functor.

foldrの型について

## Let's talk algebras

In mathematics, and more specifically in abstract algebra, an algebraic structure on a set A (called carrier set or underlying set) is a collection of finitary operations on A; the set A with this structure is also called an algebra.

In mathematics, specifically in category theory, F-algebras generalize algebraic structure. Rewriting the algebraic laws in terms of morphisms eliminates all references to quantified elements from the axioms, and these algebraic laws may then be glued together in terms of a single functor F, the signature.

## Let's talk algebras

\mathfrak{F} c \rightarrow c ~~~ - ~~~ \text{an }\mathfrak{F}\text{-algebra}
\mathfrak{F} - \text{is called a signature, or pattern functor} \\ c - \text{is called a carrier}
type Algebra[F[_], C] = F[C] => C
def foldr[Z](this: Expr)(lit: Int => Z)(add: (Z, Z) => Z)(mul: (Z, Z) => Z): Z =
this match {
case Lit(i)    => lit(i)
}
\forall z. \text{Expr} \rightarrow ((Int + (z, z) + (z, z)) \rightarrow z) \rightarrow z
sealed trait ExprF[+Z]
case class LitF(i: Int)        extends ExprF[⊥]
case class AddF[Z](l: Z, r: Z) extends ExprF[Z]
case class MulF[Z](l: Z, r: Z) extends ExprF[Z]

\forall z. \text{Expr} \rightarrow (\text{ExprF}~z \rightarrow z) \rightarrow z

Let's define the signature functor.

ファンクターのシグネチャを定義しよう

def foldRS[A, Z](algebra: ExprF[Z] => Z): Z =
this match {
case Lit(i)    => algebra(LitF(i))
case Mul(l, r) => algebra(MulF(foldRS(l)(algebra), foldRS(r)(algebra)))
}
sealed trait ExprF[+Z]
case class LitF(i: Int)        extends ExprF[⊥]
case class AddF[Z](l: Z, r: Z) extends ExprF[Z]
case class MulF[Z](l: Z, r: Z) extends ExprF[Z]

\forall z. \text{Expr} \rightarrow (\text{ExprF}~z \rightarrow z) \rightarrow z

We have arrived at Recursion Schemes.

## Let's talk Recursion Schemes

\begin{aligned} \text{Expr} &= \text{Lit}~\text{Int} | &\text{Add}~ &\text{Expr} &\text{Expr} &| &\text{Mul}~ &\text{Expr} &\text{Expr} \\ \text{ExprF} \bullet &= \text{Lit}~\text{Int} | &\text{Add} &~~~\bullet &\bullet~~~ &| &\text{Mul} &~~~\bullet &\bullet~~~ \end{aligned}

ExprF represents one layer of the Expr tree.

Here's another way to look at signature functors:

def project(expr: Expr): ExprF[Expr] = expr match {
case Lit(i)    => LitF(i)
case Mul(x, y) => MulF(x, y)
}

def embed(expr: ExprF[Expr]): Expr = expr match {
case LitF(i)    => Lit(i)
case MulF(x, y) => Mul(x, y)
}
def foldRS[Z](this: Expr)(algebra: ExprF[Z] => Z): Z =
this match {
case Lit(i)    => algebra(LitF(i))
case Mul(l, r) => algebra(MulF(l.foldRS(algebra), r.foldRS(algebra)))
}

We can use these to rewrite

as

def foldRS[Z](this: Expr)(algebra: ExprF[Z] => Z): Z =
algebra(project(this).map(subtree => foldRS(subtree)(algebra)))

とこうなる

trait Recursive[T, F[_]] extends Functor[F] {
def project(t: T): F[T]
def cata[Z](t: T)(algebra: F[Z] => Z): Z =
algebra(project(t).map(cata(_)(algebra)))
}

new Recursive[Expr, ExprF] {
def map[A, B](e: ExprF[A])(f: A => B): ExprF[B] = ...
def project(t: Expr): ExprF[Expr] = ...
}

We can further generalize this idea of extracting one layer of a recursive data structure at a time.

This is the basis of Recursion Schemes.

ファンクターは再帰的なデータ構造を一度に一つの層に抽出する考えに一般化出来る

val expr = Mul(Lit(3), Add(Lit(2), Lit(3))

val evalAlg: ExprF[Int] => Int = {
case LitF(i)    => i
case AddF(l, r) => l + r
case MulF(l, r) => l * r
}
val res = foldRS(expr)(evalAlg) // 3 * (2 + 3) = 15

val printAlg: ExprF[String] => String = {
case LitF(i)    => i.toString
case AddF(l, r) => s"($l +$r)"
case MulF(l, r) => s"($l *$r)"
}
val str = foldRS(expr)(printAlg) // "(3 * (2 + 3))"

We can use the new foldRS to reinterpret expressions the same way we could with foldr.

foldrと同じようにfoldRSを再解釈式に利用できる

Alright, let's go back to our types again:

What if instead of extracting a pattern functor, we extract the algebra?

\forall z. \text{Expr} \rightarrow (Int \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow z
\forall z. \text{Expr} \rightarrow ((Int + (z, z) + (z, z)) \rightarrow z) \rightarrow z
\forall z. \text{Expr} \rightarrow (Int \rightarrow z, (z, z) \rightarrow z, (z, z) \rightarrow z) \rightarrow z

ファンクターの抽出パターンに置き換えるなら、代数を抽出出来るか

What if instead of extracting a pattern functor, we extract the algebra?

trait ExprA[Z] {
def lit(i: Int): Z
def add(l: Z, r: Z): Z
def mul(l: Z, r: Z): Z
}
\forall z. \text{Expr} \rightarrow (Int \rightarrow z, (z, z) \rightarrow z, (z, z) \rightarrow z) \rightarrow z
∀ z. \text{Expr} \rightarrow \text{ExprA}~z \rightarrow z
def foldAlg(expr: Expr)(algebra: ExprA[Z]): Z = expr match {
case Lit(i)    => algebra.lit(i)
case Mul(l, r) => algebra.mul(foldAlg(l)(algebra), foldAlg(r)(algebra))
}

ファンクターの抽出パターンに置き換えるなら、代数を抽出出来るか

val expr = Mul(Lit(3), Add(Lit(2), Lit(3))

val evalAlg: ExprA[Int] = new ExprA[Int] {
def lit(i: Int): Int = i
def add(l: Int, r: Int): Int = l + r
def mul(l: Int, r: Int): Int = l * r
}
val res = foldAlg(expr)(evalAlg) // 3 * (2 + 3) = 15

val printAlg: ExprA[String] = new ExprA[String] {
def lit(i: Int): String = i.toString
def add(l: String, r: String): Int = s"($l +$r)"
def mul(l: String, r: String): Int = s"($l *$r)"
}
val str = foldAlg(expr)(printAlg) // "(3 * (2 + 3))"

We can use the new foldAlg to reinterpret expressions the same way we could with foldr and foldRS

This is the basis of Final Tagless, except usually ExprA is a typeclass.

foldrやfoldRSと同じようにfoldAlgを再解釈式に利用できる

trait ExprC[Z] {
def lit(i: Int): Z
def add(l: Z, r: Z): Z
def mul(l: Z, r: Z): Z
}

def lit[Z](i: Int)(implicit Z: ExprC[Z]): Z = Z.lit(i)
def mul[Z](l: Z, r: Z)(implicit Z: ExprC[Z]): Z = Z.mul(l, r)
def foldFT[Z: ExprC](expr: Expr): Z = expr match {
case Lit(i)    => lit(i)
case Mul(l, r) => mul(foldFT(l), foldFT(r))
}

Rewriting foldAlg using a typeclass

val expr = Mul(Lit(3), Add(Lit(2), Lit(3))

implicit val evalAlg: ExprC[Int] = new ExprC[Int] {
def lit(i: Int): Int = i
def add(l: Int, r: Int): Int = l + r
def mul(l: Int, r: Int): Int = l * r
}
val res = foldFT[Int](expr) // 3 * (2 + 3) = 15

implicit val printAlg: ExprC[String] = new ExprC[String] {
def lit(i: Int): String = i.toString
def add(l: String, r: String): Int = s"($l +$r)"
def mul(l: String, r: String): Int = s"($l *$r)"
}
val str = foldFT[String](expr) // "(3 * (2 + 3))"

We can use the new foldFT to reinterpret expressions the same way we could with foldr, foldRS, and foldAlg.

foldrやfoldRS、foldAlgと同じようにfoldFTを再解釈式に利用できる

Let's see all of the derived functions

def foldr  [Z](expr: Expr)(lit: Int => Z)(add: (Z, Z) => Z)(mul: (Z, Z) => Z): Z

def foldRS [Z](expr: Expr)(         algebra: ExprF[Z] => Z): Z
def foldAlg[Z](expr: Expr)(         algebra: ExprA[Z]     ): Z
def foldFT [Z](expr: Expr)(implicit algebra: ExprC[Z]     ): Z

Simply by transforming a function type we have arrived at Recursion Schemes and Final Tagless.

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

sealed trait ExprF[+Z]
case class LitF(i: Int)        extends ExprF[⊥]
case class AddF[Z](l: Z, r: Z) extends ExprF[Z]
case class MulF[Z](l: Z, r: Z) extends ExprF[Z]

type ExprA1[Z] = Algebra[ExprF, Z]

trait ExprA2[Z] {
def lit(i: Int): Z
def add(l: Z, r: Z): Z
def mul(l: Z, r: Z): Z
}

These are just different ways to express the same idea: abstracting over recursion.

## One more thing

I mentioned before that every function of a recursive type can be expressed in terms of foldr.

Turns out that every type is isomorphic to its Boehm-Berarducci (also known as Church-) encoding.

Boehm-Berarducciエンコーディングによって全ての型は同一型に表せる

## One more thing

\forall z. \text{Expr} \rightarrow (Int \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow z
\forall z. \text{Expr} \rightarrow ((Int + (z, z) + (z, z)) \rightarrow z) \rightarrow z
\forall z. \text{Expr} \rightarrow (Int \rightarrow z, (z, z) \rightarrow z, (z, z) \rightarrow z) \rightarrow z

This is almost an an isomorphism, we just need to move the quantifier.

ほとんどの同型写像。量化子へ移るのに必要

## One more thing

\text{Expr} \leftrightarrow \forall z. (Int \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow ((z, z) \rightarrow z) \rightarrow z
\text{Expr} \leftrightarrow \forall z. ((Int + (z, z) + (z, z)) \rightarrow z) \rightarrow z
\text{Expr} \leftrightarrow \forall z. (Int \rightarrow z, (z, z) \rightarrow z, (z, z) \rightarrow z) \rightarrow z

This is an isomorphism!

Boehm-Berarducci encoding

Boehm-Berarducciエンコーディング

trait ExprA[Z] {
def lit(i: Int): Z
def add(l: Z, r: Z): Z
def mul(l: Z, r: Z): Z
}

trait Encoded {
def apply[Z](algebra: ExprA[Z]): Z
}

def to(e: Expr): Encoded = new Encoded {
def apply[Z](algebra: ExprA[Z]): Z = foldAlg(e)(algebra)
}
def from(e: Encoded): Expr = e.apply[Expr](new ExprA[Expr] {
def lit(i: Int): Expr = Lit(i)
def mul(l: Expr, r: Expr): Expr = Mul(l, r)
})

We can explicitly construct the isomorphism:

In mathematics, an initial algebra is an initial object in the category of F-algebras for a given endofunctor F.

We won't go into detail, but in our case, Expr is the initial algebra carrier of ExprA.

The important takeaway is: a recursive type is isomorphic to ∀ z. Alg z → z,

where Alg z = PatF z → z.

ExprはExprAの始対象の集合である

Every type T is isomorphic to the set of all observations we can make about T.

If you know Yoneda Lemma, you should get some pretty interesting ideas right about now!

これらの考えられる一般的な別の方法

Every type T is isomorphic to the set of all observations we can make about T.

Given some type T, we can construct a type U that represents all observable properties of T as a tuple of their values.

u : T → U
u = x ↦ (p₁ x, p₂ x, ...)

リストの全ての関数は foldr で表現できる!

u : T → U
u = x ↦ (p₁ x, p₂ x, ...)

It is clear that it must map equal elements of T to equal elements of U. Identity of Indiscernibles also tells us that distinct elements will map to distinct elements in both directions.

Which means that this mapping is an isomorphism!

この写像は、同型写像である

sealed trait Free[F[_], A]
case class Pure   [F[_], A](value: A)             extends Free[F, A]
case class Suspend[F[_], A](value: F[Free[F, A]]) extends Free[F, A]

def runFree[F[_], A, G[_]: Monad](ffa: Free[F, A])(nat: F ~> G): G[A] = ...

Free[F, A] is either a pure value without any effects, or a "free computation" suspended within an effect F.

They can be interpreted into any monad G, as long as you supply a way to transform any F[X] into G[X]​.

フリーモナドについて話そう

The reason Free monads are useful is that they allow us to write an expression in a DSL and have it reinterpret into a different monad.

Consider the following API:

get : (key: Int) => Int

set: (key: Int, value: Int) => Unit

フリーモナドについて話そう

Freeモナドについて話そう

def program: Free[ServiceF, Int] = for {
x <- get(0)
_ <- set(0, x + 1)
_ <- set(1, x + 2)
} yield x

Using Free, we can write a program like this:

runFree[ServiceF, Int, IO](program)(
new (ServiceF ~> IO) { ... }
) : IO[Int]

And have it interpreted either in IO monad against a real service (e.g. a microservice):

runFree[ServiceF, Int, State[(Int, Int), ?]](program)(
new (ServiceF ~> State[(Int, Int), ?]) { ... }
) : State[(Int, Int), Int]

Or mock the microservice and run everything in State monad:

Freeを使うとこのように書ける

そして、実際のサービスに対して IO モナドの中で実行するか

sealed trait ServiceF[+A]
case class Get[A](key: Int,             k: Int => A) extends ServiceF[A]
case class Set[A](key: Int, value: Int, k: ()  => A) extends ServiceF[A]

def get(key: Int)            : Free[ServiceF, Int]  = Suspend(Get(key,        Pure))
def set(key: Int, value: Int): Free[ServiceF, Unit] = Suspend(Set(key, value, Pure))

and then an interpreter for those operations:

We first define our operations:

new (ServiceF ~> State[(Int, Int), ?]) {
def apply[X](value: ServiceF[X]): State[(Int, Int), ?] = {
case Get(key, k) => for {
state <- State.get
value = key match {
case 0 => state._1
case 1 => state._2
}
} yield k(value)

case Set(key, value, k) => ...
}
}

これらの操作は、こう解釈される

Usually, people use a slightly different version of Free monads that removes the Functor constraint on F.

sealed trait Free[F[_], A]
case class Pure   [F[_], A]   (value: A)           extends Free[F, A]
case class Suspend[F[_], A]   (value: F[A])        extends Free[F, A]
case class FlatMap[F[_], A, B](value: Free[F, A],
f: A => Free[F, B]) extends Free[F, B]

def runFree[F[_], A, G[_]: Monad](ffa: Free[F, A])(nat: F ~> G): G[A] = ...

It is a bit cleaner but not substantially different.

Fにおけるファンクターの制約を取り除いたものと、Freeモナドの違い

sealed trait ServiceF[A]
case class Get(key: Int,           ) extends ServiceF[Int]
case class Set(key: Int, value: Int) extends ServiceF[Unit]

def get(key: Int)            : Free[ServiceF, Int]  = Suspend(Get(key       ))
def set(key: Int, value: Int): Free[ServiceF, Unit] = Suspend(Set(key, value))

and then an interpreter for those operations:

Similarly, we first define our operations:

new (ServiceF ~> State[(Int, Int), ?]) {
def apply[X](value: ServiceF[X]): State[(Int, Int), ?] = {
case Get(key) => for {
state <- State.get
value = key match {
case 0 => state._1
case 1 => state._2
}
} yield value

case Set(key, value) => ...
}
}

これらの操作は、こう解釈される

Remember the principle from before:

Every type T is isomorphic to the set of all observations we can make about T.

Let's apply it to our Free[F, A].

The only thing we can observe about (ffa: Free[F, A]) are the results of runFree(ffa).

Freeを適用してみよう

The only thing we can observe about (ffa: Free[F, A]) are the results of runFree(ffa).

trait Free[F[_], A] {
def runFree[G[_]: Monad](nat: F ~> G): G[A]
}

def runFree[F[_], A, G[_]: Monad](ffa: Free[F, A])(nat: F ~> G): G[A]
= ffa.runFree(nat)

Surprisingly, this works perfectly fine, all instances are fairly straight-forward to implement.

// data Is a b = Is (forall (f :: * -> *). f a -> f b)

trait Is[A, B] {
def subst[F[_]](fa: F[A]): F[B]
}
object Is {
implicit def refl[A]: A Is A = new Is[A, A] {
def subst[F[_]](fa: F[A]): F[A] = fa
}
}

THIS SLIDE IS NEW

sealed trait Foo[X]
final case class A() extends Foo[Int]
final case class B(i: Int) extends Foo[Unit]
final case class C[A](i: A) extends Foo[A]

// is the same as

sealed trait Foo[X]
final case class A[X]()      (implicit ev: X Is Int)  extends Foo[X]
final case class B[X](i: Int)(implicit ev: X Is Unit) extends Foo[X]
final case class C[A](i: A)                           extends Foo[A]


THIS SLIDE IS NEW

trait Free[F[_], A] { def runFree[G[_]: Monad](nat: F ~> G): G[A] }

Once again, we look at the type more closely:

\forall g. \text{Monad}~g \rightarrow (\forall x. f x \rightarrow g x) \rightarrow g a

Let's rewrite this term as a constraint on g

\forall g. \text{Monad}~g \rightarrow A g \rightarrow g a
A g = \forall x. f x \rightarrow g x

Hmm, what is A?

もう一度、もっと近くで型を見てみよう

gによる束縛による条件で書き直して見よう

Aは何？

Consider the concrete case of ServiceF

sealed trait ServiceF[A]
case class Get(key: Int,           ) extends ServiceF[Int]
case class Set(key: Int, value: Int) extends ServiceF[Unit]

trait A[G[_]] {
def run[X](value: ServiceF[X]): G[X]
}
A g = \forall x. \text{ServiceF}~x \rightarrow g x
\forall x. ((x = \text{Int}, Int) + (x = \text{Unit}, (Int, Int)) \rightarrow g x

Expanding the GADT as a sum of products with type equalities:

ServiceFの具体的なケースで考えてみる

\forall x. ((x = \text{Int}, Int) + (x = \text{Unit}, (Int, Int)) \rightarrow g x
\forall x. ((x = \text{Int}, Int) \rightarrow g x, (x = \text{Unit}, (Int, Int)) \rightarrow g x)

Uncurrying:

(\forall x. (x = \text{Int}, Int) \rightarrow g x, \forall x. (x = \text{Unit}, (Int, Int)) \rightarrow g x)

Distributing ∀:

Applying type equalities:

(Int \rightarrow g~\text{Int}, (Int, Int) \rightarrow g~\text{Unit})

sealed trait ServiceF[A]
case class Get(key: Int,           ) extends ServiceF[Int]
case class Set(key: Int, value: Int) extends ServiceF[Unit]

trait A[G[_]] {
def get(key: Int): G[Int]
def set(key: Int, value: Int): G[Unit]
}
(Int \rightarrow g~\text{Int}, (Int, Int) \rightarrow g~\text{Unit})

So the constraint A turned out to be what is colloquially known as an algebra!

Aの制約は代数として知られているものと判明した

Let's rewrite our Free monad accordingly:

trait Free[F[_], A] {
def runFree[G[_]: Monad](nat: F ~> G): G[A]
}

trait FreeA[Alg[_[_]], A] {
}

Does it look familiar?

This is Final Tagless encoding!

Freeモナドに書き直そう

タグレスファイナルエンコーディング

trait ServiceAlg[G[_]] {
def get(key: Int): G[Int]
def set(key: Int, value: Int): G[Unit]
}
def program: FreeA[ServiceAlg, Int] = ...

Now notice that if we have

we might as well dispose of the FreeA type and write simply:

def program[G[_]: Monad](alg: ServiceAlg[G]): G[Int] = ...

where

FreeA型の置き換えと単純に書き換える

Or we could make ServiceAlg a typeclass:

def program[G[_]: Monad: ServiceAlg]: G[Int] = ...

So what is the takeaway here?

または ServiceAlg 型クラスを作ることもできる

So what is the takeaway here?

Free = Final Tagless, at least on the the conceptual level.

Both give us an ability to write our programs in a DSL and have them compile into some different language.

There is an isomorphism that converts from one representation to the other

DSLで書ける力があり、違う言語でもコンパイル出来る

ある表現から別の表現への同型写像

## Summing it all up

folds ≈ Recursion Schemes ≈ Final Tagless (simple algebras)

Identity of Indiscernibles and its connection to isomorphisms

Type algebra

まとめ

## Summing it all up

Free ≈ Final Tagless

Isomorphism to the Initial algebra carrier

Isomorphism to the product of all observable properties

まとめ

## Q&A

Alexander Konovalov, Compellon Inc

alex.knvl@gmail.com @alexknvl

alexknvl.com

#### Copy of Recursion

By Alexander Konovalov

• 2,580