0

Suppose we have the following code:

open import Data.Fin
open import Data.Nat

data SType : ℕ → Set where

variable
  ℓ : ℕ
  ι : Fin ℓ
  τ τ' : SType ℓ

infixl 5 _,_
data Ctx : ℕ → Set where
  ⊘   : Ctx zero
  _,_ : Ctx ℓ → SType ℓ → Ctx (suc ℓ)

variable Γ : Ctx ℓ

postulate weaken : SType ℓ → SType (suc ℓ)

infix 4 _∈_at_
data _∈_at_ : SType ℓ → Ctx ℓ → Fin ℓ → Set where
  ∈-zero : weaken τ ∈ Γ , τ at zero
  ∈-suc  : τ ∈ Γ at ι
         → weaken τ ∈ Γ , τ' at suc ι

which models a tiny part of a well-scoped representation of a type system (and I'm keeping weaken postulated and SType not having any constructors for the sake of brevity).

Now suppose we want to write a function that's basically an "inverse" of the ∈-suc constructor:

∈-chop : weaken τ ∈ Γ , τ' at suc ι
       → τ ∈ Γ at ι
∈-chop ∈ = {! !}

Now, if we try to split on , Agda will get all doubting and hesitant:

I'm not sure if there should be a case for the constructor ∈-suc,
because I get stuck when trying to solve the following unification
problems (inferred index ≟ expected index):
  {suc τ.ℓ₁} ≟ {suc τ.ℓ₂}
  weaken τ₁ ≟ weaken τ₂
  Γ₁ , τ'' ≟ Γ₂ , τ'''
  suc ι₁ ≟ suc ι₂
when checking that the expression ? has type τ ∈ Γ at ι

Why is it not sure, and what's the best way to fix this?

0xd34df00d
  • 1,496
  • 1
  • 8
  • 17

2 Answers2

4

Your problem is the Green Slime.

Quoting Jesper Cockx:

The error message "cannot generalize over the indices" is thrown by Agda when it encounters a unification problem of the form c us =?= c vs where c is a constructor of an indexed datatype, but the indices in the type of this equation are something other than distinct variables (i.e. they should be fully general). If they are not, Agda tries to apply a technique called higher-dimensional unification (see our CPP 2017 paper) to bring them in a fully general form. However, this unfortunately doesn't always succeed, for example in your code it gets stuck on the + function in the index of con.

One way to fix your problem would be to get rid of the 'green slime' in the type of con: it's better to use only variables and constructors in the indices of your datatypes, and use explicit proofs of equality for the heavier work.

You can check that this is indeed the case by making weaken a constructor of SType, which then allows you to define ∈-chop by pattern matching like you want.

Matching on ∈-suc amounts to solving

weaken τ ∈ Γ , τ' at suc ι =?= weaken _τ ∈ _Γ , _τ' at suc _ι

where the LHS is the type that you provided in the type signature and the RHS is the inferred type of ∈-suc where each implicit variable got turned into a meta. Now unifying, say, suc ι and suc _ι is no problem, since constructors are injective, but functions are generally not (see the first part of this answer) and so when weaken is a function you can't unify weaken τ with weaken _τ.

You can use explicit equality to get around the issue:

open import Relation.Binary.PropositionalEquality
 
infix 4 _∈_at_
data _∈_at_ : SType ℓ → Ctx ℓ → Fin ℓ → Set where
  ∈-zero : τ' ≡ weaken τ → τ' ∈ Γ , τ at zero
  ∈-suc  : τ' ≡ weaken τ
         → τ ∈ Γ at ι
         → τ' ∈ Γ , τ at suc ι

That allows you to pattern match in ∈-chop even when weaken is a function.

effectfully
  • 12,325
  • 2
  • 17
  • 40
2

Your definitions seem to imply that, in ∈-chop there are no possible value for τ which can be seen as follows:

∈-chop : ∀ {Γ τ ι} → weaken τ ∈ Γ , τ' at suc ι → τ ∈ Γ at ι
∈-chop {τ = ()}

This does not directly answer your question but it's probably not the indented behavior which could ultimately solve your problem.

MrO
  • 1,291
  • 7
  • 14
  • 1
    That's because `SType` is empty. In the real code it probably has a bunch of constructors, so this is unrelated. – effectfully Dec 07 '20 at 13:02
  • 1
    it might not be completely unrelated because it's often by pattern matching on other arguments that problems of kind "I'm not sure if there should be a case ..." are solved, here we cannot because of the empty type. – MrO Dec 07 '20 at 13:15
  • Thank you for your comment, I've updated my question to note that `SType` indeed has a bunch of constructors. – 0xd34df00d Dec 07 '20 at 16:57