Generic Programming with Adjunctions - Department of Computer ...

9 downloads 241 Views 544KB Size Report
Overview 1.4. 1.4 Overview. • Part 0: Prologue. • Part 1: Category theory. • Part 2: Adjoint folds and unfolds. â€
Generic Programming with Adjunctions

0.0

Generic Programming with Adjunctions Ralf Hinze Computing Laboratory, University of Oxford Wolfson Building, Parks Road, Oxford, OX1 3QD, England [email protected] http://www.comlab.ox.ac.uk/ralf.hinze/

March 2010

University of Oxford — Ralf Hinze

1-172

Generic Programming with Adjunctions

1.0

Part 1

Prologue

University of Oxford — Ralf Hinze

2-172

Generic Programming with Adjunctions

1.0

1.0

Outline

1. What? 2. Why? 3. Where? 4. Overview

University of Oxford — Ralf Hinze

3-172

Generic Programming with Adjunctions

1.1

What?

1.1

What?

Haskell programmers have embraced • functors, • natural transformations, • initial algebras, • final coalgebras, • monads, • ...

It is time to turn our attention to adjunctions.

University of Oxford — Ralf Hinze

4-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Catamorphism

f = Lb M

⇐⇒

University of Oxford — Ralf Hinze

f · in = b · F f

5-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Banana-split law

LhM  Lk M

= L h · F outl  k · F outr M

University of Oxford — Ralf Hinze

6-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Proof of banana-split law

=

=

=

=

=

(L h M  L k M ) · in

{ split-fusion }

L h M · in  L k M · in

{ fold-computation }

h · F LhM  k · F Lk M

{ split-computation }

h · F (outl · (L h M  L k M ))  k · F (outr · (L h M  L k M )) { F functor }

h · F outl · F (L h M  L k M )  k · F outr · F (L h M  L k M ) { split-fusion }

(h · F outl  k · F outr) · F (L h M  L k M ) University of Oxford — Ralf Hinze

7-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Example: total

data Stack = Empty | Push (Nat, Stack) total : Stack → Nat total (Empty) =0 total (Push (n, s)) = n + total s

University of Oxford — Ralf Hinze

8-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Two-level types

Abstracting away from the recursive call. data Stack stack = Empty | Push (Nat, stack) instance Functor Stack where fmap f (Empty) = Empty fmap f (Push (n, s)) = Push (n, f s) Tying the recursive knot. newtype µf = In {in◦ : f (µf )} type Stack = µStack

University of Oxford — Ralf Hinze

9-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Two-level functions

Structure. total : Stack Nat → Nat total (Empty) =0 total (Push (n, s)) = n + s Tying the recursive knot. total : µStack → Nat total (In s) = total (fmap total s)

University of Oxford — Ralf Hinze

10-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Counterexample: stack

stack : (Stack, Stack) → Stack stack (Empty, bs) = bs stack (Push (a, as), bs) = Push (a, stack (as, bs))

University of Oxford — Ralf Hinze

11-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Counterexamples: fac and fib

data Nat = Z | S Nat fac : Nat → Nat fac (Z) = 1 fac (S n) = S n∗fac n fib : Nat → Nat fib (Z) = Z fib (S Z) = SZ fib (S (S n)) = fib n + fib (S n)

University of Oxford — Ralf Hinze

12-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Counterexample: sum

data List a = Nil | Cons (a, List a) sum : List Nat → Nat sum (Nil) =0 sum (Cons (a, as)) = a + sum as

University of Oxford — Ralf Hinze

13-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Counterexample: append

append : ∀ a . (List a, List a) → List a append (Nil, bs) = bs append (Cons (a, as), bs) = Cons (a, append (as, bs))

University of Oxford — Ralf Hinze

14-172

Generic Programming with Adjunctions

1.2

Why?

1.2

Counterexample: concat

concat : ∀ a . List (List a) → List a concat (Nil) = Nil concat (Cons (l, ls)) = append (l, concat ls)

University of Oxford — Ralf Hinze

15-172

Generic Programming with Adjunctions

1.3

Where?

1.3

References

The lectures are based on: • Part 1: R. Hinze: A category theory primer, SSGIP 2010. • Part 2 & 3: R. Hinze: Adjoint Folds and Unfolds, MPC’10. • Part 4: R. Hinze: Type Fusion.

Further reading: • S. Mac Lane: Categories for the Working Mathematician. • M. Fokkinga, L. Meertens: Adjunctions. • R. Bird, R. Paterson: Generalised folds for nested

datatypes.

University of Oxford — Ralf Hinze

16-172

Generic Programming with Adjunctions

1.4

Overview

1.4

Overview

• Part 0: Prologue • Part 1: Category theory • Part 2: Adjoint folds and unfolds • Part 3: Adjunctions • Part 4: Application: Type fusion • Part 5: Epilogue

University of Oxford — Ralf Hinze

17-172

Generic Programming with Adjunctions

2.0

Part 2

Category theory

University of Oxford — Ralf Hinze

18-172

Generic Programming with Adjunctions

2.0

2.0

Outline

5. Categories, functors and natural transformations 6. Constructions on categories 7. Initial and final objects 8. Products 9. Adjunctions 10. Yoneda lemma

University of Oxford — Ralf Hinze

19-172

Generic Programming with Adjunctions

2.1

Categories, functors and natural transformations

2.1

Category

• objects: A ∈ C, • arrows: f ∈ C(A, B), • identity: id A ∈ C(A, A), • composition: if f ∈ C(A, B) and g ∈ C(B, C),

then g · f ∈ C(A, C), • · is associative with id as its neutral element.

University of Oxford — Ralf Hinze

20-172

Generic Programming with Adjunctions

2.1

Categories, functors and natural transformations

2.1

Example: a preorder P

• objects: a ∈ P, • arrows: a à b, • identity: a à a (reflexivity), • composition: if a à b and b à c, then a à c (transitivity).

NB There is at most one arrow between two objects.

University of Oxford — Ralf Hinze

21-172

Generic Programming with Adjunctions

2.1

Categories, functors and natural transformations

2.1

Example: Set

• objects: sets, • arrows: total functions, • identity: id x = x, • composition: function composition (g · f ) x = g (f x).

University of Oxford — Ralf Hinze

22-172

Generic Programming with Adjunctions

2.1

Categories, functors and natural transformations

2.1

Example: Mon

• objects: monoids hA, , + +i, • arrows: monoid homomorphisms

h : hA, 0, +i → hB, 1, ∗i: h0

= 1

h (x + y) = h x∗h y, • identity: id x = x, • composition: function composition (g · f ) x = g (f x).

University of Oxford — Ralf Hinze

23-172

Generic Programming with Adjunctions

2.1

Categories, functors and natural transformations

2.1

Functor

• F : C → D, • action on objects, • action on arrows, • if f ∈ C(A, B), then F f ∈ D(F A, F B) • F id A = id F A , • F (g · f ) = F g · F f .

University of Oxford — Ralf Hinze

24-172

Generic Programming with Adjunctions

2.1

Categories, functors and natural transformations

2.1

Example: the forgetful functor

• U : Mon → Set, • action on objects: U hA, , + +i = A, • action on arrows: U f = f .

University of Oxford — Ralf Hinze

25-172

Generic Programming with Adjunctions

2.1

Categories, functors and natural transformations

2.1

Natural transformation

• let F, G : C → D be two parallel functors, • a transformation α : F → G is a collection of arrows: for

each object A ∈ C there is an arrow α A ∈ D(F A, G A), • a natural transformation α : F → ˙ G additionally satisfies

G h · α A = α B · F h for all arrows h ∈ C(A, B). FA

Fh

αA … GA

University of Oxford — Ralf Hinze

 FB αB

