{-# OPTIONS --no-exact-split #-}
module GpdCont.RecordEquiv where
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism hiding (iso)
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Function using (_$_)
open import Cubical.Data.Unit.Base
open import Cubical.Data.List.Base as List using (List ; _∷_ ; [])
open import Cubical.Reflection.Base
open import Cubical.Reflection.StrictEquiv public
open import Cubical.Reflection.RecordEquiv public
import Agda.Builtin.Reflection as R
open Iso
private
pattern _hω∷_ a l = harg {q = R.quantity-ω} a ∷ l
pattern iarg t = R.arg (R.arg-info R.instance′ (R.modality R.relevant R.quantity-ω)) t
_<$>_ : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → (A → B) → R.TC A → R.TC B
f <$> t = t >>= λ x → R.returnTC (f x)
hideArg : ∀ {ℓ} {A : Type ℓ} → R.Arg A → R.Arg A
hideArg (R.arg (R.arg-info _ m) a) = R.arg (R.arg-info R.hidden m) a
underPi : ∀ {ℓ} {A : Type ℓ}
→ (ty : R.Type)
→ (f : (tele : R.Telescope) → (ity : R.Type) → A)
→ A
underPi {A = A} = go [] where
go : (tele : R.Telescope)
→ (ty : R.Type)
→ (f : (tele : R.Telescope) → (ity : R.Type) → A)
→ A
go tele (R.pi pi-arg (R.abs name ty)) f = go ((name , pi-arg) ∷ tele) ty f
go tele ty@(_) f = f (List.rev tele) ty
getRecordDefinition : (r : R.Term) → R.TC R.Definition
getRecordDefinition (R.def f _) = R.getDefinition f
getRecordDefinition r@(_) = R.typeError $ R.strErr "Not a record definition: " ∷ R.termErr r ∷ []
getRecordΣFormat : (r : R.Term) → R.TC ΣFormat
getRecordΣFormat (R.def name _) = do
(R.record-type _ fs) ← R.getDefinition name
where _ → R.typeError (R.strErr "Not a record type name:" ∷ R.nameErr name ∷ [])
R.returnTC $ List→ΣFormat $ List.map (λ { (R.arg _ name) → name }) fs
getRecordΣFormat r@(_) = R.typeError $ R.strErr "Not a record definition: " ∷ R.termErr r ∷ []
inferTypeNormalised : R.Name → R.TC R.Type
inferTypeNormalised name = do
ty ← R.inferType (R.def name [])
R.normalise ty
recordName→ΣFormat : (recordName : R.Name) → R.TC ΣFormat
recordName→ΣFormat recordName = do
(R.record-type _ fs) ← R.getDefinition recordName
where _ → R.typeError (R.strErr "Not a record type name:" ∷ R.nameErr recordName ∷ [])
R.returnTC $ List→ΣFormat $ List.map (λ { (R.arg _ name) → name }) fs
recordIsoΣTermMacro : (record-term : R.Term) → (hole : R.Term) → R.TC Unit
recordIsoΣTermMacro record-term hole = do
σ ← getRecordΣFormat record-term
R.unify (recordIsoΣTerm σ) hole
equivΣMacro : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} → Iso A B → R.Term → R.TC Unit
equivΣMacro isoΣ hole = strictEquivMacro (isoΣ .fun) (isoΣ .inv) hole <|> isoToEquivMacro
where
isoToEquivMacro : R.TC Unit
isoToEquivMacro = do
`isoΣ ← R.quoteTC isoΣ
R.unify (R.def (quote isoToEquiv) (`isoΣ v∷ [])) hole
record RecordToΣ {ℓ} (R : Type ℓ) {S : Type ℓ} : Type (ℓ-suc ℓ) where
constructor toΣ
field
isoΣ : Iso R S
@(tactic equivΣMacro isoΣ) {equivΣ} : R ≃ S
defineRecordToΣ' : (id-name : R.Name) (iso-term : R.Term) → R.TC Unit
defineRecordToΣ' id-name iso-term =
R.defineFun id-name
$ R.clause [] (R.proj (quote RecordToΣ.isoΣ) v∷ []) iso-term
∷ []
defineRecordToΣ : (id-name record-name : R.Name) → R.TC Unit
defineRecordToΣ id-name record-name = do
σ ← recordName→ΣFormat record-name
defineRecordToΣ' id-name $ recordIsoΣTerm σ
declareRecordToΣ' : (id-name record-name : R.Name) (σ : ΣFormat) → R.TC Unit
declareRecordToΣ' id-name record-name σ = do
record-type ← inferTypeNormalised record-name
decl-type ← underPi record-type $ makeRecordToΣTele []
R.declareDef (iarg id-name) decl-type
where
σTy : R.Type
σTy = ΣFormat→Ty σ
makeRecordToΣTele : (params : List (R.Arg R.Type)) → R.Telescope → R.Type → R.TC R.Term
makeRecordToΣTele params ((name , pi-arg@(R.arg arg-inf _)) ∷ tele) ty = do
let var = R.arg arg-inf (v (List.length params))
decl ← makeRecordToΣTele (var ∷ params) tele ty
R.returnTC $ R.pi (hideArg pi-arg) (R.abs name decl)
makeRecordToΣTele params [] = λ where
(R.agda-sort _) → R.returnTC $ R.def (quote RecordToΣ) (R.def record-name params v∷ σTy hω∷ [])
ty@(_) → R.typeError
$ R.strErr "Failed to declare RecordToΣ instance: '"
∷ R.nameErr record-name
∷ R.strErr "' is not a parametrized record.\n"
∷ R.strErr "Expected a sort, got '"
∷ R.termErr ty
∷ R.strErr "'"
∷ []
deriveRecordToΣ : (id-name record-name : R.Name) → R.TC Unit
deriveRecordToΣ id-name record-name = do
σ ← recordName→ΣFormat record-name
declareRecordToΣ' id-name record-name σ
defineRecordToΣ' id-name $ recordIsoΣTerm σ
open RecordToΣ ⦃...⦄
infix 1.5 _asΣ
_asΣ : ∀ {ℓ} (R : Type ℓ) {S : Type ℓ} → ⦃ RecordToΣ R {S} ⦄ → Type ℓ
_asΣ R {S = S} = S
_IsoΣ : ∀ {ℓ} (R : Type ℓ) {S : Type ℓ} → ⦃ RecordToΣ R {S} ⦄ → Iso R S
R IsoΣ = isoΣ
_≃Σ : ∀ {ℓ} (R : Type ℓ) {S : Type ℓ} → ⦃ RecordToΣ R {S} ⦄ → R ≃ S
R ≃Σ = equivΣ
Σ≃_ : ∀ {ℓ} (R : Type ℓ) {S : Type ℓ} → ⦃ RecordToΣ R {S} ⦄ → S ≃ R
Σ≃ R = invEquiv equivΣ
cast→Σ : ∀ {ℓ} {R : Type ℓ} {S : Type ℓ} → ⦃ RecordToΣ R {S} ⦄ → R → S
cast→Σ = isoΣ .fun
cast←Σ : ∀ {ℓ} {R : Type ℓ} {S : Type ℓ} → ⦃ RecordToΣ R {S} ⦄ → S → R
cast←Σ = isoΣ .inv
recordIsOfHLevel : ∀ {ℓ} {R S : Type ℓ} → ⦃ RecordToΣ R {S} ⦄ → (n : HLevel) → isOfHLevel n S → isOfHLevel n R
recordIsOfHLevel n = isOfHLevelRetractFromIso n isoΣ