-- Data --------- -- In the Calculus of Constructions, it is possible to encode data via -- Church-style encodings. However, it is then impossible to do -- inductive reasoning on these. This led to the addition of inductive -- constructions (CiC). Agda features inductive families as a native -- construct. -- Even though uAgda does not feature a native construction for data, -- it is possible to encode data using parametricity, erasure and a -- little bit of special sauce. The trick is that -- 1. The erasure of the induction principle for a given inductive -- family is equal to its Church representation, and -- 2. The relational interpretation of the representation yields back -- the inductive principle. -- More theoretical background can be found in Phil Wadler's "The -- Girard-Reynolds isomorphism". -- In uAgda, we proceed as follows. First define the appropriate -- induction principle and the proof that the constructors respect -- induction. (Note that these definitions are parameterised over an -- arbitrary module "q" containing an *abstract* version of the stuff -- we want to define (here with fields Nat, suc and zer). param Q = \ q -> ( Nat = \n -> (P : q#Nat -> *) -> ((n : q#Nat) -> P n -> P (q#suc n)) -> (P q#zer) -> P n, zer = \P s z -> z, suc = \m n P s z -> s m (n P s z), \ _ -> *) :: ((Nat : *1) ; (zer : Nat) ; (suc : Nat -> Nat) ; *1), -- The keyword "param" and the double colon are special syntax to -- construct a concrete representation (here "Q") that is -- computationally equal to the erasure of the above, but whose -- relational interpretation is the one given. -- (The last component of the tuple is just noise, as usual). -- From there we can do simple computations: one = Q#suc Q#zer : Q#Nat, two = Q#suc one, -- And we can also do inductive reasoning (but indexed by a less -- relevant version of the type/values): Nat-elim = \n -> n! : (n : Q#Nat) -> (P : Q<#Nat -> *) -> ((n : Q<#Nat) -> P n -> P (Q<#suc n)) -> (P Q<#zer) -> P n<, -- In particular, we can also inductive computation. In that case, -- because we work in a predicative type system, we need to apply the -- induction on a copy of the natural lifted to a higher universe. -- That's fine, because we also have an operator for that: postfix ^. lift = \n -> n^ : Q#Nat -> Q#Nat^, plus = \m n -> n^! (\_ -> Q#Nat) (\_ r -> Q#suc r) m : Q#Nat -> Q#Nat -> Q#Nat, four = plus two two, *