Gh

…  GB

26-172

Generic Programming with Adjunctions

2.2

Constructions on categories

2.2

Cat

• objects: small categories, • arrows: functors, • identity: identity functor: IdC A = A and IdC f = f , • composition: (G ◦ F) A = G (F A) and (G ◦ F) f = G (F f ).

University of Oxford — Ralf Hinze

27-172

Generic Programming with Adjunctions

2.2

Constructions on categories

2.2

Functor category DC

• let C and D be two categories, • objects: functors C → D, • arrows: natural transformations F → ˙ G, • identity: id F A = id F A , • composition: (β · α) A = β A · α A.

University of Oxford — Ralf Hinze

28-172

Generic Programming with Adjunctions

2.2

Constructions on categories

2.2

Opposite category Cop

• let C be a category, • objects: A ∈ Cop if A ∈ C • arrows: f ∈ Cop (A, B) if f ∈ C(B, A) • identity: id A ∈ C(A, A), • composition: g · f ∈ Cop (A, C) if f · g ∈ C(C, A).

University of Oxford — Ralf Hinze

29-172

Generic Programming with Adjunctions

2.2

Constructions on categories

2.2

Product category C1 × C2

• let C1 and C2 be two categories, • objects: hA1 , A2 i ∈ C1 × C2 if A1 ∈ C1 and A2 ∈ C2 , • arrows: hf1 , f2 i ∈ (C1 × C2 )(hA1 , A2 i, hB1 , B2 i) if

f1 ∈ C1 (A1 , B1 ) and f2 ∈ C2 (A2 , B2 ), • identity: id = hid, idi, • composition: hg1 , g2 i · hf1 , f2 i = hg1 · f1 , g2 · f2 i.

University of Oxford — Ralf Hinze

30-172

Generic Programming with Adjunctions

2.2

Constructions on categories

2.2

Outl, Outr and ∆

• projection functors:

Outl : C × D → C; Outl hA, Bi = A; Outl hf , gi = f ;

Outr : C × D → D; Outr hA, Bi = B; Outr hf , gi = g.

• diagonal functor:

∆ : C → C × C; ∆A = hA, Ai; ∆f = hf , f i.

University of Oxford — Ralf Hinze

31-172

Generic Programming with Adjunctions

2.2

Constructions on categories

2.2

The hom-functor

• C(−, =) : Cop × C → Set, • action on objects: C(−, =) hA, Bi = C(A, B), • action on arrows: C(−, =) hf , gi = λ h . g · h · f , • shorthand: C(f , g) h = g · h · f .

University of Oxford — Ralf Hinze

32-172

Generic Programming with Adjunctions

2.3

Initial and final objects

2.3

Initial object

The object 0 is initial if for each object B ∈ C there is exactly one arrow from 0 to B, denoted ¡B (pronounce “gnab”). 0

University of Oxford — Ralf Hinze

¡B

B

33-172

Generic Programming with Adjunctions

2.3

Initial and final objects

2.3

Final object

Dually, 1 is a final object if for each object A ∈ C there is a unique arrow from A to 1, denoted !A (pronounce “bang”). A

University of Oxford — Ralf Hinze

!A

1

34-172

Generic Programming with Adjunctions

2.4

Products

2.4

Product

The product of two objects B1 and B2 consists of • an object written B1 × B2 , • a pair of arrows outl : B1 × B2 → B1 and

outr : B1 × B2 → B2 , and satisfies the following universal property: • for each object A, • for each pair of arrows f1 : A → B1 and f2 : A → B2 , • there exists an arrow f1  f2 : A → B1 × B2 such that

f1 = outl · g ∧ f2 = outr · g

⇐⇒

f1  f2 = g,

for all g : A → B1 × B2 .

University of Oxford — Ralf Hinze

35-172

Generic Programming with Adjunctions

2.4

Products

2.4

Product

f1 ≺ B1 ≺

University of Oxford — Ralf Hinze

outl

A .. .. . f1  f2 ... . . … B1 × B2

f2

outr

  B2

36-172

Generic Programming with Adjunctions

2.4

Products

2.4

Laws

• computation laws:

f1

= outl · (f1  f2 );

f2

= outr · (f1  f2 ),

• reflection law:

outl  outr

University of Oxford — Ralf Hinze

= id A×B .

37-172

Generic Programming with Adjunctions

2.4

Products

2.4

Laws

• fusion law:

(f1  f2 ) · h = f1 · h  f2 · h, • action of × on arrows:

f1 × f2

= f1 · outl  f2 · outr,

• functor fusion law:

(k1 × k2 ) · (f1  f2 ) = k1 · f1  k2 · f2 , • outl and outr are natural transformations:

k1 · outl

= outl · (k1 × k2 );

k2 · outr

= outr · (k1 × k2 ).

University of Oxford — Ralf Hinze

38-172

Generic Programming with Adjunctions

2.4

Products

2.4

Proof of functor fusion

(k1 × k2 ) · (f1  f2 ) =

{ definition of × } (k1 · outl  k2 · outr) · (f1  f2 )

=

{ fusion } k1 · outl · (f1  f2 )  k2 · outr · (f1  f2 )

=

{ computation } k1 · f1  k2 · f2

University of Oxford — Ralf Hinze

39-172

Generic Programming with Adjunctions

2.4

Products

2.4

Naturality

• fusion and functor fusion:

() : ∀A B . (C × C)(∆A, B) → C(A, ×B), • naturality of outl and outr:

outl

: ∀B . C(×B, Outl B);

outr

: ∀B . C(×B, Outr B),

or more succinctly houtl, outri : ∀B . (C × C)(∆(×B), B).

University of Oxford — Ralf Hinze

40-172

Generic Programming with Adjunctions

2.5

Adjunctions

2.5

Adjunction

C



L ⊥ R



D

φ : ∀A B . C(L A, B) › D(A, R B)

University of Oxford — Ralf Hinze

41-172

Generic Programming with Adjunctions

2.5

Adjunctions

2.5

Adjoints, adjuncts and units

• left and right adjoints:

Lg Rf

= φ◦ (η · g), = φ (f · ),

• left and right adjuncts:

φ◦ g =  · L g, φf = R f · η, • counit and unit:

 = φ◦ id, η = φ id.

University of Oxford — Ralf Hinze

42-172

Generic Programming with Adjunctions

2.5

Adjunctions

2.5

Adjoints of the diagonal functor

f = houtl, outri · ∆g

C

f = g



⇐⇒

University of Oxford — Ralf Hinze

+ ⊥ ∆

⇐⇒



C×C

f = g



∆ ⊥ ×



C

∆f · hinl, inri = g

43-172

Generic Programming with Adjunctions

2.5

Adjunctions

2.5

Left adjoint of the forgetful functor

Mon

University of Oxford — Ralf Hinze



List ⊥ U



Set

44-172

Generic Programming with Adjunctions

Adjunctions

φ◦ introduction / elimination

2.5

φ elimination / introduction

Universal property f = φ◦ g ⇐⇒ φ f = g  : C(L (R B), B) ◦

η : D(A, R (L A))

 = φ id

φ id = η

— / computation law

computation law / —

η-rule / β-rule

β-rule / η-rule

f = φ◦ (φ f )

φ (φ◦ g) = g

reflection law / —

— / reflection law

simple η-rule / simple β-rule

simple β-rule / simple η-rule



id = φ η

University of Oxford — Ralf Hinze

φ  = id

45-172

Generic Programming with Adjunctions

Adjunctions

φ◦ introduction / elimination

2.5

φ elimination / introduction

Universal property f = φ◦ g ⇐⇒ φ f = g functor fusion law / — ◦

— / fusion law

