--------------------------------------------------------------------------------
-- This is part of Agda Inference Systems 

{-# OPTIONS --guardedness #-}

open import Agda.Builtin.Equality
open import Data.Product
open import Level
open import Relation.Unary using (_โІ_)

module is-lib.InfSys.Coinduction {๐“} where

  private
    variable
      U : Set ๐“
  
  open import is-lib.InfSys.Base {๐“}
  open import is-lib.InfSys.Induction {๐“}
  open MetaRule
  open IS
  
  {- Coinductive interpretation -}

  record CoIndโŸฆ_โŸง {๐“c ๐“p ๐“n : Level} (is : IS {๐“c} {๐“p} {๐“n} U) (u : U) : Set (๐“ โŠ” ๐“c โŠ” ๐“p โŠ” ๐“n) where
    coinductive
    constructor cofold_
    field
      unfold : ISF[ is ] CoIndโŸฆ is โŸง u

  {- Coinduction Principle -}

  coind[_] : โˆ€{๐“c ๐“p ๐“n ๐“'}
      โ†’ (is : IS {๐“c} {๐“p} {๐“n} U) 
      โ†’ (S : U โ†’ Set ๐“')
      โ†’ (S โІ ISF[ is ] S)   -- S is consistent
      โ†’ S โІ CoIndโŸฆ is โŸง
  CoIndโŸฆ_โŸง.unfold (coind[ is ] S cn Su) with cn Su
  ... | rn , c , refl , pr = rn , c , refl , ฮป i โ†’ coind[ is ] S cn (pr i)

  {- Apply Rule -}

  apply-coind : โˆ€{๐“c ๐“p ๐“n}{is : IS {๐“c} {๐“p} {๐“n} U} โ†’ (rn : is .Names) โ†’ RClosed (is .rules rn) CoIndโŸฆ is โŸง
  apply-coind {is = is} rn = prefixโ‡’closed (is .rules rn) {P = CoIndโŸฆ _ โŸง} ฮป{(c , refl , pr) โ†’ cofold (rn , c , refl , pr)}

  {- Postfix - Prefix -}

  coind-postfix : โˆ€{๐“c ๐“p ๐“n}{is : IS {๐“c} {๐“p} {๐“n} U} โ†’ CoIndโŸฆ is โŸง โІ ISF[ is ] CoIndโŸฆ is โŸง
  coind-postfix x = x .CoIndโŸฆ_โŸง.unfold
  
  coind-prefix : โˆ€{๐“c ๐“p ๐“n}{is : IS {๐“c} {๐“p} {๐“n} U} โ†’ ISF[ is ] CoIndโŸฆ is โŸง โІ CoIndโŸฆ is โŸง
  coind-prefix x = cofold x