open import 1Lab.Reflection.Signature
open import 1Lab.Reflection.Subst
open import 1Lab.Reflection
open import 1Lab.Type.Sigma
open import 1Lab.Type.Pi
open import 1Lab.HLevel
open import 1Lab.Path
open import 1Lab.Type
open import Data.Nat.Base
open import Meta.Append
module 1Lab.Reflection.Induction where
open import 1Lab.HLevel.Closure public
open import Data.Maybe.Base using (nothing; just) public
pi-view-path : Term → Telescope
pi-view-path (pi x (abs n y)) = (n , x) ∷ pi-view-path y
pi-view-path (def (quote PathP) (_ h∷ lam _ (abs n y) v∷ _ v∷ _ v∷ [])) =
(n , argN (quoteTerm I)) ∷ pi-view-path y
pi-view-path _ = []
Replacements = List (Term × Term)
subst-replacements : Subst → Replacements → Replacements
subst-replacements s = map (×-map (applyS s) (applyS s))
instance
Has-subst-Replacements : Has-subst Replacements
Has-subst-Replacements = record { applyS = subst-replacements }
record Elim-options : Type where
field
induction : Bool
into-hlevel : Maybe Nat
hide-motive : Bool
hide-indices : Bool
hide-cons-args : Bool
private
module Induction
(opts : Elim-options)
(D : Name) (pars : Nat) (ixTel : Telescope) (cs : List Name)
where
open Elim-options opts
{-# TERMINATING #-}
replace : Replacements → Term → Maybe Term
replace* : Replacements → Args → Args
lookupR : Term → Replacements → Maybe Term
lookupR t [] = nothing
lookupR t@(con c _) ((con c' _ , r) ∷ rs) with c ≡? c'
... | yes _ = just r
... | no _ = lookupR t rs
lookupR t@(var i _) ((var i' _ , r) ∷ rs) with i ≡? i'
... | yes _ = just r
... | no _ = lookupR t rs
lookupR t (_ ∷ rs) = lookupR t rs
replace rs (lam v (abs n t)) = lam v ∘ abs n <$> replace (raise 1 rs) t
replace rs t@(con c args) = lookupR t rs <&> λ r →
apply-tm* r (replace* rs (drop pars args))
replace rs t@(var i args) = lookupR t rs <&> λ r →
apply-tm* r (replace* rs args)
replace rs _ = nothing
replace* rs [] = []
replace* rs (arg ai t ∷ as) with replace rs t
... | just t' = hide-if hide-cons-args (arg ai t) ∷ arg ai t' ∷ replace* rs as
... | nothing = arg ai t ∷ replace* rs as
{-# TERMINATING #-}
display
: (depth : Nat)
→ (ps : Args)
→ (P : Term)
→ (rs : Replacements)
→ (rec : Term)
→ (α : Args)
→ (c : Term) (T : Term)
→ Maybe (Term × Args)
display depth ps P rs rec α c (pi (arg ai x) (abs n y)) = do
let
ps = raise 1 ps
P = raise 1 P
rs = raise 1 rs
rec = raise 1 rec
α = raise 1 α
c = raise 1 c
base =
let
c = c <#> arg ai (var 0 [])
α = α ∷r hide-if hide-cons-args (arg ai (var 0 []))
in display depth ps P rs rec α c y <&> ×-map₁ λ y →
pi (hide-if hide-cons-args (arg ai x)) (abs n y)
suc depth-1 ← pure depth
where _ → base
just (h , α') ← pure (display depth-1 ps P rs unknown [] (var 0 []) (raise 1 x))
where _ → base
let
ps = raise 1 ps
P = raise 1 P
rs = (var 1 [] , var 0 []) ∷ raise 1 rs
c = raise 1 c <#> arg ai (var 1 [])
hTel = pi-view-path h
l = tel→lam hTel (apply-tm* (raise (length hTel) rec)
(infer-tel ixTel ∷r argN (var (length hTel) α')))
α = α ++ [ hide-if hide-cons-args (arg ai (var 0 [])) , argN l ]
y = raise 1 y
display depth ps P rs rec α c y <&> ×-map₁ λ y →
pi (hide-if hide-cons-args (arg ai x)) (abs n (pi (argN h) (abs ("P" <> n) y)))
display depth ps P rs rec α c (def (quote PathP) (_ h∷ lam v (abs n y) v∷ l v∷ r v∷ [])) = do
l ← replace rs l
r ← replace rs r
let
ps = raise 1 ps
P = raise 1 P
rs = raise 1 rs
rec = raise 1 rec
α = raise 1 α ∷r argN (var 0 [])
c = raise 1 c <#> argN (var 0 [])
display depth ps P rs rec α c y <&> ×-map₁ λ y →
def (quote PathP) (unknown h∷ lam v (abs n y) v∷ l v∷ r v∷ [])
display depth ps P rs rec α c (def D' args) = do
yes _ ← pure (D ≡? D')
where _ → nothing
let ps' , is = split-at pars args
yes _ ← pure (ps ≡? ps')
where _ → nothing
let Pc = apply-tm* P (if induction then hide-if hide-indices is ++ c v∷ [] else [])
pure (Pc , α)
display depth ps P rs rec α c _ = nothing
try-hlevel : Term → TC (Maybe Term)
try-hlevel T =
(do
maybe→alt into-hlevel
m ← new-meta T
unify m $ def (quote centre) $
def (quote hlevel) (unknown h∷ T h∷ lit (nat 0) v∷ []) v∷ []
pure (just m))
<|> pure nothing
×-map₁₂ : ∀ {A B C : Type} → (A → A) → (B → B) → A × B × C → A × B × C
×-map₁₂ f g (a , b , c) = (f a , g b , c)
methods : Args → Term → TC (Telescope × List Args × Replacements)
methods ps P = go ps P [] cs where
go : Args → Term → Replacements → List Name → TC _
go ps P rs [] = pure ([] , [] , rs)
go ps P rs (c ∷ cs) = do
let c' = con c (hide ps)
cT ← flip pi-applyTC ps =<< normalise =<< get-type c
just (methodT , α) ← pure (display 1 ps P rs (var 0 []) [] c' cT)
where _ → typeError [ "The type of constructor " , nameErr c , " is not supported" ]
try-hlevel methodT >>= λ where
(just m) → do
let rs = (c' , m) ∷ rs
go ps P rs cs <&> ×-map₁₂ id (α ∷_)
nothing → do
method ← ("P" <>_) <$> render-name c
let
ps = raise 1 ps
P = raise 1 P
rs = (c' , var 0 []) ∷ raise 1 rs
extend-context method (argN methodT) (go ps P rs cs) <&>
×-map₁₂ ((method , argN methodT) ∷_) (α ∷_)
make-elim-with : Elim-options → Name → Name → TC ⊤
make-elim-with opts elim D = withNormalisation true do
DT ← get-type D >>= normalise
data-type pars cs ← get-definition D
where _ → typeError [ "not a data type: " , nameErr D ]
let
open Elim-options opts
DTTel , _ = pi-view DT
parTel , ixTel = split-at pars DTTel
parTelH = hide parTel
ixTel = hide-if hide-indices ixTel
DTel = ixTel ∷r ("" , argN (def D (tel→args 0 DTTel)))
DTel = raise 1 DTel
PTel = if induction then id else λ _ → []
argP = if hide-motive then argH else argN
motiveTel = ("ℓ" , argH (quoteTerm Level))
∷ ("P" , argP (unpi-view (PTel DTel) (agda-sort (set (var (length (PTel DTel)) [])))))
∷ []
DTel = raise 1 DTel
hlevelTel = maybe→alt into-hlevel <&> λ n → "h" , argN
(unpi-view (PTel DTel)
(def (quote is-hlevel) (var (length (PTel DTel)) (tel→args 0 (PTel DTel))
v∷ lit (nat n) v∷ [])))
H-LevelTel = maybe→alt into-hlevel <&> λ n → "h" , argI
(unpi-view (hide (PTel DTel)) (pi (argH (quoteTerm Nat)) (abs "k"
(def (quote H-Level) (var (length (PTel DTel) + 1) (tel→args 1 (PTel DTel)) v∷
def (quote _+_) (lit (nat n) v∷ var 0 [] v∷ []) v∷ [])))))
ps = tel→args (length motiveTel + length hlevelTel) parTel
P = var (length hlevelTel) []
module I = Induction opts D pars ixTel cs
methodTel , αs , rs ← in-context (reverse (parTelH ++ motiveTel ++ H-LevelTel)) (I.methods ps P)
let
baseTel = parTelH ++ motiveTel ++ hlevelTel ++ methodTel
DTel = raise (length hlevelTel + length methodTel) DTel
P = raise (length methodTel + length DTel) P
Pd = apply-tm* P (tel→args 0 (PTel DTel))
elimT = unpi-view (baseTel ++ DTel) Pd
elimT' ← just <$> get-type elim <|> nothing <$ declare (argN elim) elimT
for elimT' (unify elimT)
let
ixTel = raise (length motiveTel + length hlevelTel + length methodTel) ixTel
ps = raise (length methodTel + length ixTel) ps
rs = raise (length ixTel) rs
let
h = length methodTel + length ixTel
rs = Maybe-rec (λ n → applyS (inplaceS h
(tel→lam (hide (PTel DTel))
(def (quote basic-instance) (lit (nat n) v∷
var (h + length (PTel DTel)) (tel→args 0 (PTel DTel)) v∷ [])))))
id into-hlevel rs
clauses ← in-context (reverse (baseTel ++ ixTel)) do
let getClause = λ (c , α) → do
cT ← flip pi-applyTC ps =<< normalise =<< get-type c
let
cTel = pi-view-path cT
pats = tel→pats (length cTel) (baseTel ++ ixTel) ∷r argN (con c (tel→pats 0 cTel))
rec = def elim (tel→args (length ixTel + length cTel) baseTel)
α = applyS (singletonS (length cTel) rec) α
just m ← pure (I.replace rs (con c (hide ps)))
where _ → typeError []
let m = apply-tm* (raise (length cTel) m) α
pure (clause (baseTel ++ ixTel ++ cTel) pats m)
traverse getClause (zip cs αs)
define-function elim clauses
default-elim = record
{ induction = true
; into-hlevel = nothing
; hide-motive = true
; hide-indices = true
; hide-cons-args = false
}
default-elim-visible = record
{ induction = true
; into-hlevel = nothing
; hide-motive = false
; hide-indices = false
; hide-cons-args = false
}
default-rec = record default-elim { induction = false }
default-rec-visible = record default-elim-visible { induction = false }
_into_ : Elim-options → Nat → Elim-options
opts into n = record opts { into-hlevel = just n }
make-elim make-rec : Name → Name → TC ⊤
make-elim = make-elim-with default-elim
make-rec = make-elim-with default-rec
make-elim-n make-rec-n : Nat → Name → Name → TC ⊤
make-elim-n n = make-elim-with (default-elim into n)
make-rec-n n = make-elim-with (default-rec into n)