φ is natural in A

φ is natural in A

φ◦ g · L h = φ◦ (g · h)

φ f · h = φ (f · L h)

fusion law / —

— / functor fusion law

φ◦ is natural in B

φ is natural in B





k · φ g = φ (R k · g)

R k · φ f = φ (k · f )

 is natural in B

η is natural in A

k ·  =  · L (R k)

R (L h) · η = η · h

University of Oxford — Ralf Hinze

46-172

Generic Programming with Adjunctions

2.6

Yoneda lemma

2.6

Yoneda lemma

Let H : C → Set be a functor, and let B ∈ C be an object. H B › C(B, −) → ˙H The functions witnessing the isomorphism are φs

= λ κ . H κ s,

φ◦ α = α B id B . NB Continuation-passing style is a special case: H = C(A, −).

University of Oxford — Ralf Hinze

47-172

Generic Programming with Adjunctions

3.0

Part 3

Adjoint folds and unfolds

University of Oxford — Ralf Hinze

48-172

Generic Programming with Adjunctions

3.0

3.0

Outline

11. Semantics of datatypes 12. Mendler-style folds and unfolds 13. Adjoint folds and unfolds

University of Oxford — Ralf Hinze

49-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

Example: total

data Stack = Empty | Push (Nat, Stack) total : Stack → Nat total (Empty) =0 total (Push (n, s)) = n + total s

University of Oxford — Ralf Hinze

50-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

Fixed-point equations

• both Stack and total are given by recursion equations, • meaning of x = Ψ x? • a solves the equation iff a is a fixed point of Ψ, • Ψ is called the base function.

University of Oxford — Ralf Hinze

51-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

Two-level types

Abstracting away from the recursive call. data Stack stack = Empty | Push (Nat, stack) instance Functor Stack where fmap f (Empty) = Empty fmap f (Push (n, s)) = Push (n, f s) Tying the recursive knot. newtype µf = In {in◦ : f (µf )} type Stack = µStack

University of Oxford — Ralf Hinze

52-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

Speaking categorically

• functor: Stack A = 1 + Nat × A, • a Stack-algebra:

total : Stack Nat → Nat total (Empty) =0 total (Push (n, s)) = n + s • total = zero  plus, • Stack-algebra: hNat, totali.

University of Oxford — Ralf Hinze

53-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

The category of F-algebras Alg(F)

• let F : C → C be an endofunctor, • objects: hA, ai with A ∈ C and a ∈ C(F A, A), • arrows: F-homomorphisms, h : hA, ai → hB, bi if

h ∈ C(A, B) such that h · a = b · F h,

FA a … A

FA

Fh

 FB

a … A

b

h

… B

FB b … B

• identity: id A : hA, ai → hA, ai, • composition: in C. University of Oxford — Ralf Hinze

54-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

The category of F-coalgebras Coalg(F)

• let F : C → C be an endofunctor, • objects: hA, ai with A ∈ C and a ∈ C(A, F A), • arrows: F-homomorphisms, h : hA, ai → hB, bi if

h ∈ C(A, B) such that F h · a = b · h,

A a … FA

A

h

B

a … FA

B b

Fh

…  FB

b … FB

• identity: id A : hA, ai → hA, ai, • composition: in C. University of Oxford — Ralf Hinze

55-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

Fixed points of functors

• initial object in Alg(F): initial F-algebra hµF, ini, • µF is the least fixed point of F, • in : F (µF) › µF, • final object in Coalg(F): final F-coalgebra hνF, outi, • νF is the greatest fixed point of F, • out : νF › F (νF).

University of Oxford — Ralf Hinze

56-172

Generic Programming with Adjunctions

3.1

Semantics of datatypes

3.1

Coq: inductive and coinductive types

Inductive Nat : Type := | Zero : Nat | Succ : Nat → Nat. Inductive Stack : Type := | Empty : Stack | Push : Nat → Stack → Stack. CoInductive Stream : Type := | Cons : Nat → Stream → Stream.

University of Oxford — Ralf Hinze

57-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Semantics of recursive functions

total : µStack → Nat total (In (Empty)) =0 total (In (Push (n, s))) = n + total s

University of Oxford — Ralf Hinze

58-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Abstracting away from the recursive call

total : (µStack → Nat) → (µStack → Nat) total total (In (Empty)) =0 total total (In (Push (n, s))) = n + total s A function of this type has many fixed points.

University of Oxford — Ralf Hinze

59-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

. . . removing in

Abstracting away from the recursive call and removing in. total : ∀ x . (x → Nat) → (Stack x → Nat) total total (Empty) =0 total total (Push (n, s)) = n + total s A function of this type has a unique ‘fixed point’. Tying the recursive knot. total : µStack → Nat total (In l) = total total l

University of Oxford — Ralf Hinze

60-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Example: from

data Sequ = Next (Nat, Sequ) from : Nat → Sequ from n = Next (n, from (n + 1))

University of Oxford — Ralf Hinze

61-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Two-level types and functions

data Sequ sequ = Next (Nat, sequ) from : ∀ x . (Nat → x) → (Nat → Sequ x) from from n = Next (n, from (n + 1)) from : Nat → νSequ from n = Out ◦ (from from n) .

University of Oxford — Ralf Hinze

62-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Initial fixed-point equations

An initial fixed-point equation in the unknown x ∈ C(µF, A) has the syntactic form x · in = Ψ x , where the base function Ψ has type Ψ : ∀ X . C(X , A) → C(F X , A) . The naturality of Ψ ensures termination.

University of Oxford — Ralf Hinze

63-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Guarded by destructors

x

= Ψ x · in◦

x ∈ C(µF, A) Ψ : ∀ X . C(X , A) → C(F X , A)

µF

University of Oxford — Ralf Hinze

in◦ Ψx  F (µF) A

64-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Mendler-style folds

x = L Ψ MId

⇐⇒ x · in = Ψ x

University of Oxford — Ralf Hinze

65-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Proof of uniqueness φ : C(F A, A) › (∀ X . C(X , A) → C(F X , A))

x · in = Ψ x ⇐⇒

{ isomorphism } x · in = φ (φ◦ Ψ) x

⇐⇒

{ definition of φ◦ : φ◦ Ψ = Ψ id } x · in = φ (Ψ id) x

⇐⇒

{ definition of φ: φ f = λ κ . f · F κ } x · in = Ψ id · F x

⇐⇒

{ initial algebras } x = L Ψ id M

University of Oxford — Ralf Hinze

66-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Final fixed-point equations

A final fixed-point equation in the unknown x ∈ C(A, νF) has the syntactic form out · x

= Ψx ,

where the base function Ψ has type Ψ : ∀ X . C(A, X ) → C(A, F X ) . The naturality of Ψ ensures productivity.

University of Oxford — Ralf Hinze

67-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Guarded by constructors

x

= out ◦ · Ψ x

x ∈ C (A, νF) Ψ : ∀ X . C(A, X ) → C(A, F X )

A

University of Oxford — Ralf Hinze

Ψx out ◦  F (νF)  νF

68-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Mendler-style unfolds

x = [(Ψ)]Id

University of Oxford — Ralf Hinze

⇐⇒ out · x = Ψ x

69-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Mutual type recursion

data Tree = Node Nat Trees data Trees = Nil | Cons (Tree, Trees) flattena : Tree → Stack flattena (Node n ts) = Push (n, flattens ts) flattens : Trees → Stack flattens (Nil) = Empty flattens (Cons (t, ts)) = stack (flattena t, flattens ts)

University of Oxford — Ralf Hinze

70-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Speaking categorically

Idea: view Tree and Trees as a fixed point in a product category. T hA, Bi = hNat × B, 1 + A × Bi flatten ∈ (C × C)(µT, hStack, Stacki)

