Parametrized Inductive Types in Agda

agda, gadt

Solution

I take the liberty to rename the data types. The first, which is indexed on `Set` will be called `ListI`, and the second `ListP`, has `Set` as a parameter:

data ListI : Set → Set₁ where
  []  : {A : Set} → ListI A
  _∷_ : {A : Set} → A → ListI A → ListI A

data ListP (A : Set) : Set where
  []  : ListP A
  _∷_ : A → ListP A → ListP A

In data types parameters go before the colon, and arguments after the colon are called indicies. The constructors can be used in the same way, you can apply the implicit set:

nilI : {A : Set} → ListI A
nilI {A} = [] {A}

nilP : {A : Set} → ListP A
nilP {A} = [] {A}

There difference comes when pattern matching. For the indexed version we have:

null : {A : Set} → ListI A → Bool
null ([]  {A})     = true
null (_∷_ {A} _ _) = false

This cannot be done for `ListP`:

-- does not work
null′ : {A : Set} → ListP A → Bool
null′ ([]  {A})     = true
null′ (_∷_ {A} _ _) = false

The error message is

The constructor [] expects 0 arguments, but has been given 1
when checking that the pattern [] {A} has type ListP A

`ListP` can also be defined with a dummy module, as `ListD`:

module Dummy (A : Set) where
  data ListD : Set where
    []  : ListD
    _∷_ : A → ListD → ListD

open Dummy public

Perhaps a bit surprising, `ListD` is equal to `ListP`. We cannot pattern match on the argument to `Dummy`:

-- does not work
null″ : {A : Set} → ListD A → Bool
null″ ([]  {A})     = true
null″ (_∷_ {A} _ _) = false

This gives the same error message as for `ListP`.

`ListP` is an example of a parameterised data type, which is simpler than `ListI`, which is an inductive family: it "depends" on the indicies, although in this example in a trivial way.

Parameterised data types are defined on the wiki, and here is a small introduction.

Inductive families are not really defined, but elaborated on in the wiki with the canonical example of something that seems to need inductive families:

data Term (Γ : Ctx) : Type → Set where
  var : Var Γ τ → Term Γ τ
  app : Term Γ (σ → τ) → Term Γ σ → Term Γ τ
  lam : Term (Γ , σ) τ → Term Γ (σ → τ)

Disregarding the Type index, a simplified version of this could not be written with in the `Dummy`-module way because of `lam` constructor.

Another good reference is Inductive Families by Peter Dybjer from 1997.

Happy Agda coding!

Problem

I'm just reading Dependent Types at Work. In the introduction to parametrised types, the author mentions that in this declaration ``` data List (A : Set) : Set where [] : List A _::_ : A → List A → List A ``` the type of `List` is `Set → Set` and that `A` becomes implicit argument to both constructors, ie. ``` [] : {A : Set} → List A _::_ : {A : Set} → A → List A → List A ``` Well, I tried to rewrite it a bit differently ``` data List : Set → Set where [] : {A : Set} → List A _::_ : {A : Set} → A → List A → List A ``` which sadly doesn't work (I'm trying to learn Agda for two days or so, but from what I gathered it's because the constructors are parametrised over `Set₀` and so `List A` must be in `Set₁`). Indeed, the following is accepted ``` data List : Set₀ → Set₁ where [] : {A : Set₀} → List A _::_ : {A : Set₀} → A → List A → List A ``` however, I'm no longer able to use `{A : Set} → ... → List (List A)` (which is perfectly understandable). So my question: What is the actual difference between `List (A : Set) : Set` and `List : Set → Set`? Thanks for your time!

Original source