{-# OPTIONS --cubical --safe #-}

module Control.Monad.Levels.Eliminators where

open import Prelude
open import Data.Bag
open import Control.Monad.Levels.Definition

record Eliminator {a p} (A : Type a) (P : Levels A  Type p) : Type (a ℓ⊔ p) where
  constructor elim
  field
    ⟦_⟧-set :  {xs}  isSet (P xs)
    ⟦_⟧_∷_⟨_⟩ :  x xs  P xs  P (x  xs)
    ⟦_⟧[] : P []
    ⟦_⟧-trail : PathP  i  P (trail i)) (⟦_⟧_∷_⟨_⟩ [] [] ⟦_⟧[]) ⟦_⟧[]

  run :  xs  P xs
  run (x  xs) = ⟦_⟧_∷_⟨_⟩ x xs (run xs)
  run [] = ⟦_⟧[]
  run (trail i) = ⟦_⟧-trail i
  run (trunc xs ys x y i j) =
    isOfHLevel→isOfHLevelDep 2
       xs  ⟦_⟧-set {xs})
      (run xs) (run ys)
      (cong run x) (cong run y)
      (trunc xs ys x y)
      i j

  _⇓_ : (xs : Levels A)  P xs
  _⇓_ = run
  {-# INLINE _⇓_ #-}
open Eliminator public
infixr 1 Eliminator

syntax Eliminator A  v  e) = Levels-Π[ v  e ] A

record Recursor (A : Type a) (B : Type b) : Type (a ℓ⊔ b) where
  constructor rec
  field
    [_]-set : isSet B
    [_]_∷_⟨_⟩ : (x :  A )  (xs : Levels A)  B  B
    [_][] : B
  private f = [_]_∷_⟨_⟩; z = [_][]
  field
    [_]-trail : f [] [] z  z

  _↑ : Eliminator A  _  B)
  _↑ = elim [_]-set f z [_]-trail

  _↓_ : Levels A  B
  _↓_ = run _↑
  {-# INLINE _↑ #-}
  {-# INLINE _↓_ #-}
open Recursor public

infixr 1 Recursor

syntax Recursor A B = Levels-ϕ[ A ] B

infix 4 _⊜_
record AnEquality (A : Type a) : Type a where
  constructor _⊜_
  field lhs rhs : Levels A
open AnEquality public

record Property {r} (A : Type a) (P : Levels A  Type r) : Type (a ℓ⊔ r) where
  constructor property
  field
    ∥_∥-prop :  {xs}  isProp (P xs)
    ∥_∥_∷_⟨_⟩ : (x :  A )  (xs : Levels A)  P xs  P (x  xs)
    ∥_∥[] : P []
  private z = ∥_∥[]; f = ∥_∥_∷_⟨_⟩
  ∥_∥⇑ = elim
           {xs}  isProp→isSet (∥_∥-prop {xs}))
          f z
          (toPathP (∥_∥-prop (transp  i  P (trail i)) i0 (f [] [] z)) z))
  ∥_∥⇓ = run ∥_∥⇑
  {-# INLINE ∥_∥⇑ #-}
  {-# INLINE ∥_∥⇓ #-}
open Property public

infixr 1 Property

syntax Property A  v  e) = Levels-ψ[ v  A ] e

record EqualityProof {B : Type b} (A : Type a) (P : Levels A  AnEquality B) : Type (a ℓ⊔ b) where
  Pr : Levels A  Type b
  Pr xs = let e = P xs in lhs e  rhs e

  field
    ⟦_⟧≡_∷_⟨_⟩ : (x :  A )  (xs : Levels A)  Pr xs  Pr (x  xs)
    ⟦_⟧≡[] : Pr []

  _⇑≡ : Eliminator A Pr
  _⇑≡ =  property (trunc _ _) ⟦_⟧≡_∷_⟨_⟩ ⟦_⟧≡[] ∥⇑

  _⇓≡_ : (xs : Levels A)  Pr xs
  _⇓≡_ = run _⇑≡
  {-# INLINE _⇑≡ #-}
  {-# INLINE _⇓≡_ #-}
open EqualityProof public

infixr 1 EqualityProof
syntax EqualityProof A  v  e) = Levels-ψ[ v  A ]≡ e