University of Oxford — Ralf Hinze

71-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Specialising fixed-point equations

An equation in C × D corresponds to two equations, one in C and one in D. x · in = Ψ x ⇐⇒ x1 · in1 = Ψ1 hx1 , x2 i and

x2 · in2 = Ψ2 hx1 , x2 i

Here, x1 = Outl x, x2 = Outr x, in1 = Outl in, in2 = Outr in, Ψ1 = Outl · Ψ and Ψ2 = Outr · Ψ.

University of Oxford — Ralf Hinze

72-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Parametric datatypes

data Perfect a = Zero a | Succ (Perfect (a, a)) size : ∀ a . Perfect a → Nat size (Zero a) = 1 size (Succ p) = 2∗size p

University of Oxford — Ralf Hinze

73-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Speaking categorically

Idea: view Perfect as a fixed point in a functor category. P F = Λ A . A + F (A × A) The second-order functor F sends a functor to a functor. size : µP → ˙ K Nat NB K : D → DC is the constant functor K A = Λ B . A.

University of Oxford — Ralf Hinze

74-172

Generic Programming with Adjunctions

3.2

Mendler-style folds and unfolds

3.2

Specialising fixed-point equations

x · in = Ψ x ⇐⇒ x A · in A = Ψ x A NB Type application and abstraction are invisible in Haskell.

University of Oxford — Ralf Hinze

75-172

Generic Programming with Adjunctions

initial fixed-point equation x · in = Ψ x Set Cpo Cpo⊥ C×D DC

Mendler-style folds and unfolds

3.2

final fixed-point equation out · x = Ψ x

inductive type standard fold

coinductive type standard unfold continuous coalgebra — continuous unfold continuous algebra continuous coalgebra strict continuous fold strict continuous unfold (µF › νF) mutually rec. ind. types mutually rec. coind. types mutually rec. folds mutually rec. unfolds inductive type functor coinductive type functor higher-order fold higher-order unfold

University of Oxford — Ralf Hinze

76-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Counterexample: stack

stack : (µStack, Stack) → Stack stack (In (Empty), bs) = bs stack (In (Push (a, as)), bs) = In (Push (a, stack (as, bs)))

University of Oxford — Ralf Hinze

77-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Counterexample: nats and squares

nats : Nat → νSequ nats n = Out ◦ (Next (n, squares n)) squares : Nat → νSequ squares n = Out ◦ (Next (n∗n, nats (n + 1)))

University of Oxford — Ralf Hinze

78-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Adjoint fixed-point equations

Idea: model the context by a functor. x · L in = Ψ x

R out · x = Ψ x

Requirement: the functors have to be adjoint: L a R.

University of Oxford — Ralf Hinze

79-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Adjoint initial fixed-point equations

An adjoint initial fixed-point equation in the unknown x ∈ C(L (µF), A) has the syntactic form x · L in = Ψ x , where the base function Ψ has type Ψ : ∀ X : D . C(L X , A) → C(L (F X ), A) . The unique solution is called an adjoint fold. Furthermore, φ x is called the transposed fold.

University of Oxford — Ralf Hinze

80-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Proof of uniqueness x · L in = Ψ x ⇐⇒

{ adjunction } φ (x · L in) = φ (Ψ x)

⇐⇒

{ naturality of φ: φ f · h = φ (f · L h) } φ x · in = φ (Ψ x)

⇐⇒

{ adjunction } φ x · in = (φ · Ψ · φ◦ ) (φ x)

⇐⇒

⇐⇒

{ universal property of Mendler-style folds } φ x = L φ · Ψ · φ◦ MId { adjunction }

x = φ◦ L φ · Ψ · φ◦ MId University of Oxford — Ralf Hinze

81-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Adjoint folds

x = L Ψ ML

⇐⇒ x · L in = Ψ x

University of Oxford — Ralf Hinze

82-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Banana-split law

L Φ ML  L Ψ ML

University of Oxford — Ralf Hinze

= L λ x . Φ (outl · x)  Ψ (outr · x) ML

83-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Proof of banana-split law

=

=

=

(L Φ ML  L Ψ ML ) · L in { split-fusion }

L Φ ML · L in  L Ψ ML · L in

{ fold-computation }

Φ L Φ ML  Ψ L Ψ ML

{ split-computation }

Φ (outl · (L Φ ML  L Ψ ML ))  Ψ (outl · (L Φ ML  L Ψ ML ))

University of Oxford — Ralf Hinze

84-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Adjoint final fixed-point equations

An adjoint final fixed-point equation in the unknown x ∈ D(A, R (νF)) has the syntactic form R out · x

= Ψx ,

where the base function Ψ has type Ψ : ∀ X : C . D(A, R X ) → D(A, R (F X )) . The unique solution is called an adjoint unfold.

University of Oxford — Ralf Hinze

85-172

Generic Programming with Adjunctions

3.3

Adjoint folds and unfolds

3.3

Adjoint unfolds

x = [(Ψ)]R

⇐⇒ R out · x = Ψ x

University of Oxford — Ralf Hinze

86-172

Generic Programming with Adjunctions

4.0

Part 4

Adjunctions

University of Oxford — Ralf Hinze

87-172

Generic Programming with Adjunctions

4.0

4.0

Outline

14. Identity 15. Currying 16. Mutual Value Recursion 17. Type Application 18. Type Composition

University of Oxford — Ralf Hinze

88-172

Generic Programming with Adjunctions

4.1

Identity

4.1

Recall: Adjoint fixed-point equations

x · L in = Ψ x

R out · x = Ψ x

Requirement: the functors have to be adjoint: L a R.

University of Oxford — Ralf Hinze

89-172

Generic Programming with Adjunctions

4.1

Identity

4.1

Identity

C



Id ⊥ Id



C

φ : ∀A B . C(Id A, B) › C(A, Id B)

Adjoint fixed-point equations subsume Mendler-style ones.

University of Oxford — Ralf Hinze

90-172

Generic Programming with Adjunctions

4.2

Currying

4.2

Recall: stack

stack : (µStack, Stack) → Stack stack (In (Empty), bs) = bs stack (In (Push (a, as)), bs) = In (Push (a, stack (as, bs))) The type µStack is embedded in a context L: L A = A × Stack L f = f × id Stack .

University of Oxford — Ralf Hinze

91-172

Generic Programming with Adjunctions

4.2

Currying

4.2

Currying

C



−×X C ⊥  X (−)

φ : ∀ A B . C(A × X , B) › C(A, B X )

University of Oxford — Ralf Hinze

92-172

Generic Programming with Adjunctions

4.2

Currying

4.2

Specialising adjoint equations

x · L in = Ψ x ⇐⇒

{ definition of L }

R out · x = Ψ x ⇐⇒

x · (in × id) = Ψ x ⇐⇒

{ pointwise } x (in a, c) = Ψ x (a, c)

University of Oxford — Ralf Hinze

{ definition of R } (out·) · x = Ψ x

⇐⇒

{ pointwise } out (x a c) = Ψ x a c

93-172

Generic Programming with Adjunctions

4.2

Currying

4.2

stack as an adjoint fold

stack : ∀ x . (L x → Stack) → (L (Stack x) → Stack) stack stack (Empty, bs) = bs stack stack (Push (a, as), bs) = In (Push (a, stack (as, bs))) stack : L (µStack) → Stack stack (In as, bs) = stack stack (as, bs)

University of Oxford — Ralf Hinze

94-172

Generic Programming with Adjunctions

4.2

Currying

4.2

The transpose of stack

R A = AStack R f = f id Stack The transposed fold is the curried variant of stack. stack : µStack → R Stack stack (In Empty) = λbs → bs stack (In (Push (a, as))) = λbs → In (Push (a, stack as bs))

