{-# OPTIONS --safe --without-K #-}
open import Prelude
module Generics.RecursionScheme where
open import Generics.Telescope
open import Generics.Description
open import Generics.Algebra
open import Generics.Recursion
private variable
rb : RecB
cb : ConB
cbs : ConBs
FoldOpTᶜ : {I : Set ℓⁱ} (D : ConD I cb) → (I → Set ℓ) → Set (max-π cb ⊔ max-σ cb ⊔ ℓ)
FoldOpTᶜ (ι i ) X = X i
FoldOpTᶜ (σ A D) X = (a : A) → FoldOpTᶜ (D a) X
FoldOpTᶜ (ρ D E) X = ⟦ D ⟧ʳ X → FoldOpTᶜ E X
FoldOpTelᶜˢ : {I : Set ℓⁱ} (D : ConDs I cbs) → (I → Set ℓ)
→ Tel (maxMap max-π cbs ⊔ maxMap max-σ cbs ⊔ hasCon? ℓ cbs)
FoldOpTelᶜˢ [] X = []
FoldOpTelᶜˢ (D ∷ Ds) X = [ _ ∶ FoldOpTᶜ D X ] FoldOpTelᶜˢ Ds X
fold-opᶜ : {I : Set ℓⁱ} (D : ConD I cb) {X : Carrierᶜ D ℓ} → FoldOpTᶜ D X → Algᶜ D X
fold-opᶜ (ι i ) f refl = f
fold-opᶜ (σ A D) f (a , xs ) = fold-opᶜ (D a) (f a ) xs
fold-opᶜ (ρ D E) f (xs , xs') = fold-opᶜ E (f xs) xs'
fold-opᶜˢ : {I : Set ℓⁱ} (D : ConDs I cbs) {X : Carrierᶜˢ D ℓ}
→ ⟦ FoldOpTelᶜˢ D X ⟧ᵗ → Algᶜˢ D X
fold-opᶜˢ (D ∷ Ds) (f , fs) (inl xs) = fold-opᶜ D f xs
fold-opᶜˢ (D ∷ Ds) (f , fs) (inr xs) = fold-opᶜˢ Ds fs xs
fold-operator : ∀ (n : Name) {D N} ⦃ C : Named n (DataC D N) ⦄ → FoldP
fold-operator _ {D} ⦃ named C ⦄ = record
{ Conv = C
; #levels = suc (DataD.#levels D)
; level = snd
; Param = λ (ℓ , ℓs) → let Dᵖ = DataD.applyL D ℓs in
[[ ps ∶ PDataD.Param Dᵖ ]]
[ X ∶ Curriedᵗ (PDataD.Index Dᵖ ps) (constTelInfo visible) (λ _ → Set ℓ) ]
FoldOpTelᶜˢ (PDataD.applyP Dᵖ ps) (uncurryᵗ X)
; param = fst
; ParamV = constTelInfo hidden ++ λ _ → hidden ∷ λ _ → constTelInfo visible
; ParamN = constTelInfo "p" ++ λ _ → "X" ∷ λ _ → constTelInfo "alg"
; Carrier = λ _ (_ , X , _) → uncurryᵗ X
; algebra = λ (ps , _ , args) → fold-opᶜˢ (PDataD.applyP (DataD.applyL D _) ps) args }
Homᶜ : {I : Set ℓⁱ} (D : ConD I cb) {X : I → Set ℓˣ} {Y : I → Set ℓʸ}
→ FoldOpTᶜ D X → FoldOpTᶜ D Y → (∀ {i} → X i → Y i)
→ ∀ {i} → ⟦ D ⟧ᶜ X i → Set (max-π cb ⊔ ℓʸ)
Homᶜ (ι i ) x y h _ = h x ≡ y
Homᶜ (σ A D) f g h (a , xs) = Homᶜ (D a) (f a) (g a) h xs
Homᶜ (ρ D E) {X} {Y} f g h (xs , xs') =
(ys : ⟦ D ⟧ʳ Y) → ExtEqʳ D (fmapʳ D h xs) ys → Homᶜ E (f xs) (g ys) h xs'
∀ᶜ : {I : Set ℓⁱ} (D : ConD I cb) {X : Carrierᶜ D ℓˣ}
→ (∀ {i} → ⟦ D ⟧ᶜ X i → Set ℓʸ) → Set (max-π cb ⊔ max-σ cb ⊔ hasRec? ℓˣ cb ⊔ ℓʸ)
∀ᶜ (ι i ) Y = Y refl
∀ᶜ (σ A D) Y = (a : A) → ∀ᶜ (D a) (curry Y a)
∀ᶜ (ρ D E) {X} Y = (xs : ⟦ D ⟧ʳ X) → ∀ᶜ E (curry Y xs)
∀ᶜ-apply : {I : Set ℓⁱ} (D : ConD I cb)
{X : Carrierᶜ D ℓˣ} {Y : ∀ {i} → ⟦ D ⟧ᶜ X i → Set ℓʸ}
→ ∀ᶜ D Y → ∀ {i} (xs : ⟦ D ⟧ᶜ X i) → Y xs
∀ᶜ-apply (ι i ) y refl = y
∀ᶜ-apply (σ A D) f (a , xs ) = ∀ᶜ-apply (D a) (f a) xs
∀ᶜ-apply (ρ D E) f (xs , xs') = ∀ᶜ-apply E (f xs) xs'
Homᶜˢ : {I : Set ℓⁱ} (D : ConDs I cbs) {X : I → Set ℓˣ} {Y : I → Set ℓʸ}
→ ⟦ FoldOpTelᶜˢ D X ⟧ᵗ → ⟦ FoldOpTelᶜˢ D Y ⟧ᵗ → (∀ {i} → X i → Y i)
→ Tel (maxMap max-π cbs ⊔ maxMap max-σ cbs ⊔ maxMap (hasRec? ℓˣ) cbs ⊔ hasCon? ℓʸ cbs)
Homᶜˢ [] _ _ h = []
Homᶜˢ (D ∷ Ds) (f , fs) (g , gs) h = [ _ ∶ ∀ᶜ D (Homᶜ D f g h) ] Homᶜˢ Ds fs gs h
fold-fusionʳ :
{I : Set ℓⁱ} (D : RecD I rb) {N : I → Set ℓ} {X : I → Set ℓˣ} {Y : I → Set ℓʸ}
(fold-fs : ∀ {i} → N i → X i) (fold-gs : ∀ {i} → N i → Y i)
→ (h : ∀ {i} → X i → Y i) (ns : ⟦ D ⟧ʳ N) → Allʳ D (λ _ n → h (fold-fs n) ≡ fold-gs n) ns
→ ExtEqʳ D (fmapʳ D h (fmapʳ D fold-fs ns)) (fmapʳ D fold-gs ns)
fold-fusionʳ (ι i ) fold-fs fold-gs h n eq = eq
fold-fusionʳ (π A D) fold-fs fold-gs h ns all =
λ a → fold-fusionʳ (D a) fold-fs fold-gs h (ns a) (all a)
fold-fusionᶜ :
{I : Set ℓⁱ} (D : ConD I cb) {N : I → Set ℓ} {X : I → Set ℓˣ} {Y : I → Set ℓʸ}
(f : FoldOpTᶜ D X) (g : FoldOpTᶜ D Y)
(fold-fs : ∀ {i} → N i → X i) (fold-gs : ∀ {i} → N i → Y i)
→ (h : ∀ {i} → X i → Y i) → (∀ {i} (xs : ⟦ D ⟧ᶜ X i) → Homᶜ D f g h xs)
→ ∀ {i} (ns : ⟦ D ⟧ᶜ N i) → Allᶜ D (λ _ n → h (fold-fs n) ≡ fold-gs n) ns ℓ'
→ h (fold-opᶜ D f (fmapᶜ D fold-fs ns)) ≡ fold-opᶜ D g (fmapᶜ D fold-gs ns)
fold-fusionᶜ (ι i ) x y fold-fs fold-gs h hom refl all = hom refl
fold-fusionᶜ (σ A D) f g fold-fs fold-gs h hom (a , ns) all =
fold-fusionᶜ (D a) (f a) (g a) fold-fs fold-gs h (curry hom a) ns all
fold-fusionᶜ (ρ D E) f g fold-fs fold-gs h hom (ns , ns') (all , all') =
fold-fusionᶜ E (f (fmapʳ D fold-fs ns)) (g (fmapʳ D fold-gs ns)) fold-fs fold-gs h
(λ xs → hom (fmapʳ D fold-fs ns , xs) (fmapʳ D fold-gs ns)
(fold-fusionʳ D fold-fs fold-gs h ns all)) ns' all'
fold-fusionᶜˢ :
{I : Set ℓⁱ} (D : ConDs I cbs) {N : I → Set ℓ} {X : I → Set ℓˣ} {Y : I → Set ℓʸ}
(fs : ⟦ FoldOpTelᶜˢ D X ⟧ᵗ) (gs : ⟦ FoldOpTelᶜˢ D Y ⟧ᵗ)
(fold-fs : ∀ {i} → N i → X i) (fold-gs : ∀ {i} → N i → Y i)
→ (h : ∀ {i} → X i → Y i) → ⟦ Homᶜˢ D fs gs h ⟧ᵗ
→ ∀ {i} (ns : ⟦ D ⟧ᶜˢ N i) → Allᶜˢ D (λ _ n → h (fold-fs n) ≡ fold-gs n) ns ℓ'
→ h (fold-opᶜˢ D fs (fmapᶜˢ D fold-fs ns)) ≡ fold-opᶜˢ D gs (fmapᶜˢ D fold-gs ns)
fold-fusionᶜˢ (D ∷ Ds) (f , _ ) (g , _ ) fold-fs fold-gs h (hom , _) (inl ns) all =
fold-fusionᶜ D f g fold-fs fold-gs h (∀ᶜ-apply D hom) ns all
fold-fusionᶜˢ (D ∷ Ds) (_ , fs) (_ , gs) fold-fs fold-gs h (_ , hom) (inr ns) all =
fold-fusionᶜˢ Ds fs gs fold-fs fold-gs h hom ns all
fold-fusion : ∀ (n : Name) {D N} ⦃ C : Named n (DataC D N) ⦄
{fold} ⦃ foldC : FoldC (fold-operator n ⦃ C ⦄) fold ⦄ → IndP
fold-fusion _ {D} ⦃ named C ⦄ {fold} ⦃ foldC ⦄ = record
{ Conv = C
; #levels = suc (suc (DataD.#levels D))
; level = snd ∘ snd
; Param = λ (ℓˣ , ℓʸ , ℓs) → let Dᵖ = DataD.applyL D ℓs in
[[ ps ∶ PDataD.Param Dᵖ ]]
let ITel = PDataD.Index Dᵖ ps; Dᶜˢ = PDataD.applyP Dᵖ ps in
[ X ∶ Curriedᵗ ITel (constTelInfo visible) (λ _ → Set ℓˣ) ]
[ Y ∶ Curriedᵗ ITel (constTelInfo visible) (λ _ → Set ℓʸ) ]
[ h ∶ Curriedᵗ ITel (constTelInfo hidden ) (λ is → uncurryᵗ X is → uncurryᵗ Y is) ]
[[ fs ∶ FoldOpTelᶜˢ Dᶜˢ (uncurryᵗ X) ]]
[[ gs ∶ FoldOpTelᶜˢ Dᶜˢ (uncurryᵗ Y) ]]
Homᶜˢ Dᶜˢ fs gs (λ {is} → uncurryᵗ h is)
; param = fst
; ParamV = constTelInfo hidden ++ λ _ →
hidden ∷ λ _ → hidden ∷ λ _ → visible ∷ λ _ →
constTelInfo hidden ++ λ _ → constTelInfo hidden ++ λ _ → constTelInfo visible
; ParamN = constTelInfo "p" ++ λ _ → "X" ∷ λ _ → "Y" ∷ λ _ → "h" ∷ λ _ →
constTelInfo "f" ++ λ _ → constTelInfo "g" ++ λ _ → constTelInfo "hom"
; Carrier = λ _ (ps , X , Y , h , fs , gs , _) is n →
uncurryᵗ h is (fold _ (ps , X , fs) n) ≡ fold _ (ps , Y , gs) n
; algebra = λ (ps , X , Y , h , fs , gs , hom) {is} ns all →
let Dᶜˢ = PDataD.applyP (DataD.applyL D _) ps in
begin
uncurryᵗ h is (fold _ (ps , X , fs) (DataC.toN C ns))
≡⟨ cong (uncurryᵗ h is) (FoldC.equation foldC ns) ⟩
uncurryᵗ h is (fold-opᶜˢ Dᶜˢ fs (fmapᶜˢ Dᶜˢ (fold _ (ps , X , fs)) ns))
≡⟨ fold-fusionᶜˢ Dᶜˢ fs gs (fold _ (ps , X , fs)) (fold _ (ps , Y , gs))
(λ {is} → uncurryᵗ h is) hom ns all ⟩'
fold-opᶜˢ Dᶜˢ gs (fmapᶜˢ Dᶜˢ (fold _ (ps , Y , gs)) ns)
≡⟨ sym (FoldC.equation foldC ns) ⟩'
fold _ (ps , Y , gs) (DataC.toN C ns)
∎ } where open ≡-Reasoning
IndOpTʳ : {I : Set ℓⁱ} (D : RecD I rb) {N : I → Set ℓ} → ⟦ D ⟧ʳ N
→ (∀ i → N i → Set ℓ') → Set (max-ℓ rb ⊔ ℓ')
IndOpTʳ (ι i ) n P = P i n
IndOpTʳ (π A D) ns P = (a : A) → IndOpTʳ (D a) (ns a) P
IndOpTᶜ : {I : Set ℓⁱ} (D : ConD I cb) {N : Carrierᶜ D ℓ} → Algᶜ D N
→ (P : IndCarrierᶜ D N ℓ') → Set (max-π cb ⊔ max-σ cb ⊔ hasRec? ℓ cb ⊔ ℓ')
IndOpTᶜ (ι i ) f P = P i (f refl)
IndOpTᶜ (σ A D) f P = (a : A) → IndOpTᶜ (D a) (curry f a) P
IndOpTᶜ (ρ D E) {N} f P = (ns : ⟦ D ⟧ʳ N) → IndOpTʳ D ns P → IndOpTᶜ E (curry f ns) P
IndOpTelᶜˢ : {I : Set ℓⁱ} (D : ConDs I cbs) {N : Carrierᶜˢ D ℓ} → Algᶜˢ D N
→ (P : IndCarrierᶜˢ D N ℓ') → Tel (maxMap max-π cbs ⊔ maxMap max-σ cbs ⊔
maxMap (hasRec? ℓ) cbs ⊔ hasCon? ℓ' cbs)
IndOpTelᶜˢ [] f P = []
IndOpTelᶜˢ (D ∷ Ds) f P = [ _ ∶ IndOpTᶜ D (f ∘ inl) P ] IndOpTelᶜˢ Ds (f ∘ inr) P
ind-opʳ : {I : Set ℓⁱ} (D : RecD I rb) {N : I → Set ℓ} (ns : ⟦ D ⟧ʳ N)
{P : ∀ i → N i → Set ℓ'} → Allʳ D P ns → IndOpTʳ D ns P
ind-opʳ (ι i ) n p = p
ind-opʳ (π A D) ns all = λ a → ind-opʳ (D a) (ns a) (all a)
ind-opᶜ : {I : Set ℓⁱ} (D : ConD I cb) {N : Carrierᶜ D ℓ} (f : Algᶜ D N)
{P : IndCarrierᶜ D N ℓ'} → IndOpTᶜ D f P → IndAlgᶜ D f P ℓ''
ind-opᶜ (ι i ) f p refl all = p
ind-opᶜ (σ A D) f g (a , ns ) all = ind-opᶜ (D a) (curry f a) (g a) ns all
ind-opᶜ (ρ D E) f g (ns , ns') (all , all') =
ind-opᶜ E (curry f ns) (g ns (ind-opʳ D ns all)) ns' all'
ind-opᶜˢ : {I : Set ℓⁱ} (D : ConDs I cbs) {N : Carrierᶜˢ D ℓ} (f : Algᶜˢ D N)
{P : IndCarrierᶜˢ D N ℓ'} → ⟦ IndOpTelᶜˢ D f P ⟧ᵗ → IndAlgᶜˢ D f P ℓ''
ind-opᶜˢ (D ∷ Ds) f (g , gs) (inl ps) = ind-opᶜ D (f ∘ inl) g ps
ind-opᶜˢ (D ∷ Ds) f (g , gs) (inr ps) = ind-opᶜˢ Ds (f ∘ inr) gs ps
ind-operator : ∀ (n : Name) {D N} ⦃ C : Named n (DataC D N) ⦄ → IndP
ind-operator _ {D} {N} ⦃ named C ⦄ = record
{ Conv = C
; #levels = suc (DataD.#levels D)
; level = snd
; Param = λ (ℓ , ℓs) → let Dᵖ = DataD.applyL D ℓs in
[[ ps ∶ PDataD.Param Dᵖ ]] let Dᶜˢ = PDataD.applyP Dᵖ ps in
[ P ∶ Curriedᵗ (PDataD.Index Dᵖ ps) (constTelInfo hidden)
(λ is → N ℓs ps is → Set ℓ) ]
IndOpTelᶜˢ Dᶜˢ (DataC.toN C) (uncurryᵗ P)
; param = fst
; ParamV = constTelInfo hidden ++ λ _ → visible ∷ λ _ → constTelInfo visible
; ParamN = constTelInfo "p" ++ λ _ → "P" ∷ λ _ → constTelInfo "ind-case"
; Carrier = λ _ (_ , P , _) is n → uncurryᵗ P is n
; algebra = λ (ps , P , fs) →
ind-opᶜˢ (PDataD.applyP (DataD.applyL D _) ps) (DataC.toN C) fs }