0

Based on this suggestion I am trying to use order-preserving embeddings to represent renamings in a project where I am going to need two levels of contexts (types live in a kinding context of type variable kinds, and terms live in a typing context of term variable types). In my full code, I have substitution for types fully implemented; but a single hole remains in the function that does type-renaming of terms (so this is for renaming type variables). Below is my attempt at recreating the hole with minimal context.

It all starts with a simple List representation of contexts, with a simple strengthening operation that enables easy substitution of variables; and an implementation of OPEs based on the link above:

open import Data.List
open import Data.List.Any
open Data.List.Any.Membership-≡ hiding (Kind)
open import Data.Sum using (_⊎_; inj₁; inj₂; [_,_]′) renaming (map to mapSum)
open import Function using (id)
open import Relation.Binary.PropositionalEquality

module Con where
  Con : Set → Set
  Con = List

  Var : {A : Set} → A → Con A → Set
  Var t Γ = t ∈ Γ

  _∖_ : ∀ {A t} → (Γ : Con A) → Var t Γ → Con A
  (._ ∷ Γ) ∖ here _ = Γ
  (_ ∷ []) ∖ there ()
  (a ∷ b ∷ Γ) ∖ there x = a ∷ (b ∷ Γ) ∖ x



  ∖-there : ∀ {A a b} {Γ : Con A} (x : Var b Γ) → (a ∷ Γ) ∖ there x ≡ a ∷ (Γ ∖ x)
  ∖-there {Γ = []} ()
  ∖-there {Γ = _ ∷ Γ} _ = refl

  strengthen : ∀ {A a b} {Γ : Con A} → (x : Var a Γ) → (y : Var b Γ) → (a ≡ b) ⊎ (Var b (Γ ∖ x))
  strengthen (here refl) (here refl) = inj₁ refl
  strengthen (here _) (there y) = inj₂ y
  strengthen {Γ = _ ∷ []} (there ())
  strengthen {Γ = _ ∷ _ ∷ _} (there y) (here refl) = inj₂ (here refl)
  strengthen {Γ = _ ∷ _ ∷ _} (there x) (there y) = mapSum id (lemma x) (strengthen x y)
    where
      lemma : ∀ {A a b c} {Γ : Con A} (x : Var a Γ) (y : Var b (Γ ∖ x)) → Var b ((c ∷ Γ) ∖ there x)
      lemma {Γ = Γ} x y = subst (Var _) (sym (∖-there x)) (there y)

  substVar : ∀ {A} {_⊢_ : Con A → A → Set}
           → (var : ∀ {a} {Γ : Con A} → Var a Γ → Γ ⊢ a)
           → ∀ {Γ : Con A} {a b}
           → (x : Var a Γ)
           → (e : (Γ ∖ x) ⊢ a)
           → (y : Var b Γ)
           → (Γ ∖ x) ⊢ b
  substVar var x e y = [ (λ eq → subst _ eq e) , var ]′ (strengthen x y)

module OPE where
  open Con

  data _≼_ {A : Set} : Con A -> Con A -> Set where
    done : [] ≼ []
    keep : ∀ {Γ Δ a} -> Γ ≼ Δ -> (a ∷ Γ) ≼ (a ∷ Δ)
    skip : ∀ {Γ Δ a} -> Γ ≼ Δ -> (a ∷ Γ) ≼ Δ

  ≼-refl : ∀ {A} {Γ : Con A} → Γ ≼ Γ
  ≼-refl {Γ = []}     = done
  ≼-refl {Γ = x ∷ Γ} = keep ≼-refl

  weak : ∀ {A} {a : A} {Γ} → (a ∷ Γ) ≼ Γ
  weak = skip ≼-refl

  ren : ∀ {A Γ Γ′} {a : A} → Γ′ ≼ Γ → Var a Γ → Var a Γ′
  ren done ()
  ren (keep σ) (here refl) = here refl
  ren (keep σ) (there x) = there (ren σ x)
  ren (skip σ) x = there (ren σ x)

  ope-∖ : ∀ {A} {Γ Γ′} {t : A} → (x : Var t Γ) → (σ : Γ′ ≼ Γ) → (Γ′ ∖ ren σ x) ≼ (Γ ∖ x)
  ope-∖ (here refl) (keep σ) = σ
  ope-∖ {Γ = _ ∷ Γ} {x′ ∷ Γ′} (here refl) (skip σ) rewrite ∖-there {a = x′} (ren σ (here refl)) = skip (ope-∖ (here refl) σ)
  ope-∖ {Γ = t ∷ Γ} {.t ∷ Γ′} (there x) (keep σ) rewrite ∖-there {a = t} (ren σ x) | ∖-there {a = t} x = keep (ope-∖ x σ)
  ope-∖ {Γ = t ∷ Γ} {t′ ∷ Γ′} (there x) (skip σ) rewrite ∖-there {a = t′} (ren σ (there x)) = skip (ope-∖ (there x) σ)

