2 minute read

Recap for Product/Sum TypesPermalink

Brief recap for product and sum to have a consensus on notations.

Product TypesPermalink

τ1×τ2

IntroductionsPermalink

Γe1:τ2,Γe2:τ2Γ⊢<e1,e2>:τ1×τ2

EliminationsPermalink

Γe:τ1×τ2Γfst(e):τ1 Γe:τ1×τ2Γsnd(e):τ2

Sum TypesPermalink

τ1+τ2

IntroductionPermalink

Γe1:τ1Γinlτ1,τ2(e1):τ1+τ2 Γe2:τ2Γinrτ1,τ2(e2):τ1+τ2

EliminationsPermalink

Γe:τ1+τ2;Γ,x1:τ2e1:σ;Γ,x2:τ2e2:σΓcase(e)of{inl(x1)e1,inr(x2)e2}:σ

UnitPermalink

Γ⊢<>:unit

Recursive Types in a Partial LanguagePermalink

ExamplesPermalink

Natural NumbersPermalink

We can write

Nunit+N

where means “type isomorphism” which means to write functions back and forth that compose to the identity.

From left to right:

λx:N:=rec{0inl(<>),s(y)inr(y)}

From right to left:

λx:unit+N:=case(z)of{inl(_)0,inr(y)s(y)}

It works because anything is observationally equivalent to <> at type unit:

_unit<>

ListsPermalink

Any list is either the empty list or a cons with the type and another list.

τlistunit+(τ×τlist)

From left to right:

λl:τlist:=case(l)of{[]inl(<>),x::xsinr(x,xs)}

ConstructionPermalink

What we’ve got here is that: certain types can be characterize as solutions to equations of the form:

tσ(t)

N solves t=unit+t

τlist solves t=unit+(τ×t)

Δ,t typeτ typeΔrec(t.τ) type

which is a/the solution to tτ(t). i.e.

rec(t.τ)[rec(t.τ)/t]τ

IntroductionsPermalink

Γe:[rec(t.τ)/t]τΓfold(e):rec(t.τ)

EliminationsPermalink

Γe:rec(t.τ)Γunfold(e):[rec(t.τ)/t]τ

DynamicsPermalink

unfold(fold(e))e

Examples using Recursive TypesPermalink

N:=rec(t.unit+t) z:N:=fold(inl(<>)) s(e):N:=fold(inr(e))

Bridging Recursive Types and ProgramsPermalink

In this language, even though there is no loops, no recursive functions in the terms, we can still get general recursion just from self-referencial types. Meaning that self-referential types will give us self-referential codes. How to do?

  1. Define a type of self-referential programs, and get fix(x.e) from it
  2. Define the type of self-referential programs from rec(t.τ)

Self TypesPermalink

The following thing is only used as a bridge between fix and rec such that we can define both fix and rec from it. It’s only to help the constructions.

In the following rules, x could be interpreted as this in a normal programming language.

τself represents a self-referential computation of a τ

IntroductionsPermalink

Γ,x:τselfe:τΓself(x.e):τself

EliminationsPermalink

Γe:τselfΓunroll(e):τ

DynamicsPermalink

self(x.e) value eeunroll(e)unroll(e) unroll(self(x.e))[self(x.e)/x]e

Construct Recursive ProgramsPermalink

Now we have τself, the above two steps can be rephrased as:

  1. We want to get a recursive computation of any type, i.e. fix(x.e):τ, from self types τself
  2. We want to get self types τself from recursive types rec(x.e)

From Recursive Computation to Self TypesPermalink

We have τself, and we want:

x:τe:τfix(x.e):τ fix(x.e)[fix(x.e)/x]e

Solution:

fix(x.e):τ:=unroll(self(y:τself.[unroll(y)/x]e))

From Self Types to Recursive TypesPermalink

We want to solve:

τselfτselfτ

Solution:

τself:=rec(t.(tτ)) self(x.e):=fold(λ(x:τself).(e:τ)) unroll(e):=(unfold(e):τselfτ)(e)

Comments