a logic (Curry-Howard) • Types are to propositions as programs are to proofs • Fine-grained types with inherent correctness properties • Must rewrite “standard library” functions for each fine- grained type • Program correctness at the expense of code reuse
functions • Generic functions work over all types defined now and all types defined in the future • Generic functions do not need to be edited when a new type is declared • Dependent typing ensures generic functions are well-typed! • By being defined over a closed universe of user-declared types
A ! List A ! List A append A nil ys = ys append A (cons x xs) ys = cons x (append A xs ys) data List (A : Set) : Set where nil : List A cons : A ! List A ! List A
ℕ) ! Vec A n ! Vec A m ! Vec A (n + m) append A zero m nil ys = ys append A (suc n) m (cons x xs) ys = cons x (append A n m xs ys) dependency correctness property data Vec (A : Set) : ℕ ! Set where nil : Vec A zero cons : {n : ℕ} ! A ! Vec A n ! Vec A (suc n)
(i.e. a universe) • Traditional • Functions defined by recursion on inductive arguments of constructors (e.g. append) • Defined over an open (i.e. extendable) universe • An open universe contains a datatype defined in terms of Set • Fully • Functions defined by recursion on inductive & non-inductive arguments of constructors (e.g. marshal) • Defined over a closed (i.e. fixed) universe
: Size `Pair : (A B : Set) ! Size `List : (A : Set) ! Size ⟦_⟧ : Size ! Set ⟦ `Bool ⟧ = Bool ⟦ `Pair A B ⟧ = A × B ⟦ `List A ⟧ = List A codes meaning function collection of types … open Bool List Bool List String List ℕ Bool × Bool String × Char Char × ℕ List (List Bool) List (List String) Bool × List Bool × Bool
: Size `Pair : (A B : Set) ! Size `List : (A : Set) ! Size ⟦_⟧ : Size ! Set ⟦ `Bool ⟧ = Bool ⟦ `Pair A B ⟧ = A × B ⟦ `List A ⟧ = List A codes meaning function collection of types Bool List Bool List String List ℕ Bool × Bool String × Char Char × ℕ List (List Bool) List (List String) Bool × List Bool × Bool … open
(A B : Set) ! Size `List : (A : Set) ! Size ⟦_⟧ : Size ! Set ⟦ `Bool ⟧ = Bool ⟦ `Pair A B ⟧ = A × B ⟦ `List A ⟧ = List A size : (A : Size) ! ⟦ A ⟧ ! ℕ size `Bool b = 1 size (`Pair A B) (a , b) = 3 size (`List A) nil = 1 size (`List A) (cons x xs) = 2 + size (`List A) xs inductive argument Traditional Generic Size Function
(A B : Count) ! Count `List : (A : Count) ! Count ⟦_⟧ : Count ! Set ⟦ `Bool ⟧ = Bool ⟦ `Pair A B ⟧ = ⟦ A ⟧ × ⟦ B ⟧ ⟦ `List A ⟧ = List ⟦ A ⟧ collection of types Bool List Bool Bool × Bool List (List Bool) List (Bool × Bool) Bool × Bool × Bool List Bool × Bool × Bool List Bool × List Bool × Bool … Closed Built-In Types Universe closed codes meaning function
(A B : Count) ! Count `List : (A : Count) ! Count ⟦_⟧ : Count ! Set ⟦ `Bool ⟧ = Bool ⟦ `Pair A B ⟧ = ⟦ A ⟧ × ⟦ B ⟧ ⟦ `List A ⟧ = List ⟦ A ⟧ collection of types Bool List Bool Bool × Bool List (List Bool) List (Bool × Bool) Bool × Bool × Bool List Bool × Bool × Bool List Bool × List Bool × Bool … Closed Built-In Types Universe closed codes meaning function
(A B : Count) ! Count `List : (A : Count) ! Count ⟦_⟧ : Count ! Set ⟦ `Bool ⟧ = Bool ⟦ `Pair A B ⟧ = ⟦ A ⟧ × ⟦ B ⟧ ⟦ `List A ⟧ = List ⟦ A ⟧ count : (A : Count) ! ⟦ A ⟧ ! ℕ count `Bool b = 1 count (`Pair A B) (a , b) = 1 + count A a + count B b count (`List A) nil = 1 count (`List A) (cons x xs) = 1 + count A x + count (`List A) xs non-inductive argument Fully Generic Count Function
fixed point of a polynomial functor • Polynomial functor (F : (X : Set) → Set) • Function body has a sum-of-products format • Sum of constructor choices (nested disjoint unions) • Product of arguments per constructor (nested pairs) • Function parameter is a type (X) representing inductive constructor arguments
nil : List A cons : A ! List A ! List A ListF : Set ! (Set ! Set) ListF A X = ⊤ ⊎ A × X List : Set ! Set List A = μ (ListF A) functor level fixpoint level fixpoint μ F ≅ F (μ F)
: Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X codes meaning function Open User-Declared Types Universe ListD : Set ! Desc ListD A = κ ⊤ ⊕ (κ A ⊗ ι) ListF : Set ! (Set ! Set) ListF A X = ⟬ ListD A ⟭ X ListF : Set ! (Set ! Set) ListF A X = ⊤ ⊎ A × X
: Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X codes meaning function ListD : Set ! Desc ListD A = κ ⊤ ⊕ (κ A ⊗ ι) ListF : Set ! (Set ! Set) ListF A X = ⟬ ListD A ⟭ X Open User-Declared Types Universe ListF : Set ! (Set ! Set) ListF A X = ⊤ ⊎ A × X
: Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X data μ (D : Desc) : Set where init : ⟬ D ⟭ (μ D) ! μ D codes meaning function ListD : Set ! Desc ListD A = κ ⊤ ⊕ (κ A ⊗ ι) List : Set ! Set List A = μ (ListD A) data List (A : Set) : Set where nil : List A cons : A ! List A ! List A Open User-Declared Types Universe meaning function F (μ F) ! μ F
: Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X data μ (D : Desc) : Set where init : ⟬ D ⟭ (μ D) ! μ D codes meaning function ListD : Set ! Desc ListD A = κ ⊤ ⊕ (κ A ⊗ ι) List : Set ! Set List A = μ (ListD A) data List (A : Set) : Set where nil : List A cons : A ! List A ! List A Open User-Declared Types Universe meaning function F (μ F) ! μ F
: Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X data μ (D : Desc) : Set where init : ⟬ D ⟭ (μ D) ! μ D size : (D : Desc) ! μ D ! ℕ size D (init xs) = 1 + sizes D D xs inductive argument open Traditional Generic Size Function sizes : (D R : Desc) ! ⟬ D ⟭ (μ R) ! ℕ sizes (D ⊕ E) X (inj₁ xs) = sizes D X xs sizes (D ⊕ E) X (inj₂ ys) = sizes E X ys sizes (D ⊗ E) X (xs , ys) = sizes D X xs + sizes E X ys sizes (κ A) X a = 1 sizes ι R x = size R x constructor arguments
: Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X data μ (D : Desc) : Set where init : ⟬ D ⟭ (μ D) ! μ D size : (D : Desc) ! μ D ! ℕ size D (init xs) = 1 + sizes D D xs inductive argument open Traditional Generic Size Function sizes : (D R : Desc) ! ⟬ D ⟭ (μ R) ! ℕ sizes (D ⊕ E) X (inj₁ xs) = sizes D X xs sizes (D ⊕ E) X (inj₂ ys) = sizes E X ys sizes (D ⊗ E) X (xs , ys) = sizes D X xs + sizes E X ys sizes (κ A) X a = 1 sizes ι R x = size R x constructor arguments
_`⊗_ : (D E : `Desc) ! `Desc `κ : (A : `Set) ! `Desc `ι : `Desc ⟪_⟫ : `Desc ! Desc ⟪ D `⊕ E ⟫ = ⟪ D ⟫ ⊕ ⟪ E ⟫ ⟪ D `⊗ E ⟫ = ⟪ D ⟫ ⊗ ⟪ E ⟫ ⟪ `κ A ⟫ = κ ⟦ A ⟧ ⟪ `ι ⟫ = ι codes ₂ meaning function closed data Desc : Set₁ where _⊕_ _⊗_ : (D E : Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X data μ (D : Desc) : Set where init : ⟬ D ⟭ (μ D) ! μ D open open user-declared types from before
_`⊗_ : (D E : `Desc) ! `Desc `κ : (A : `Set) ! `Desc `ι : `Desc ⟪_⟫ : `Desc ! Desc ⟪ D `⊕ E ⟫ = ⟪ D ⟫ ⊕ ⟪ E ⟫ ⟪ D `⊗ E ⟫ = ⟪ D ⟫ ⊗ ⟪ E ⟫ ⟪ `κ A ⟫ = κ ⟦ A ⟧ ⟪ `ι ⟫ = ι codes ₂ meaning function closed data Desc : Set₁ where _⊕_ _⊗_ : (D E : Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X data μ (D : Desc) : Set where init : ⟬ D ⟭ (μ D) ! μ D open open user-declared types from before
`⊤ : `Set _`⊎_ : (A B : `Set) ! `Set `Σ `Π : (A : `Set) (B : ⟦ A ⟧ ! `Set) ! `Set `Id : (A : `Set) (x y : ⟦ A ⟧) ! `Set ⟦_⟧ : `Set ! Set ⟦ `⊥ ⟧ = ⊥ ⟦ `⊤ ⟧ = ⊤ ⟦ A `⊎ B ⟧ = ⟦ A ⟧ ⊎ ⟦ B ⟧ ⟦ `Σ A B ⟧ = Σ ⟦ A ⟧ (λ a ! ⟦ B a ⟧) ⟦ `Π A B ⟧ = (a : ⟦ A ⟧) ! ⟦ B a ⟧ ⟦ `Id A x y ⟧ = Id ⟦ A ⟧ x y data `Desc : Set where _`⊕_ _`⊗_ : (D E : `Desc) ! `Desc `κ : (A : `Set) ! `Desc `ι : `Desc ⟪_⟫ : `Desc ! Desc ⟪ D `⊕ E ⟫ = ⟪ D ⟫ ⊕ ⟪ E ⟫ ⟪ D `⊗ E ⟫ = ⟪ D ⟫ ⊗ ⟪ E ⟫ ⟪ `κ A ⟫ = κ ⟦ A ⟧ ⟪ `ι ⟫ = ι codes ₁ closed codes ₂ meaning function meaning function closed closed closed `μ : (D : `Desc) ! `Set ⟦ `μ D ⟧ = μ ⟪ D ⟫
`⊤ : `Set _`⊎_ : (A B : `Set) ! `Set `Σ `Π : (A : `Set) (B : ⟦ A ⟧ ! `Set) ! `Set `Id : (A : `Set) (x y : ⟦ A ⟧) ! `Set ⟦_⟧ : `Set ! Set ⟦ `⊥ ⟧ = ⊥ ⟦ `⊤ ⟧ = ⊤ ⟦ A `⊎ B ⟧ = ⟦ A ⟧ ⊎ ⟦ B ⟧ ⟦ `Σ A B ⟧ = Σ ⟦ A ⟧ (λ a ! ⟦ B a ⟧) ⟦ `Π A B ⟧ = (a : ⟦ A ⟧) ! ⟦ B a ⟧ ⟦ `Id A x y ⟧ = Id ⟦ A ⟧ x y data `Desc : Set where _`⊕_ _`⊗_ : (D E : `Desc) ! `Desc `κ : (A : `Set) ! `Desc `ι : `Desc ⟪_⟫ : `Desc ! Desc ⟪ D `⊕ E ⟫ = ⟪ D ⟫ ⊕ ⟪ E ⟫ ⟪ D `⊗ E ⟫ = ⟪ D ⟫ ⊗ ⟪ E ⟫ ⟪ `κ A ⟫ = κ ⟦ A ⟧ ⟪ `ι ⟫ = ι codes ₁ closed codes ₂ meaning function meaning function closed closed `μ : (D : `Desc) ! `Set ⟦ `μ D ⟧ = μ ⟪ D ⟫ Closed Fixpoints as a Built-In Type closed
`⊤ : `Set _`⊎_ : (A B : `Set) ! `Set `Σ `Π : (A : `Set) (B : ⟦ A ⟧ ! `Set) ! `Set `Id : (A : `Set) (x y : ⟦ A ⟧) ! `Set ⟦_⟧ : `Set ! Set ⟦ `⊥ ⟧ = ⊥ ⟦ `⊤ ⟧ = ⊤ ⟦ A `⊎ B ⟧ = ⟦ A ⟧ ⊎ ⟦ B ⟧ ⟦ `Σ A B ⟧ = Σ ⟦ A ⟧ (λ a ! ⟦ B a ⟧) ⟦ `Π A B ⟧ = (a : ⟦ A ⟧) ! ⟦ B a ⟧ ⟦ `Id A x y ⟧ = Id ⟦ A ⟧ x y data `Desc : Set where _`⊕_ _`⊗_ : (D E : `Desc) ! `Desc `κ : (A : `Set) ! `Desc `ι : `Desc ⟪_⟫ : `Desc ! Desc ⟪ D `⊕ E ⟫ = ⟪ D ⟫ ⊕ ⟪ E ⟫ ⟪ D `⊗ E ⟫ = ⟪ D ⟫ ⊗ ⟪ E ⟫ ⟪ `κ A ⟫ = κ ⟦ A ⟧ ⟪ `ι ⟫ = ι codes ₁ closed codes ₂ meaning function meaning function closed 2 4 + = 3 closed `μ : (D : `Desc) ! `Set ⟦ `μ D ⟧ = μ ⟪ D ⟫ closed
_`⊕_ _`⊗_ : (D E : `Desc) ! `Desc `κ : (A : `Set) ! `Desc `ι : `Desc ⟪_⟫ : `Desc ! Desc ⟪ D `⊕ E ⟫ = ⟪ D ⟫ ⊕ ⟪ E ⟫ ⟪ D `⊗ E ⟫ = ⟪ D ⟫ ⊗ ⟪ E ⟫ ⟪ `κ A ⟫ = κ ⟦ A ⟧ ⟪ `ι ⟫ = ι codes ₂ meaning function closed data Desc : Set₁ where _⊕_ _⊗_ : (D E : Desc) ! Desc κ : (A : Set) ! Desc ι : Desc ⟬_⟭ : Desc ! (Set ! Set) ⟬ D ⊕ E ⟭ X = ⟬ D ⟭ X ⊎ ⟬ E ⟭ X ⟬ D ⊗ E ⟭ X = ⟬ D ⟭ X × ⟬ E ⟭ X ⟬ κ A ⟭ X = A ⟬ ι ⟭ X = X data μ (D : Desc) : Set where init : ⟬ D ⟭ (μ D) ! μ D open codes meaning function
`⊕ (`κ A `⊗ `ι) `List : `Set ! `Set `List A = `μ (`ListD A) ListD : Set ! Desc ListD A = κ ⊤ ⊕ (κ A ⊗ ι) List : Set ! Set List A = μ (ListD A) closed open 3 4
ℕ count (A `⊎ B) (inj₁ a) = 1 + count A a count (A `⊎ B) (inj₂ b) = 1 + count B b count (`Σ A B) (a , b) = 1 + count A a + count (B a) b count (`μ D) (init xs) = 1 + counts D (`μ D) xs count A a = 1 counts : (D : `Desc) (X : `Set) ! ⟬ ⟪ D ⟫ ⟭ ⟦ X ⟧ ! ℕ counts (D `⊕ E) X (inj₁ xs) = counts D X xs counts (D `⊕ E) X (inj₂ ys) = counts E X ys counts (D `⊗ E) X (xs , ys) = counts D X xs + counts E X ys counts (`κ A) X a = count A a counts `ι X x = count X x Fully Generic Count Function non-inductive argument 2
ℕ count (A `⊎ B) (inj₁ a) = 1 + count A a count (A `⊎ B) (inj₂ b) = 1 + count B b count (`Σ A B) (a , b) = 1 + count A a + count (B a) b count (`μ D) (init xs) = 1 + counts D (`μ D) xs count A a = 1 counts : (D : `Desc) (X : `Set) ! ⟬ ⟪ D ⟫ ⟭ ⟦ X ⟧ ! ℕ counts (D `⊕ E) X (inj₁ xs) = counts D X xs counts (D `⊕ E) X (inj₂ ys) = counts E X ys counts (D `⊗ E) X (xs , ys) = counts D X xs + counts E X ys counts (`κ A) X a = count A a counts `ι X x = count X x Fully Generic Count Function constructor arguments 3
ℕ count (A `⊎ B) (inj₁ a) = 1 + count A a count (A `⊎ B) (inj₂ b) = 1 + count B b count (`Σ A B) (a , b) = 1 + count A a + count (B a) b count (`μ D) (init xs) = 1 + counts D (`μ D) xs count A a = 1 counts : (D : `Desc) (X : `Set) ! ⟬ ⟪ D ⟫ ⟭ ⟦ X ⟧ ! ℕ counts (D `⊕ E) X (inj₁ xs) = counts D X xs counts (D `⊕ E) X (inj₂ ys) = counts E X ys counts (D `⊗ E) X (xs , ys) = counts D X xs + counts E X ys counts (`κ A) X a = count A a counts `ι X x = count X x inductive argument Fully Generic Count Function 3
ℕ count (A `⊎ B) (inj₁ a) = 1 + count A a count (A `⊎ B) (inj₂ b) = 1 + count B b count (`Σ A B) (a , b) = 1 + count A a + count (B a) b count (`μ D) (init xs) = 1 + counts D (`μ D) xs count A a = 1 counts : (D : `Desc) (X : `Set) ! ⟬ ⟪ D ⟫ ⟭ ⟦ X ⟧ ! ℕ counts (D `⊕ E) X (inj₁ xs) = counts D X xs counts (D `⊕ E) X (inj₂ ys) = counts E X ys counts (D `⊗ E) X (xs , ys) = counts D X xs + counts E X ys counts (`κ A) X a = count A a counts `ι X x = count X x non-inductive argument Fully Generic Count Function 4
in dependently typed programming • Despite proliferation of dependent types • Generic functions work over all types defined now and all types defined in the future • Generic functions do not need to be edited when a new type is declared • Dependent typing ensures generic functions are well-typed! • By being defined over a closed universe of user-declared types • The universe models a closed dependently typed programming language 4
• extended to dependent, infinitary, and inductive-recursive polynomial functors • Examples of fully generic programming using the model • i.e. count, lookup, ast • Special attention payed to role of types versus role of kinds • Procedure to close any universe of types • Generalization of model of types to kinds, superkinds, etc. • Modeling a closed hierarchy of user-declared types • Modeling a language that internalizes polymorphism, hence internalizes fully generic programming
= ⊤ ⊎ A × X List : Set ! Set List A = μ (ListF A) nil : {A : Set} ! List A nil = init (inj₁ tt) cons : {A : Set} ! A ! List A ! List A cons x xs = init (inj₂ (x , xs))