Reflection:

algebraic data types for mortals

About me

  • Mathematics Student at Imperial
  • PHP Core developer & documentation maintainer

What are Algebraic Data Types?

Definition

Warning: Software development, Computer Science, and Type Theory don't agree on what stuff means at time

Definition

Definition

Definition

In computer programming, especially functional programming and type theory, an algebraic data type is a kind of composite type, i.e., a type formed by combining other types.

Definition

In computer programming, especially functional programming and type theory, an algebraic data type is a kind of composite type, i.e., a type formed by combining other types.

Two common classes of algebraic types are product types (i.e., tuples and records) and sum types (i.e., tagged or disjoint unions, coproduct types or variant types).

Product types

The popular ADT

Product types

Explanation for mortals

Product types

Explanation for mortals

Product types allow you to have more than one value in a single structure, at the same time.

<?php

class BoolTuple2 {
    public bool $boolean1;
    public bool $boolean2;
    
    public function __construct(bool $boolean1, bool $boolean2) {
        $this->boolean1 = $boolean1;
        $this->boolean2 = $boolean2;
    }
}

Product type examples

<?php

class BoolTuple2 {
    public function __construct(public bool $boolean1, public bool $boolean2) {}
}

Product type examples

<?php

class BoolTuple2 {
    public function __construct(public bool $boolean1, public bool $boolean2) {}
}

Product type examples

How many ways can we construct BoolTuple2?

<?php

class BoolTuple2 {
    public function __construct(public bool $boolean1, public bool $boolean2) {}
}

Product type examples

How many ways can we construct BoolTuple2?

<?php

$trueTrue   = new BoolTuple2(true, true);
$trueFalse  = new BoolTuple2(true, false);
$falseTrue  = new BoolTuple2(false, true);
$falseFalse = new BoolTuple2(false, false);
<?php

class BoolTuple2 {
    public function __construct(public bool $boolean1, public bool $boolean2) {}
}

Product type examples

How many ways can we construct BoolTuple2?

4 = 2 \times 2 = |bool| \times |bool|
<?php

class Digit {
    public int $digit;
    
    public function __construct(int $digit) {
        if ($digit < 0 || $digit > 9) {
            throw new ValueError('Value must be a digit');
        }
        $this->digit = $digit;
    }
}

class Composite {
    public function __construct(public BoolTuple2 $boolTuple2, public Digit $digit) {}
}

Product type examples

<?php

class Digit {
    public int $digit;
    
    public function __construct(int $digit) {
        if ($digit < 0 || $digit > 9) {
            throw new ValueError('Value must be a digit');
        }
        $this->digit = $digit;
    }
}

class Composite {
    public function __construct(public BoolTuple2 $boolTuple2, public Digit $digit) {}
}

Product type examples

How many ways can we construct Composite?

<?php

class Digit {
    public int $digit;
    
    public function __construct(int $digit) {
        if ($digit < 0 || $digit > 9) {
            throw new ValueError('Value must be a digit');
        }
        $this->digit = $digit;
    }
}

class Composite {
    public function __construct(public BoolTuple2 $boolTuple2, public Digit $digit) {}
}

Product type examples

How many ways can we construct Composite?

|Composite| = |Digit| \times |BoolTuple2|
<?php

class Digit {
    public int $digit;
    
    public function __construct(int $digit) {
        if ($digit < 0 || $digit > 9) {
            throw new ValueError('Value must be a digit');
        }
        $this->digit = $digit;
    }
}

class Composite {
    public function __construct(public BoolTuple2 $boolTuple2, public Digit $digit) {}
}

Product type examples

How many ways can we construct Composite?

|Composite| = |Digit| \times |bool| \times |bool|
<?php

class Digit {
    public int $digit;
    
    public function __construct(int $digit) {
        if ($digit < 0 || $digit > 9) {
            throw new ValueError('Value must be a digit');
        }
        $this->digit = $digit;
    }
}

class Composite {
    public function __construct(public BoolTuple2 $boolTuple2, public Digit $digit) {}
}

Product type examples

How many ways can we construct Composite?

|Composite| = 10 \times 2 \times 2
<?php

class Digit {
    public int $digit;
    
    public function __construct(int $digit) {
        if ($digit < 0 || $digit > 9) {
            throw new ValueError('Value must be a digit');
        }
        $this->digit = $digit;
    }
}

class Composite {
    public function __construct(public BoolTuple2 $boolTuple2, public Digit $digit) {}
}

Product type examples

How many ways can we construct Composite?

|Composite| = 40

Sum types

Also know as Coproduct types

Sum types

Explanation for mortals

Sum types

Explanation for mortals

Sum types are types where your value must be one of a fixed set of options.

Sum type examples

Sum type examples

