[Agda] Records and irrelevant fields

Dan Doel dan.doel at gmail.com
Fri Sep 17 12:16:21 CEST 2010


On Friday 17 September 2010 4:52:54 am Andreas Abel wrote:
> It seems that we cannot have records with irrelevant fields, like e.g.
> 
> postulate NonNeg : Nat -> Set
> 
> record Pos : Set where
>    constructor mkPos
>    field
>      theNum : Nat
>      .theProof : NonNeg theNum
> 
> because the second projection is not definable
> 
> Pos.theProof : (r : Pos) -> NonNeg (Pos.theNum r)
> Pos.theProof (mkPos n p) = p
> 
> Since p is irrelevant, it cannot be returned.
> 
> Consequently, eta-expansion for Pos does not work either, nor
> replacing the match against mkPos by projections (new feature of 2.2.8).
> 
> The theory of irrelevance (Barras/Bernardo, Sheard/Mishra-Linger) does
> not account for definitions which can only be used in irrelevant
> context, such as Pos.theProof.

There may be partial solutions to this. One important irrelevant inductive 
type is:

  data Squash (A : Set) : Set where
    squash : .A -> Squash A

which throws away all information about what element of A you have. You can 
project out irrelevant fields using this type:

> For now, we have to use data instead.
>
> data Pos : Set where
>    mkPos : (n : Nat) -> .(NonNeg n) -> Pos

  elim : {P : Pos -> Set} -> ((n : Nat) -> .(p : NonNeg n) -> P (mkpos n p))
       -> (p : Pos) -> P p
  elim f (mkPos n p) = f n p

  theNum : Pos -> Nat
  theNum = elim (\n -> /\_ -> n)

  theProof : (p : Pos) -> Squash (NonNeg (theNum p))
  theProof = elim (\n -> /\p -> squash at p)

I don't know how feasible it would be, but it's conceivable that record 
projections could automatically project to a squashed type, possibly declared 
with a BUILTIN pragma.

In this case, you should also be able to go back:

  construct : (n : Nat) -> Squash (NonNeg n) -> Pos
  construct n sp = elimSquash (mkPos n) sp

Although in general, I don't think you can. For instance:

  data ∃ (A : Set) (T : A → Set) : Set where
    _,_ : .(x : A) → (w : T x) → ∃ A T

  fst : ∀{A T} → ∃ A T → Squash A
  fst (x , _) = squash x

  snd : ∀{A T} → (p : ∃ A T) → T ?

I'm not sure there's anything to fill in for the hole there. T doesn't take a 
Squash A, and we can't eliminate the squash in the type correctly. This is 
actually probably a good thing, though, as it ensures that ∃ is a weak sum, 
and enforces the abstraction guarantees we want. I suppose this example is 
another nail in the coffin, though, as even though we can project out the 
irrelevant field using squash, we cannot project out the relevant field, 
because its type depends on the irrelevant field, which we can't access 
normally.

I thought about this a fair amount a while back, considering just things like 
∃ above, with elimination by projections. I had been thinking something like:

  p :r ∃ A P
  fst p :c A
  snd p :r P (fst p)

That doesn't work, but it will if you change context reset to be:

  reset (G , p :? ∃ A P) = reset G , p :r Σ A P

which isn't totally crazy, since those contexts are essentially:

  reset (G , fst p :c A , snd p :r P (fst p)) = reset g , fst p :r A , ...

But if we do that, what about higher-order encodings of those? Do we reset

  G , f : (R : Set) -> (.(x : A) -> P x -> R) -> R

to

  G , f : (R : Set) -> ((x : A) -> P x -> R) -> R

Sheard/Mishra-Linger say no. If we do stuff like this, it also means that ∃ is 
again a strong sum, I believe, and having weak sums is (if you ask me) part of 
the interest of this stuff.

I don't have any firm answers on the subject.

-- Dan


More information about the Agda mailing list