University of Oxford — Ralf Hinze

95-172

Generic Programming with Adjunctions

4.2

Currying

4.2

Recall: append

append : ∀ a . (List a, List a) → List a append (Nil, bs) = bs append (Cons (a, as), bs) = Cons (a, append (as, bs))

University of Oxford — Ralf Hinze

96-172

Generic Programming with Adjunctions

4.2

Currying

4.2

Two-level types

data LIST list a = Nil | Cons (a, list a) instance (Functor list) ⇒ Functor (LIST list) where fmap f (Nil) = Nil fmap f (Cons (a, as)) = Cons (f a, fmap f as) append : ∀ a . (µLIST a, List a) → List a append (In (Nil), bs) = bs append (In (Cons (a, as)), bs) = In (Cons (a, append (as, bs)))

University of Oxford — Ralf Hinze

97-172

Generic Programming with Adjunctions

4.2

Currying

4.2

append as a natural transformation

˙ G) A = F A × G A, we can view append as a Definining (F × natural transformation: ˙ List → append : List × ˙ List. ˙ H. We have to find the right adjoint of the lifted product − ×

University of Oxford — Ralf Hinze

98-172

Generic Programming with Adjunctions

4.2

Currying

4.2

Deriving the right adjoint GH A ›

{ Yoneda lemma } C(A, −) → ˙ GH

›

˙ H a −H } { requirement: − × ˙ H→ C(A, −) × ˙G

›

{ natural transformation } ∀ X : C . C(A, X ) × H X → G X

›

{ − × X a −X } ∀ X : C . C(A, X ) → (G X )H X .

NB We assume that the functor category is SetC so GH : C → Set. University of Oxford — Ralf Hinze

99-172

Generic Programming with Adjunctions

4.2

Currying

4.2

The transpose of append

append 0 : List → ˙ ListList In Haskell: append 0 : ∀ a . List a → ∀ x . (a → x) → (List x → List x) append 0 as = λf → λbs → append (fmap f as, bs). NB append 0 combines append with fmap.

University of Oxford — Ralf Hinze

100-172

Generic Programming with Adjunctions

4.3

Mutual Value Recursion

4.3

Recall: nats and squares

nats : Nat → νSequ nats n = Out ◦ (Next (n, squares n)) squares : Nat → νSequ squares n = Out ◦ (Next (n∗n, nats (n + 1)))

University of Oxford — Ralf Hinze

101-172

Generic Programming with Adjunctions

4.3

Mutual Value Recursion

4.3

Speaking categorically

numbers : hNat, Nati → ∆(νSequ)

University of Oxford — Ralf Hinze

102-172

Generic Programming with Adjunctions

4.3

Mutual Value Recursion

4.3

Adjoints of the diagonal functor

φ : ∀ A B . C((+) A, B) › (C × C)(A, ∆B)

C



+ ⊥ ∆



C×C



∆ ⊥ ×



C

φ : ∀ A B . (C × C)(∆A, B) › C(A, (×) B)

University of Oxford — Ralf Hinze

103-172

Generic Programming with Adjunctions

4.3

Mutual Value Recursion

4.3

Specialising adjoint equations

∆out · x = Ψ x ⇐⇒ out · x1 = Ψ1 hx1 , x2 i and

out · x2 = Ψ2 hx1 , x2 i

Here, x1 = Outl x, x2 = Outr x, Ψ1 = Outl · Ψ and Ψ2 = Outr · Ψ.

University of Oxford — Ralf Hinze

104-172

Generic Programming with Adjunctions

4.3

Mutual Value Recursion

4.3

The transpose of nats and squares

numbers : Either Nat Nat → νSequ numbers (Left n) = ◦ Out (Next (n, numbers (Right n))) numbers (Right n) = ◦ Out (Next (n∗n, numbers (Left (n + 1))))

University of Oxford — Ralf Hinze

105-172

Generic Programming with Adjunctions

4.3

Mutual Value Recursion

4.3

A special case: paramorphisms

fac : µNat → Nat fac (In (Z)) = 1 fac (In (S n)) = In (S (id n))∗fac n id : µNat → Nat id (In (Z)) = In Z id (In (S n)) = In (S (id n))

University of Oxford — Ralf Hinze

106-172

Generic Programming with Adjunctions

4.3

Mutual Value Recursion

4.3

A special case: histomorphisms

fib : µNat → Nat fib (In (Z)) = 0 fib (In (S n)) = fib 0 n fib 0 : µNat → Nat fib 0 (In (Z)) = 1 fib 0 (In (S n)) = fib n + fib 0 n

University of Oxford — Ralf Hinze

107-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Recall: sum

data List a = Nil | Cons (a, List a) sum : List Nat → Nat sum (Nil) =0 sum (Cons (a, as)) = a + sum as

University of Oxford — Ralf Hinze

108-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Likewise for perfect trees

sump : Perfect Nat → Nat sump (Zero n) =n sump (Succ p) = sump (fmap plus p) plus (a, b) = a + b NB The recursive call is not applied to a subterm of Succ p.

University of Oxford — Ralf Hinze

109-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Speaking categorically

sum : AppNat List → ˙ K Nat where AppX : CD → C AppX F = F X AppX α = α X .

University of Oxford — Ralf Hinze

110-172

Generic Programming with Adjunctions

Type Application

4.4

φ : ∀ A B . CD (LshX A, B) › C(A, AppX B)

D

C



LshX ⊥ AppX



C



AppX ⊥ CD  RshX

φ : ∀ A B . C(AppX A, B) › CD (A, RshX B)

University of Oxford — Ralf Hinze

111-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Deriving the left adjoint C(A, AppX B) ›

{ definition of AppX } C(A, B X )

›

{ Yoneda } ∀ Y : D . D(X , Y ) → C(A, B Y )

P { definition of a copower: Ix → C(X , Y ) › C( Ix . X , Y ) } P ∀ Y : D . C( D(X , Y ) . A, B Y ) P › { define LshX A = Λ Y : D . D(X , Y ) . A }

›

∀ Y : D . C(LshX A Y , B Y ) ›

{ natural transformation } LshX A → ˙B

University of Oxford — Ralf Hinze

112-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Left shifts in Haskell

newtype Lshx a y = Lsh (x → y, a) instance Functor (Lshx a) where fmap f (Lsh (κ, a)) = Lsh (f · κ, a) φLsh : (∀ y . Lshx a y → b y) → (a → b x) φLsh α = λs → α (Lsh (id, s)) φ◦Lsh : (Functor b) ⇒ (a → b x) → (∀ y . Lshx a y → b y) φ◦Lsh g = λ(Lsh (κ, s)) → fmap κ (g s)

University of Oxford — Ralf Hinze

113-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Right shifts in Haskell

newtype Rshx b y = Rsh {rsh◦ : (y → x) → b } instance Functor (Rshx b) where fmap f (Rsh g) = Rsh (λκ → g (κ · f )) φRsh : (Functor a) ⇒ (a x → b) → (∀ y . a y → Rshx b y) φRsh f = λs → Rsh (λκ → f (fmap κ s)) φ◦Rsh : (∀ y . a y → Rshx b y) → (a x → b) φ◦Rsh β = λs → rsh◦ (β s) id

University of Oxford — Ralf Hinze

114-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Specialising adjoint equations

x · AppX in = Ψ x ⇐⇒

{ definition of AppX } x · in X = Ψ x

University of Oxford — Ralf Hinze

115-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

The transpose of sump

sump 0 : ∀ x . Perfect x → (x → Nat) → Nat sump 0 (Zero n) = λκ → κn 0 sump (Succ p) = λκ → sump 0 p (plus · (κ × κ))

University of Oxford — Ralf Hinze

116-172

Generic Programming with Adjunctions

4.4

Type Application

4.4

Relation to Generic Haskell

sump 0 : ∀ x . (x → Nat) → (Perfect x → Nat) sump 0 sumx (Zero n) = sumx n 0 sump sumx (Succ p) = 0 sump (plus · (sumx × sumx)) p

University of Oxford — Ralf Hinze

117-172

Generic Programming with Adjunctions

4.5

Type Composition

4.5

Recall: concat

concat : ∀ a . List (List a) → List a concat (Nil) = Nil concat (Cons (l, ls)) = append (l, concat ls)

University of Oxford — Ralf Hinze

118-172

Generic Programming with Adjunctions

4.5

Type Composition

4.5

Speaking categorically

concat : PreList (µLIST) → ˙ List where PreJ : ED → EC PreJ F = F ◦ J PreJ α = α ◦ J.

University of Oxford — Ralf Hinze

119-172

Generic Programming with Adjunctions

Type Composition

4.5

φ : ∀ F G . ED (LanJ F, G) › EC (F, G ◦ J)

C

≺ ≺ E≺

F

J

G

… D

C E

D



LanJ (− ◦ J) C ≺ ⊥ E ⊥ ED   (− ◦ J) RanJ

LanJ F

J … D

G

F RanJ G

 E 

φ : ∀ F G . EC (F ◦ J, G) › ED (F, RanJ G)

University of Oxford — Ralf Hinze

120-172

Generic Programming with Adjunctions

Type Composition

4.5

F◦J→ ˙G ›

{ natural transformation as an end } ∀ A : C . E(F (J A), G A)

›

{ Yoneda } ∀ A : C . ∀ X : D . D(X , J A) → E(F X , G A) Q

Ix . B) }