I then define a type representing well-scoped, well-kinded System F types, and implement substitution of type variables:

module _ where
  open Con
  open OPE

  data Kind : Set where
    ⋆ : Kind

  data _⊢_ (Γ : Con Kind) : Kind → Set where
    tyvar : ∀ {κ} → (α : Var κ Γ) → Γ ⊢ κ
    _⟶_ : (t₁ t₂ : Γ ⊢ ⋆) → Γ ⊢ ⋆
    Pi : ∀ {κ′} → (κ : Kind) → (t : (κ ∷ Γ) ⊢ κ′) → Γ ⊢ κ′

  renType : ∀ {κ} {Γ Γ′ : Con Kind} → Γ′ ≼ Γ → Γ ⊢ κ → Γ′ ⊢ κ
  renType σ (tyvar α) = tyvar (ren σ α)
  renType σ (t₁ ⟶ t₂) = renType σ t₁ ⟶ renType σ t₂
  renType σ (Pi κ t) = Pi κ (renType (keep σ) t)

  substType :  ∀ {κ κ′} {Γ : Con Kind}
            → (β : Var κ′ Γ)
            → (t′ : (Γ ∖ β) ⊢ κ′)
            → (t : Γ ⊢ κ)
            → (Γ ∖ β) ⊢ κ
  substType β t′ (tyvar α) = substVar tyvar β t′ α
  substType β t′ (t₁ ⟶ t₂) = substType β t′ t₁ ⟶ substType β t′ t₂
  substType {Γ = []} () t′ (Pi κ t)
  substType {Γ = _ ∷ Γ} β t′ (Pi κ t) = Pi κ (substType (there β) (renType weak t′) t)

And now I finally have everything in place to formulate my question: how do I prove the following relationship between substType and ren?

  substType-ren : ∀ {κ κ′ Γ Γ′}
                → (σ : Γ′ ≼ Γ)
                → (β : Var κ′ Γ)
                → (t′ : (Γ ∖ β) ⊢ κ′)
                → (t : Γ ⊢ κ)
                → substType (ren σ β) (renType (ope-∖ β σ) t′) (renType σ t) ≡ renType (ope-∖ β σ) (substType β t′ t)
  substType-ren σ β t′ t = {!!}

Appendix

Just to show my work so far, here are the cases I was able to cover:

  strengthen-self : ∀ {A a} {Γ : Con A} (x : Var a Γ) → strengthen x x ≡ inj₁ refl
  strengthen-self (here refl) = refl
  strengthen-self {Γ = x ∷ []} (there ())
  strengthen-self {Γ = _ ∷ _ ∷ Γ} (there x) rewrite strengthen-self x = refl

  substVar-self : ∀ {A} {_⊢_ : Con A → A → Set}
                → (var : ∀ {a} {Γ : Con A} → Var a Γ → Γ ⊢ a)
                → ∀ {Γ : Con A} {a}
                → (x : Var a Γ)
                → (e : (Γ ∖ x) ⊢ a)
                → substVar var x e x ≡ e
  substVar-self var x e rewrite strengthen-self x = refl

  substType-ren : ∀ {κ κ′ Γ Γ′}
                → (σ : Γ′ ≼ Γ)
                → (β : Var κ′ Γ)
                → (t′ : (Γ ∖ β) ⊢ κ′)
                → (t : Γ ⊢ κ)
                → substType (ren σ β) (renType (ope-∖ β σ) t′) (renType σ t) ≡ renType (ope-∖ β σ) (substType β t′ t)
  substType-ren σ (here refl) t′ (tyvar (here refl))
    rewrite substVar-self tyvar (ren σ (here refl)) (renType (ope-∖ (here refl) σ) t′) = refl
  substType-ren (keep σ) (here refl) t′ (tyvar (there α)) = refl
  substType-ren (skip σ) (here refl) t′ (tyvar (there α)) = {!!}
  substType-ren σ (there β) t′ (tyvar (here refl)) = {!!}
  substType-ren σ (there β) t′ (tyvar (there α)) = {!!}
  substType-ren σ β t′ (t₁ ⟶ t₂) = cong₂ _⟶_ (substType-ren σ β t′ t₁) (substType-ren σ β t′ t₂)
  substType-ren σ β t′ (Pi κ t) = {!!}