Enumerations, aka Enums

Sum type examples

Booleans

bool = \{true, false\}

Enumerations, aka Enums

Sum type examples

Booleans

bool = \{true, false\}

Our Digit class

Digit = \{0, 1, 2, 3, 4, 5, 6, 7, 8, 9\}

Enumerations, aka Enums

Sum type examples

Sequences

Sum type examples

Lists

\textrm{List } a = [] \ | \ \textrm{Construct } a \ (\textrm{List } a)

Sequences

Sum type examples

Lists

\textrm{List } a = [] \ | \ \textrm{Construct } a \ (\textrm{List } a)

Strings

\textrm{String } c = \textsf{'}\textsf{'}\ | \ \textrm{Construct } c \ (\textrm{String } c)

Sequences

Sum type examples

Union types

Sum type examples

Union types

<?php

class BoolOrDigit {
    public function __construct(public bool|Digit $boolOrDigit) {}
}

Sum type examples

Union types

<?php

class BoolOrDigit {
    public function __construct(public bool|Digit $boolOrDigit) {}
}

How many ways can we construct BoolOrDigit?

Sum type examples

Union types

<?php

class BoolOrDigit {
    public function __construct(public bool|Digit $boolOrDigit) {}
}

How many ways can we construct BoolOrDigit?

BoolOrDigit = bool \cup Digit

Sum type examples

Union types

<?php

class BoolOrDigit {
    public function __construct(public bool|Digit $boolOrDigit) {}
}

How many ways can we construct BoolOrDigit?

BoolOrDigit = bool \cup Digit
|BoolOrDigit| = |bool| + |Digit|

Sum type examples

Union types

<?php

class BoolOrDigit {
    public function __construct(public bool|Digit $boolOrDigit) {}
}

How many ways can we construct BoolOrDigit?

BoolOrDigit = bool \cup Digit
|BoolOrDigit| = 2 + 10 = 12

Pattern matching

Reason why sum types are๐Ÿ˜Ž

Definition

Definition

In computer science, pattern matching is the act of checking a given sequence of tokens for the presence of the constituents of some pattern.

Definition

In computer science, pattern matching is the act of checking a given sequence of tokens for the presence of the constituents of some pattern.

The patterns generally have the form of either sequences or tree structures.

Poor man Pattern matching example

<?php

class Nil {}
class Leaf {
    public function __construct(public int $value) {}
}
class Node {
    public function __construct(public Tree $left, public Tree $right) {}
}
class Tree {
    public function __construct(public Nil|Leaf|Node $val) {}
}

Poor man Pattern matching example

<?php

class Nil {}
class Leaf {
    public function __construct(public int $value) {}
}
class Node {
    public function __construct(public Tree $left, public Tree $right) {}
}
class Tree {
    public function __construct(public Nil|Leaf|Node $val) {}
}

function depth(Tree $tree): int {
    $val = $tree->val;
    return match ($val::class) {
        Nil::class => 0,
        Leaf::class => 1,
        Node::class => 1 + max(depth($val->left), depth($val->right)),
    };
}

Poor man Pattern matching example

<?php

$treeExample = new Tree(new Node(
    new Tree(new Leaf(5)),
    new Tree(new Node(
        new Tree(new Node(
            new Tree(new Nil()),
            new Tree(new Leaf(2)),
        )),
        new Tree(new Leaf(6)),
    ))
));

print depth($treeExample);

Poor man Pattern matching example

<?php

$treeExample = new Tree(new Node(
    new Tree(new Leaf(5)),
    new Tree(new Node(
        new Tree(new Node(
            new Tree(new Nil()),
            new Tree(new Leaf(2)),
        )),
        new Tree(new Leaf(6)),
    ))
));

print depth($treeExample);

5

2

6

Poor man Pattern matching example

<?php

$treeExample = new Tree(new Node(
    new Tree(new Leaf(5)),
    new Tree(new Node(
        new Tree(new Node(
            new Tree(new Nil()),
            new Tree(new Leaf(2)),
        )),
        new Tree(new Leaf(6)),
    ))
));

print depth($treeExample);

5

2

6

4

Output

Poor man Pattern matching example

<?php

$treeExample = new Tree(new Node(
    new Tree(new Leaf(5)),
    new Tree(new Node(
        new Tree(new Node(
            new Tree(new Nil()),
            new Tree(new Leaf(2)),
        )),
        new Tree(new Leaf(6)),
    ))
));

print depth($treeExample);

5

2

6

4

Output

What about Reflection?

What about Reflection?

Well, turns out we don't need it. ๐Ÿ˜“

Thank you!

Sources and inspiration:

Reflection: algebraic data types for mortals

By girgias

Reflection: algebraic data types for mortals

  • 891