›

{ definition of power: Ix → C(A, B) › C(A, Q ∀ A : C . ∀ X : D . E(F X , D(X , J A) . G A)

›

{ interchange of quantifiers } Q ∀ X : D . ∀ A : C . E(F X , D(X , J A) . G A)

›

{ the functor E(F X , −) preserves ends } Q ∀ X : D . E(F X , ∀ A : C . D(X , J A) . G A) Q { define RanJ G = Λ X : D . ∀ A : C . D(X , J A) . G A }

›

∀ X : D . E(F X , RanJ G X ) ›

{ natural transformation as an end } F→ ˙ RanJ G

University of Oxford — Ralf Hinze

121-172

Generic Programming with Adjunctions

4.5

Type Composition

4.5

Right Kan extensions in Haskell

newtype Rani g x = Ran {ran◦ : ∀ a . (x → i a) → g a} instance Functor (Rani g) where fmap f (Ran h) = Ran (λκ → h (κ · f )) φRan : (Functor f ) ⇒ (∀ x . f (i x) → g x) → (∀ x . f x → Rani g x) φRan α = λs → Ran (λκ → α (fmap κ s)) φ◦Ran : (∀ x . f x → Rani g x) → (∀ x . f (i x) → g x) φ◦Ran β = λs → ran◦ (β s) id

University of Oxford — Ralf Hinze

122-172

Generic Programming with Adjunctions

4.5

Type Composition

4.5

Left Kan extensions in Haskell

data Lani f x = ∀ a . Lan (i a → x, f a) instance Functor (Lani f ) where fmap f (Lan (κ, s)) = Lan (f · κ, s) φLan : (∀ x . Lani f x → g x) → (∀ x . f x → g (i x)) φLan α = λs → α (Lan (id, s)) φ◦Lan : (Functor g) ⇒ (∀ x . f x → g (i x)) → (∀ x . Lani f x → g x) φ◦Lan β = λ(Lan (κ, s)) → fmap κ (β s)

University of Oxford — Ralf Hinze

123-172

Generic Programming with Adjunctions

4.5

Type Composition

4.5

The transpose of concat

concat 0 : ∀ a b . µLIST a → (a → List b) → List b concat 0 as = λκ → concat (fmap κ as) The transpose of concat is the bind of the list monad (written >>= in Haskell)!

University of Oxford — Ralf Hinze

124-172

Generic Programming with Adjunctions

adjunction LaR Id a Id (− × X ) a (−X )

(+) a ∆

Type Composition

initial fixed-point equation x · L in = Ψ x φ x · in = (φ · Ψ · φ◦ ) (φ x)

final fixed-point equation R out · x = Ψ x out · φ◦ x = (φ◦ · Ψ · φ) (φ◦ x)

standard fold standard fold parametrised fold fold to an exponential recursion from a coproduct of mutually recursive types mutual value recursion on mutually recursive types

standard unfold standard unfold curried unfold unfold from a pair

mutual value recursion ∆ a (×)

single recursion to a product domain

mutual value recursion single recursion from a coproduct domain recursion to a product of mutually recursive types mutual value recursion on mutually recursive types monomorphic unfold unfold from a left shift

LshX a (− X )



(− X ) a RshX

monomorphic fold fold to a right shift



LanJ a (− ◦ J)



polymorphic unfold unfold from a left Kan extension

(− ◦ J) a RanJ

polymorphic fold fold to a right Kan extension



University of Oxford — Ralf Hinze

4.5

125-172

Generic Programming with Adjunctions

5.0

Part 5

Application: Type fusion

University of Oxford — Ralf Hinze

126-172

Generic Programming with Adjunctions

5.0

5.0

Outline

19. Memoisation 20. Fusion 21. Type fusion 22. Application: firstification 23. Application: type specialisation 24. Application: tabulation

University of Oxford — Ralf Hinze

127-172

Generic Programming with Adjunctions

5.1

Memoisation

5.1

Memoisation

Say, you want to memoise the function f : Nat → V so that it caches previously computed values.

University of Oxford — Ralf Hinze

128-172

Generic Programming with Adjunctions

Memoisation

5.1

Given the interface data Table v lookup : ∀ v . Table v → (Nat → v) tabulate : ∀ v . (Nat → v) → Table v, we can memoize f as follows memo-f : Nat → V memo-f = lookup (tabulate f ).

University of Oxford — Ralf Hinze

129-172

Generic Programming with Adjunctions

5.1

Memoisation

5.1

Implementing Table

data Nat

= Zero | Succ Nat

data Table v = Node {zero : v, succ : Table v } lookup (Node {zero = t }) Zero =t lookup (Node {succ = t }) (Succ n) = lookup t n tabulate f = Node {zero = f Zero, succ = tabulate (λn → f (Succ n))}

University of Oxford — Ralf Hinze

130-172

Generic Programming with Adjunctions

5.2

Fusion

5.2

Fusion for adjoint folds

Let α : ∀ X ∈ D . C(L X , B) → C0 (L0 X , B 0 ), then α L Ψ ML = L Ψ 0 ML0

⇐=

α · Ψ = Ψ 0 · α.

NB This subsumes the fusion law for folds.

University of Oxford — Ralf Hinze

131-172

Generic Programming with Adjunctions

5.2

Fusion

5.2

Proof of fusion

=

=

=

α L Ψ ML · L0 in

{ naturality of α: α x · L0 h = α (x · L h) }

α (L Ψ ML · L in)

{ computation }

α (Ψ L Ψ ML )

{ assumption α · Ψ = Ψ 0 · α }

Ψ 0 (α L Ψ ML )

University of Oxford — Ralf Hinze

132-172

Generic Programming with Adjunctions

5.3

Type fusion

5.3

Type fusion

C≺

G G

C



L ⊥ R



D≺

L (µF) › µG

⇐=

L◦F›G◦L

νF › R (νG)

⇐=

F◦R›R◦G

University of Oxford — Ralf Hinze

F F

D

133-172

Generic Programming with Adjunctions

τ : L (µF) › µG

University of Oxford — Ralf Hinze

Type fusion

⇐=

5.3

swap : L ◦ F › G ◦ L

134-172

Generic Programming with Adjunctions

5.3

Type fusion

5.3

Definition of τ and τ ◦

G (L (µF)) ≺ Gτ p  a w ◦ s Gτ ◦ p a ≺ sw L (F (µF)) L in L in … L (µF) ≺

τ·L in = in·G τ·swap

University of Oxford — Ralf Hinze

τ◦ τ

and

 G (µG)

in in …  µG

τ ◦ ·in = L in·swap ◦ ·G τ ◦

135-172

Generic Programming with Adjunctions

Type fusion

5.3

Proof of τ · τ ◦ = id µG

5.3

(τ · τ ◦ ) · in =

{ definition of τ ◦ } τ · L in · swap ◦ · G τ ◦

=

{ definition of τ } in · G τ · swap · swap ◦ · G τ ◦

=

{ inverses } in · G τ · G τ ◦

=

{ G functor } in · G (τ · τ ◦ )

The equation x · in = in · G x has a unique solution. Since id is also a solution, the result follows. University of Oxford — Ralf Hinze

136-172

Generic Programming with Adjunctions

Type fusion

5.3

Proof of τ ◦ · τ = id L (µF)

5.3

(τ ◦ · τ) · L in =

{ definition of τ } ◦

τ · in · G τ · swap =

{ definition of τ ◦ } L in · swap ◦ · G τ ◦ · G τ · swap

=

{ G functor } L in · swap ◦ · G (τ ◦ · τ) · swap

Again, x · L in = L in · swap ◦ · G x · swap has a unique solution. And again, id is also solution, which implies the result. University of Oxford — Ralf Hinze

137-172

Generic Programming with Adjunctions

5.4

Application: firstification

5.4

Application: firstification

data Stack = Empty | Push (Nat, Stack) data List a = Nil | Cons (a, List a)

List Nat

› Stack

University of Oxford — Ralf Hinze

138-172

Generic Programming with Adjunctions

5.4

Application: firstification

5.4

Speaking categorically

AppNat (µLIST) › µStack ⇐= AppNat ◦ LIST › Stack ◦ AppNat

University of Oxford — Ralf Hinze

139-172

Generic Programming with Adjunctions

5.4

Application: firstification

5.4

Proof of AppNat ◦ LIST › Stack ◦ AppNat

AppNat ◦ LIST ›

{ composition of functors and definition of App } Λ X . LIST X Nat

›

{ definition of LIST } Λ X . 1 + Nat × X Nat

›

{ definition of Stack } Λ X . Stack (X Nat)

›

{ composition of functors and definition of App } Stack ◦ AppNat

University of Oxford — Ralf Hinze

140-172

Generic Programming with Adjunctions

5.4

Application: firstification

5.4

In Haskell swap : ∀ x . LIST x Nat → Stack (x Nat) swap Nil = Empty swap (Cons (n, x)) = Push (n, x) swap ◦ : ∀ x . Stack (x Nat) → LIST x Nat swap ◦ Empty = Nil ◦ swap (Push (n, x)) = Cons (n, x) Λ-lift : µStack → µLIST Nat Λ-lift (In x) = In (swap ◦ (fmap Λ-lift x)) Λ-drop : µLIST Nat → µStack Λ-drop (In x) = In (fmap Λ-drop (swap x))

University of Oxford — Ralf Hinze

141-172

Generic Programming with Adjunctions

5.5

Application: type specialisation

5.5

Application: type specialisation

Lists of optional values, List ◦ Maybe with data Maybe a = Nothing | Just a, can be represented more compactly using the tailor-made data Sequ a = Done | Skip (Sequ a) | Yield (a, Sequ a).

University of Oxford — Ralf Hinze

142-172

Generic Programming with Adjunctions

5.5

Application: type specialisation

5.5

Speaking categorically

List ◦ Maybe › Sequ,

PreMaybe (µLIST) › µSEQU ⇐= PreMaybe ◦ LIST › SEQU ◦ PreMaybe

University of Oxford — Ralf Hinze

143-172

Generic Programming with Adjunctions

5.5

Application: type specialisation

5.5

Proof of PreMaybe ◦ LIST › SEQU ◦ PreMaybe LIST X ◦ Maybe ›

{ composition of functors } Λ A . LIST X (Maybe A)

›

{ definition of LIST } Λ A . 1 + Maybe A × X (Maybe A)

›

{ definition of Maybe } Λ A . 1 + (1 + A) × X (Maybe A)

›

{ × distributes over + and 1 × B › B } Λ A . 1 + X (Maybe A) + A × X (Maybe A)

›

{ composition of functors } Λ A . 1 + (X ◦ Maybe) A + A × (X ◦ Maybe) A

›

{ definition of SEQU } SEQU (X ◦ Maybe)

University of Oxford — Ralf Hinze

144-172

Generic Programming with Adjunctions

5.5

Application: type specialisation

5.5

In Haskell

swap : ∀ x . ∀ a . LIST x (Maybe a) → SEQU (x ◦ Maybe) a swap (Nil) = Done swap (Cons (Nothing, x)) = Skip x swap (Cons (Just a, x)) = Yield (a, x)

University of Oxford — Ralf Hinze

145-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Recall Nat and Table

data Nat

= Zero | Succ Nat

data Table val = Node {zero : val, succ : Table val }

V Nat

› Table V

University of Oxford — Ralf Hinze

146-172

Generic Programming with Adjunctions

(−)Nat

Application: tabulation

5.6

› Table

University of Oxford — Ralf Hinze

147-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Truth tables

(∧) : Bool Bool×Bool

University of Oxford — Ralf Hinze

False False

False True

148-172

Generic Programming with Adjunctions

(−)Bool×Bool

University of Oxford — Ralf Hinze

Application: tabulation

5.6

˙ Id) × ˙ (Id × ˙ Id) › (Id ×

149-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Laws of exponentials

V0

› 1

1

› V

V

V A+B

› VA × VB

V A×B

› (V B )A

University of Oxford — Ralf Hinze

150-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Curried exponentiation

Exp : C → (CC )op Exp K = Λ V . V K Exp f = Λ V . (id V )f

University of Oxford — Ralf Hinze

151-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Laws of exponentials

Exp 0

› K1

Exp 1

› Id

˙ Exp B Exp (A + B) › Exp A × Exp (A × B) › Exp A · Exp B

University of Oxford — Ralf Hinze

152-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Exp is a left adjoint

C op

(C )



G G

University of Oxford — Ralf Hinze

C op

 (C )



Exp ⊥ Sel



C≺

F F

C

153-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Deriving the right adjoint (CC )op (Exp A, B) ›

{ definition of −op } C

C (B, Exp A) ›

{ natural transformation as an end } ∀ X ∈ C . C(B X , Exp A X )

›

{ definition of Exp } ∀ X ∈ C . C(B X , X A )

›

{ − × Y a (−)Y and Y × Z › Z × Y } ∀ X ∈ C . C(A, X B X )

›

{ the functor C(A, −) preserves ends } C(A, ∀ X ∈ C . X B X )

›

{ define Sel B = ∀ X ∈ C . X B X } C(A, Sel B)

University of Oxford — Ralf Hinze

154-172

Generic Programming with Adjunctions

C op

(C )



G G

Application: tabulation

C op

 (C )



Exp ⊥ Sel



C≺

5.6

F F

C

Since Exp is a contra-variant functor, τ and swap live in an opposite category. Type fusion in terms of arrows in CC : τ : νG › Exp (µF)

University of Oxford — Ralf Hinze

⇐=

swap : G ◦ Exp › Exp ◦ F.

155-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

Look-up and tabulate

The isomorphism τ : νG → ˙ Exp (µF) is a curried look-up function that maps a memo table to an exponential. lookup (Out ◦ t) (in i) = swap (G lookup t) i The inverse τ ◦ : Exp (µF) → ˙ νG is a transformation that tabulates a given exponential. tabulate f = Out ◦ (G tabulate (swap ◦ (f · in)))

University of Oxford — Ralf Hinze

156-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

In Haskell

The transformation swap implements V × V X › V 1+X . swap : ∀ x . ∀ val . TABLE (Exp x) val → (Nat x → val) swap (Node (v, t)) (Zero) = v swap (Node (v, t)) (Succ n) = t n The inverse of swap implements V 1+X › V × V X . swap ◦ : ∀ x . ∀ val . (Nat x → val) → TABLE (Exp x) val swap ◦ f = Node (f Zero, f · Succ)

University of Oxford — Ralf Hinze

157-172

Generic Programming with Adjunctions

5.6

Application: tabulation

5.6

In Haskell

lookup : ∀ val . νTABLE val → (µNat → val) lookup (Out ◦ (Node (v, t))) (In Zero) =v lookup (Out ◦ (Node (v, t))) (In (Succ n)) = lookup t n tabulate : ∀ val . (µNat → val) → νTABLE val tabulate f = Out ◦ (Node (f (In Zero), tabulate (f · In · Succ)))

University of Oxford — Ralf Hinze

158-172

Generic Programming with Adjunctions

6.0

Part 6

Epilogue

University of Oxford — Ralf Hinze

159-172

Generic Programming with Adjunctions

6.0

6.0

Summary

• Adjoint (un-) folds capture many recursion schemes. • Adjunctions play a central role. • Tabulation is an intriguing example.

University of Oxford — Ralf Hinze

160-172

Generic Programming with Adjunctions

6.0

6.0

Limitations

• Simultaneous recursion doesn’t fit under the umbrella.

zip zip zip zip

: (List a, List b) → List (a, b) (Nil, bs) = Nil (as, Nil) = Nil (Cons (a, as), Cons (b, bs)) = Cons ((a, b), zip (as, bs))

• However, one can establish

x = L Ψ M×

⇐⇒ x · (×) in = Ψ x

using a different technique (colimits). See, R. Bird, R. Paterson: Generalised folds for nested datatypes.

University of Oxford — Ralf Hinze

161-172

Generic Programming with Adjunctions

7.0

Part 7

Tagless interpreters

University of Oxford — Ralf Hinze

162-172

Generic Programming with Adjunctions

7.0

7.0

Initial algebras: view from the left

data Expr 0 = Lit Nat | Add (Expr 0 , Expr 0 ) e0 : Expr 0 e0 = Add (Lit 4700, Lit 11)

University of Oxford — Ralf Hinze

163-172

Generic Programming with Adjunctions

7.0

data Expr expr = Lit Nat | Add (expr, expr) The evaluation algebra. eval 0 : Expr Nat → Nat eval 0 (Lit n) =n eval 0 (Add (n1 , n2 )) = n1 + n2 The fold for expressions. fold 0 : ∀ val . (Expr val → val) → (Expr 0 → val) fold 0 alg (Lit n) = alg (Lit n) fold 0 alg (Add (e1 , e2 )) = alg (Add (fold 0 alg e1 , fold 0 alg e2 ))

University of Oxford — Ralf Hinze

164-172

Generic Programming with Adjunctions

7.0

C(Expr Val, Val) ›

{ definition of Expr } C(Nat + (Val × Val), Val)

›

{ (+) a ∆ } (C × C)(hNat, Val × Vali, ∆Val)

›

{ product categories } C(Nat, Val) × C(Val × Val, Val)

data Alg val = Alg {lit : Nat → val, add : (val, val) → val }

University of Oxford — Ralf Hinze

165-172

Generic Programming with Adjunctions

7.0

data Alg val = Alg {lit : Nat → val, add : (val, val) → val } The evaluation algebra. eval 0 : Alg Nat eval 0 = Alg {lit = id, add = λ(n1 , n2 ) → n1 + n2 } The fold for expressions. fold 0 : ∀ val . Alg val → (Expr 0 → val) fold 0 alg (Lit n) = lit alg n fold 0 alg (Add (e1 , e2 )) = add alg (fold 0 alg e1 , fold 0 alg e2 )

University of Oxford — Ralf Hinze

166-172

Generic Programming with Adjunctions

7.0

7.0

Initial algebras: view from the right

∀ val . Alg val → (Expr 0 → val) ›

{ A → (B → C) › B → (A → C) } ∀ val . Expr 0 → (Alg val → val)

›

{ ∀a . A → Ta › A → ∀a . Ta } Expr 0 → (∀ val . Alg val → val)

University of Oxford — Ralf Hinze

167-172

Generic Programming with Adjunctions

7.0

7.0

. . . using records

newtype Expr 1 = Expr {fold 1 : ∀ val . Alg val → val } e1 : Expr 1 e1 = Expr {fold 1 = λalg → add alg (lit alg 4700, lit alg 11)} Converting between the left and right view. toRight : Expr 0 → Expr 1 toRight e = Expr {fold 1 = λi → fold 0 i e} toLeft : Expr 1 → Expr 0 toLeft e = fold 1 e (Alg {lit = Lit, add = Add })

University of Oxford — Ralf Hinze

168-172

Generic Programming with Adjunctions

7.0

7.0

. . . using classes class Alg val where {lit : Nat → val; add : (val, val) → val } e1 : (Alg val) ⇒ val e1 = add (lit 4700, lit 11)

Converting between the left and right view. toRight : (Alg val) ⇒ Expr 0 → val toRight e = fold 0 (Alg {lit = lit, add = add }) e instance Alg Expr 0 where {lit = Lit; add = Add } toLeft : Expr 0 → Expr 0 toLeft e = e University of Oxford — Ralf Hinze

169-172

Generic Programming with Adjunctions

7.0

7.0

Parametricity ∀ A . (F A → A) → A

(φ, φ) ∈ ∀ A . (F A → A) → A ⇐⇒

{ polymorphic type } ∀ h . (φ A1 , φ A2 ) ∈ (F h → h) → h

⇐⇒

{ function type } ∀ h . ∀ f1 f2 . (f1 , f2 ) ∈ F h → h =⇒ (φ A1 f1 , φ A2 f2 ) ∈ h

⇐⇒

{ base } ∀ h . ∀ f1 f2 . (f1 , f2 ) ∈ F h → h =⇒ h (φ A1 f1 ) = φ A2 f2

⇐⇒

{ function type } ∀ h . ∀ f1 f2 . h · f1 = f2 · F h =⇒ h (φ A1 f1 ) = φ A2 f2

University of Oxford — Ralf Hinze

170-172

Generic Programming with Adjunctions

7.0

7.0

An isomorphism

toRight i toLeft f

= λ a . LaM i

= f in

toLeft (toRight i) { definition of toRight }

=

=

=

toLeft (λ a . L a M i)

{ definition of toLeft }

L in M i

{ reflection }

i University of Oxford — Ralf Hinze

171-172

Generic Programming with Adjunctions

toRight i toLeft f

7.0

= λ a . LaM i = f in

toRight (toLeft f ) { definition of toLeft }

=

toRight (f in) { definition of toRight }

=

=

λ a . L a M (f in)

{ parametricity with L a M · in = a · F L a M }

λa . f a

{ extensionality }

= f

University of Oxford — Ralf Hinze

172-172