{-# OPTIONS --safe --without-K #-}
open import Prelude
module Generics.Reflection.Datatype where
open import Utils.Reflection
open import Utils.Error as Err
open import Generics.Telescope
open import Generics.Description
open import Generics.Reflection.Telescope
private
variable
rb : RecB
cb : ConB
cbs : ConBs
t u : Tel ℓ
pattern `[] = con₀ (quote ConDs.[])
pattern _`∷_ x y = con₂ (quote ConDs._∷_) x y
pattern `ιʳ x = con₁ (quote RecD.ι) x
pattern `π x y = con₂ (quote RecD.π) x y
pattern `ιᶜ x = con₁ (quote ConD.ι) x
pattern `σ x y = con₂ (quote ConD.σ) x y
pattern `ρ x y = con₂ (quote ConD.ρ) x y
to`ConDs : Terms → Term
to`ConDs = foldr `[] _`∷_
module _ {T : Tel ℓ} (`A : ⟦ T ⟧ᵗ → TC Type) where
RecDToType : (R : RecD ⟦ T ⟧ᵗ rb) → TC Type
RecDToType (ι i) = `A i
RecDToType (π A D) = do
s ← getAbsNameω D
exCxtT s visible-relevant-ω A λ `A x →
vΠ[ s ∶ `A ]_ <$> RecDToType (D x)
ConDToType : (D : ConD ⟦ T ⟧ᵗ cb) → TC Type
ConDToType (ι i) = `A i
ConDToType (σ A D) = do
s ← getAbsNameω D
exCxtT s visible-relevant-ω A λ `A x →
vΠ[ s ∶ `A ]_ <$> ConDToType (D x)
ConDToType (ρ R D) = do
`R ← RecDToType R
extendContext "_" (vArg (quoteTerm ⊤)) do
vΠ[ `R ]_ <$> ConDToType D
ConDsToTypes : (Ds : ConDs ⟦ T ⟧ᵗ cbs) → TC Types
ConDsToTypes [] = return []
ConDsToTypes (D ∷ Ds) = ⦇ ConDToType D ∷ ConDsToTypes Ds ⦈
getCons : Name → (`Param : Telescope) → PDataD → TC Types
getCons d `Param Dᵖ = exCxtTel Param λ ps → ConDsToTypes (typeOfData d ps) (applyP ps)
where open PDataD Dᵖ
{-# INLINE getCons #-}
getSignature : PDataD → TC (Telescope × Type)
getSignature Dᵖ = do
`Param ← fromTel Param (constTelInfo visible)
`Param+Index ← fromTel (Param ++ Index) (constTelInfo visible)
dT ← extend*Context `Param+Index do
`Setℓ ← quoteTC! (Set dlevel)
return $ ⇑ (`Param+Index , `Setℓ) ⦂ Type
return $ `Param , dT
where open PDataD Dᵖ
defineByDataD : DataD → Name → List Name → TC _
defineByDataD dataD dataN conNs = exCxtℓs #levels λ ℓs → do
let `Levels = `Levels #levels
let Dᵖ = applyL ℓs
`Param , dT ← withNormalisation true $ getSignature Dᵖ
declareData dataN (#levels + length `Param) (prependToType `Levels dT)
conTs ← withNormalisation true $ getCons dataN `Param Dᵖ
let |conTs| = length conTs ; |conNs| = length conNs
when (|conTs| /= |conNs|) $ typeError {A = ⊤}
(strErr ("The number of required constructor names: " <> show |conTs|) ∷
strErr ("\n ≠ \nthe number of given names: " <> show |conNs|) ∷ [])
defineData dataN (zip conNs conTs)
printData dataN
where open DataD dataD
private
pattern `DataD = def₀ (quote DataD)
pattern `datad x y = con₂ (quote datad) x y
pattern `pdatad x z u v = con₄ (quote pdatad) x z u v
module _ (dataName : Name) (pars : ℕ) where
idxArgs = argsToIdx ∘ drop pars
telescopeToRecD : Telescope → Type → TC Term
telescopeToRecD ((s , arg _ `x) ∷ `tel) end = do
rec ← telescopeToRecD `tel end
return $ `π `x (`vλ s `→ rec)
telescopeToRecD [] (def f args) = if f == dataName
then return $ `ιʳ (idxArgs args)
else Err.notEndIn (strErr "telescope") (nameErr dataName)
telescopeToRecD [] _ = Err.notEndIn (strErr "telescope") $ nameErr dataName
telescopeToConD : Telescope → Type → TC Term
telescopeToConD ((s , arg _ `x) ∷ `tel) end = if endsIn `x dataName
then (do
recd ← uncurry telescopeToRecD (⇑ `x)
cond ← telescopeToConD `tel end
return $ `ρ recd (strengthen 0 1 cond)
) else (do
cond ← telescopeToConD `tel end
return $ `σ `x (vLam (abs s cond))
)
telescopeToConD [] (def f args) = if f == dataName
then (return $ `ιᶜ (idxArgs args))
else (Err.notEndIn (strErr "telescope") (nameErr dataName))
telescopeToConD [] _ = Err.notEndIn (strErr "telescope") (nameErr dataName)
reifyConstructor : Name → TC Term
reifyConstructor conName = do
conType ← getType conName
let (tel , end) = (⇑ conType) ⦂ Telescope × Type
telescopeToConD (drop pars tel) end
reifyData : Name → TC Term
reifyData d = do
(ℓsΓΔ , end) ← coerce'_to (Telescope × Type) <$> getType d
pars , cs ← getDataDefinition d
let (ℓsΓ , Δ) = splitAt pars ℓsΓΔ
(ℓtel , Γ) = span (λ (_ , `A) → unArg `A == `Level) ℓsΓ
`#levels = lit (nat (length ℓtel))
`ℓ ← getSetLevel end
conDs ← to`ConDs <$> mapM (reifyConstructor d pars) cs
return $ `datad `#levels
(patLam ℓtel
(`pdatad
(strengthen 0 (length Γ + length Δ) `ℓ)
(to`Tel Γ)
(patLam Γ $ to`Tel Δ)
(patLam Γ conDs)))
where
patLam : Telescope → Term → Term
patLam Γ body = let (_ , p) , _ = cxtToVars 0 (`tt , `tt) Γ in
pat-lam₀ [ Γ ⊢ [ vArg p ] `= body ]
genDataDT : Name → Term → TC Name
genDataDT d hole = do
t ← reifyData d
defineUnify (vArg "_") `DataD t hole
macro
genDataD : Name → Tactic
genDataD d hole = genDataDT d hole >> return tt
macro
defineAndPrintData : DataD → String → List String → Tactic
defineAndPrintData D s cs hole = do
dName ← freshName s
len ← exCxtℓs #levels λ ℓs → do
return $ length $ PDataD.struct (applyL ℓs)
conNames ← align len cs
defineByDataD D dName conNames
printData dName
where
open DataD D
align : ℕ → List String → TC (List Name)
align zero cs = return []
align (suc n) [] = do c ← freshName "con"
ns ← align n []
return $ c ∷ ns
align (suc n) (x ∷ cs) = ⦇ freshName x ∷ align n cs ⦈