Also, I have a ton of lemmas by now about how renType lifts equally rening OPEs into equal functions, or how renTypes compose, or that ren σ is injective; so, the usual suspects, but none has been helpful so far in proving substType-ren.

Community
  • 1
  • 1
Cactus
  • 27,075
  • 9
  • 69
  • 149
  • Is this hereditary substitutions stuff necessary? You don't need to track the states of a context at the type level, since you don't perform any non-obviously terminating actions. Try the usual substitution-via-environment approach (can't find any reference, should look something like [this](http://lpaste.net/146357)). – effectfully Dec 02 '15 at 15:44
  • Or alternatively you can use the substitution-via-function approach (basically the same dichotomy as with `Ren` vs OPE, and here I too prefer first-order things, which are environments now), described in the [Relative monads formalized](http://eprints.nottingham.ac.uk/28455/1/relmonform.pdf) paper as well. – effectfully Dec 02 '15 at 15:55
  • Maybe I am mistaken in what "environment" means here vs "context", but I would imagine an "environment" would be something that gives an interpretation/substitution for *all* (type/term) variables? How does substitution-via-environment handle partial substitutions? I am thinking of the case of term-level type application (i.e. what in GHC Core is written as `@`), which I currently do as `_&_ : ∀ {κ t₀} (e : Γ , Σ ⊢ (Pi κ t₀)) → (t : Γ ⊢ κ) → Γ , Σ ⊢ₜ substType t t₀`. – Cactus Dec 03 '15 at 01:44
  • 1
    "How does substitution-via-environment handle partial substitutions?" — map some variables to some terms, map other variables to themselves. – effectfully Dec 03 '15 at 07:23
  • 1
    [Here](http://lpaste.net/146406) I cooked up something. – effectfully Dec 03 '15 at 08:37
  • @user3237465: thanks, I'll hopefully have time to look at it over the next couple days -- I think I have to push it all the way to terms to be able to tell how well that approach works (since the OPE approach also only caused problems once I got to terms and that prompted the need for `substType-ren`) – Cactus Dec 03 '15 at 08:48
  • 1
    I wrote [an overcomplicated version](https://github.com/effectfully/random-stuff/blob/master/System-F.agda) of System F. But it should be possible to extend the encoding to the whole System Fω, with some notion of normalization at the type level (I guess, hereditary substitutions fit perfectly, altough I would try NbE first). – effectfully Dec 03 '15 at 15:24
  • But wait, this doesn't do any term substitution! I have managed to write everything up to term substitution in three different ways by now: my original ad-hoc way of using vector `insert`tion directly; using OPEs; and using substitution-via-environments as per your penultimate suggestion. In all three, I can get everything working until I get to term substitution, and then I get stuck on the case for Λ and type application, which both require weakening in the "wrong" (outer) context. – Cactus Dec 04 '15 at 01:53
  • @Cactus: could [this](https://gist.github.com/AndrasKovacs/83e7dcbb4bd0a4dc11f3#file-systemf-agda-L41) be of some help? I used two different `var`-s in types, one pointing to types in the outer context, and one pointing to bindings inside a type. I confusingly named them `free` and `bound`. My vars are just `Fin`-s though, since `*` is the only kind, and thus left implicit. – András Kovács Dec 04 '15 at 09:51
  • 1
    I've just realized I've never showed my full program, so [here it is](https://gist.github.com/gergoerdi/6733fc50beb9deaf15b2) with just two holes remaining. Unfortunately, both are about exactly the same thing: renaming in the *outer* context. – Cactus Dec 04 '15 at 14:28
  • Looking at it again, the `wkᵗₜ (e & t)` case is probably also suffers because `_&_` has [green slime](http://stackoverflow.com/a/29270415/477476) all over it... hmm I guess that will be the next thing I'll try to attack. – Cactus Dec 04 '15 at 14:34
  • 1
    I effectively [filled in](http://lpaste.net/146507) one of the two holes (I generalized wkᵗₜ to renᵗₜ then filled in the type lambda case). I have some ideas as to the remaining hole, it needs some hammering out though. – András Kovács Dec 05 '15 at 07:42
  • @András Kovács: that's very promising, because that generalization of `wk` sounds exactly what I need for the type app case, after I've changed my repr to be green slime-less. Unfortunately, I won't be able to look at this more until after next week. – Cactus Dec 05 '15 at 08:03
  • 1
    @András Kovács, I [generalized the lemma](https://github.com/effectfully/random-stuff/blob/master/System-F/Subst.agda), but haven't tried to fill the last hole (`ren-lookup-top`) yet. – effectfully Dec 05 '15 at 11:02

0 Answers0