2

I have a definition with the following type:

insert : ∀ {n} → (i : Fin (suc n)) → ∀ t → Env n → Env (suc n)
weaken : ∀ {t t₀ n} {Γ : Env n} → (i : Fin (suc n)) → (e : Γ ⊢ t₀) → (insert i t Γ) ⊢ t₀

Given two environments Γ : Env n and Γ′ : Env n′, and a pointer to a position in the second one, i : Fin (suc n), I would like to weaken an e : (Γ′ ++ Γ) ⊢ t₀.

In theory, this should be easy by using something like

let i′ = raise n′ i
weaken {t} i′ e : insert i′ t (Γ′ ++ Γ) ⊢ t₀

However, in practice it doesn't work out so nicely, because the typechecker is not convinced that raise n′ i has type Fin (suc _) (required by weaken):

(n′ + suc n) != (suc (_n_550 i e)) of type when checking that the expression i′ has type Fin (suc (_n_550 i e))

My problem is, I could use something like +-suc : ∀ n′ n → n′ + suc n ≡ suc (n′ + n) to substitute the type of i′, but then the resulting type from weaken i′ e will not have the form insert i′ t (Γ′ ++ Γ) ⊢ t₀.

Cactus
  • 27,075
  • 9
  • 69
  • 149

1 Answers1

2

Given two environments Γ : Env n and Γ′ : Env n′

Those are contexts.

It should be possible to change the type of insert to

data Bound : ℕ -> Set where
  zero : ∀ {n} -> Bound n
  suc  : ∀ {n} -> Bound n -> Bound (suc n)

insert : ∀ {n} → (i : Bound n) → ∀ t → Env n → Env (suc n)

without changing the body of the function.

You can write a version of raise that raises under suc:

raise′ : ∀ {m} n → Fin (suc m) → Fin (suc (n + m))
raise′ zero    i = i
raise′ (suc n) i = suc (raise′ n i)

But the actual solution is to rename terms using either functions:

Ren : Con -> Con -> Set
Ren Γ Δ = ∀ {σ} -> σ ∈ Γ -> σ ∈ Δ

keepʳ : ∀ {Γ Δ σ} -> Ren Γ Δ -> Ren (Γ ▻ σ) (Δ ▻ σ)
keepʳ r  vz    = vz
keepʳ r (vs v) = vs (r v)

ren : ∀ {Γ Δ σ} -> Ren Γ Δ -> Γ ⊢ σ -> Δ ⊢ σ
ren r (var v) = var (r v)
ren r (ƛ b  ) = ƛ (ren (keepʳ r) b)
ren r (f · x) = ren r f · ren r x

or order preserving embeddings.

effectfully
  • 12,325
  • 2
  • 17
  • 40
  • But there are `suc n` places to insert a new item into an `Env n`. In particular, with your version of `insert`, there's no way to start from an empty `Env` and turn it into a singleton one, since that would require `i : Fin zero`. What am I missing? – Cactus Dec 01 '15 at 06:38
  • In fact, most of my code currently is written by having things which can do weakening at any `i`ndex (so that they can go under binders by shifting variables by one), and then externally are only used by setting `i` to `zero`. But none of that will work if `i : Fin n`. – Cactus Dec 01 '15 at 06:41
  • @Cactus, ah, sorry, I used `insert` [here](https://github.com/effectfully/Ouroboros/blob/master/Weakening/Main.agda), but I forgot that my `Fin`s encode `_≤_` rather than `_<_`. I'll fix the answer. – effectfully Dec 01 '15 at 06:54
  • I started rewriting my code to use this kind of `Ren`aming functions as weakening witnesses, but now I have so many followup questions... – Cactus Dec 01 '15 at 11:45
  • 1
    @Cactus, I see this `Ren` pretty often, but I prefer OPEs — they are really very nice and I use them all the time. You can write me at effectfully@gmail.com, I'll try to answer your questions. For better understanding of the `Ren` thing I recommend to read [Conor McBride's lecture notes](https://github.com/pigworker/SSGEP-DataData) (the second chapter IIRC) and the [Relative monads formalized](http://eprints.nottingham.ac.uk/28455/1/relmonform.pdf) paper. – effectfully Dec 01 '15 at 12:37
  • OK I'm looking into OPEs now. I have this feeling that any of these, even including my original implementation, would work just fine for the basic case; and I always start getting into trouble when I start needing two, nested contexts (i.e. I need to be able to weaken both by the inner, and the outer context, where the inner context's elements are typed by the outer one). – Cactus Dec 01 '15 at 13:17
  • Thanks for the offer to directly answer my questions, but this OPE avenue now looks promising enough that I'd rather spend a bit more time playing around with it, before deciding again to just try & get some help :) – Cactus Dec 01 '15 at 13:28
  • @Cactus, if you can always distinguish the outer and the inner contexts, maybe it is possible to represent them differently? Like inner contexts are indexed by outers. Then you'll probably need "outer" and "inner" OPEs. – effectfully Dec 01 '15 at 13:37
  • 1
    Most of the time I would avoid using _++_ in contexts, and rather have two contexts and require a proof that one is some extension of the other. – Saizan Dec 02 '15 at 09:40
  • @user3237465 I've posted an unfortunately too "gimme the codez"-y followup question to http://stackoverflow.com/q/34045074/477476 in case you're still interested. – Cactus Dec 02 '15 at 14:34
  • @Cactus, I'm too tired today, I'll try to dive deeper tomorrow, if the suggestions that I've just posted there are inappropriate or insufficient. – effectfully Dec 02 '15 at 15:58