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◦FG◦L
νF R (νG)
⇐=
F◦RR◦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