------------------------------------------------------------------------
-- The Agda standard library
--
-- Syntax for the building blocks of equational reasoning modules
------------------------------------------------------------------------

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

open import Level using (Level; _⊔_; suc)
open import Relation.Nullary.Decidable.Core
  using (Dec; True; toWitness)
open import Relation.Nullary.Negation using (contradiction)
open import Relation.Binary.Core using (Rel; REL; _⇒_)
open import Relation.Binary.Definitions
open import Relation.Binary.PropositionalEquality.Core as P
  using (_≡_)

-- List of `Reasoning` modules that do not use this framework and so
-- need to be updated manually if the syntax changes.
--
--   Data/Vec/Relation/Binary/Equality/Cast
--   Relation/Binary/HeterogeneousEquality
--   Effect/Monad/Partiality
--   Effect/Monad/Partiality/All
--   Codata/Guarded/Stream/Relation/Binary/Pointwise
--   Function/Reasoning

module Relation.Binary.Reasoning.Syntax where

private
  variable
    a ℓ₁ ℓ₂ ℓ₃ ℓ₄ : Level
    A B C : Set a
    x y z : A

------------------------------------------------------------------------
-- Syntax for beginning a reasoning chain
------------------------------------------------------------------------

------------------------------------------------------------------------
-- Basic begin syntax

module begin-syntax
  (R : REL A B ℓ₁)
  {S : REL A B ℓ₂}
  (reflexive : R  S)
  where

  infix 1 begin_

  begin_ : R x y  S x y
  begin_ = reflexive

------------------------------------------------------------------------
-- Begin subrelation syntax

-- Sometimes we want to support sub-relations with the
-- same reasoning operators as the main relations (e.g. perform equality
-- proofs with non-strict reasoning operators). This record bundles all
-- the parts needed to extract the sub-relation proofs.
record SubRelation {A : Set a} (R : Rel A ℓ₁) ℓ₂ ℓ₃ : Set (a  ℓ₁  suc ℓ₂  suc ℓ₃) where
  field
    S : Rel A ℓ₂
    IsS : R x y  Set ℓ₃
    IsS? :  (xRy : R x y)  Dec (IsS xRy)
    extract :  {xRy : R x y}  IsS xRy  S x y

module begin-subrelation-syntax
  (R : Rel A ℓ₁)
  (sub : SubRelation R ℓ₂ ℓ₃)
  where
  open SubRelation sub

  infix 1 begin_

  begin_ :  {x y} (xRy : R x y)  {s : True (IsS? xRy)}  S x y
  begin_ r {s} = extract (toWitness s)

-- Begin equality syntax
module begin-equality-syntax
  (R : Rel A ℓ₁)
  (sub : SubRelation R ℓ₂ ℓ₃) where

  open begin-subrelation-syntax R sub public
    renaming (begin_ to begin-equality_)

-- Begin apartness syntax
module begin-apartness-syntax
  (R : Rel A ℓ₁)
  (sub : SubRelation R ℓ₂ ℓ₃) where

  open begin-subrelation-syntax R sub public
    renaming (begin_ to begin-apartness_)

-- Begin strict syntax
module begin-strict-syntax
  (R : Rel A ℓ₁)
  (sub : SubRelation R ℓ₂ ℓ₃) where

  open begin-subrelation-syntax R sub public
    renaming (begin_ to begin-strict_)

------------------------------------------------------------------------
-- Begin membership syntax

module begin-membership-syntax
  (R : Rel A ℓ₁)
  (_∈_ : REL B A ℓ₂)
  (resp : _∈_ Respectsʳ R) where

  infix  1 step-∈

  step-∈ :  (x : B) {xs ys}  R xs ys  x  xs  x  ys
  step-∈ x = resp

  syntax step-∈ x  xs⊆ys x∈xs  = x ∈⟨ x∈xs  xs⊆ys

------------------------------------------------------------------------
-- Begin contradiction syntax

-- Used with asymmetric subrelations to derive a contradiction from a
-- proof that an element is related to itself.
module begin-contradiction-syntax
  (R : Rel A ℓ₁)
  (sub : SubRelation R ℓ₂ ℓ₃)
  (asym : Asymmetric (SubRelation.S sub))
  where

  open SubRelation sub

  infix 1 begin-contradiction_

  begin-contradiction_ :  (xRx : R x x) {s : True (IsS? xRx)} 
                          {b} {B : Set b}  B
  begin-contradiction_ {x} r {s} = contradiction x<x (asym x<x)
    where
    x<x : S x x
    x<x = extract (toWitness s)

------------------------------------------------------------------------
-- Syntax for continuing a chain of reasoning steps
------------------------------------------------------------------------

-- Note that the arguments to the `step`s are not provided in their
-- "natural" order and syntax declarations are later used to re-order
-- them. This is because the `step` ordering allows the type-checker to
-- better infer the middle argument `y` from the `_IsRelatedTo_`
-- argument (see issue 622).
--
-- This has two practical benefits. First it speeds up type-checking by
-- approximately a factor of 5. Secondly it allows the combinators to be
-- used with macros that use reflection, e.g. `Tactic.RingSolver`, where
-- they need to be able to extract `y` using reflection.

------------------------------------------------------------------------
-- Syntax for unidirectional relations

-- See https://github.com/agda/agda-stdlib/issues/2150 for a possible
-- simplification.

module _
  {R : REL A B ℓ₂}
  (S : REL B C ℓ₁)
  (T : REL A C ℓ₃)
  (step : Trans R S T)
  where

  forward :  (x : A) {y z}  S y z  R x y  T x z
  forward x yRz x∼y = step {x} x∼y yRz

  -- Arbitrary relation syntax
  module ∼-syntax where
    infixr 2 step-∼
    step-∼ = forward
    syntax step-∼ x yRz x∼y = x ∼⟨ x∼y  yRz


  -- Preorder syntax
  module ≲-syntax where
    infixr 2 step-≲
    step-≲ = forward
    syntax step-≲ x yRz x≲y = x ≲⟨ x≲y  yRz


  -- Partial order syntax
  module ≤-syntax where
    infixr 2 step-≤
    step-≤ = forward
    syntax step-≤ x yRz x≤y = x ≤⟨ x≤y  yRz


  -- Strict partial order syntax
  module <-syntax where
    infixr 2 step-<
    step-< = forward
    syntax step-< x yRz x<y = x <⟨ x<y  yRz


  -- Subset order syntax
  module ⊆-syntax where
    infixr 2 step-⊆
    step-⊆ = forward
    syntax step-⊆ x yRz x⊆y = x ⊆⟨ x⊆y  yRz


  -- Strict subset order syntax
  module ⊂-syntax where
    infixr 2 step-⊂
    step-⊂ = forward
    syntax step-⊂ x yRz x⊂y = x ⊂⟨ x⊂y  yRz


  -- Square subset order syntax
  module ⊑-syntax where
    infixr 2 step-⊑
    step-⊑ = forward
    syntax step-⊑ x yRz x⊑y = x ⊑⟨ x⊑y  yRz


  -- Strict square subset order syntax
  module ⊏-syntax where
    infixr 2 step-⊏
    step-⊏ = forward
    syntax step-⊏ x yRz x⊏y = x ⊏⟨ x⊏y  yRz


  -- Divisibility syntax
  module ∣-syntax where
    infixr 2 step-∣
    step-∣ = forward
    syntax step-∣ x yRz x∣y = x ∣⟨ x∣y  yRz


  -- Single-step syntax
  module ⟶-syntax where
    infixr 2 step-⟶
    step-⟶ = forward
    syntax step-⟶ x yRz x∣y = x ⟶⟨ x∣y  yRz


  -- Multi-step syntax
  module ⟶*-syntax where
    infixr 2 step-⟶*
    step-⟶* = forward
    syntax step-⟶* x yRz x∣y = x ⟶*⟨ x∣y  yRz


------------------------------------------------------------------------
-- Syntax for bidirectional relations

  module _
    {U : REL B A ℓ₄}
    (sym : Sym U R)
    where

    backward :  x {y z}  S y z  U y x  T x z
    backward x yRz x≈y = forward x yRz (sym x≈y)

    -- Setoid equality syntax
    module ≈-syntax where
      infixr 2 step-≈-⟩ step-≈-⟨
      step-≈-⟩ = forward
      step-≈-⟨ = backward
      syntax step-≈-⟩ x yRz x≈y = x ≈⟨ x≈y  yRz
      syntax step-≈-⟨ x yRz y≈x = x ≈⟨ y≈x  yRz

      -- Deprecated
      infixr 2 step-≈ step-≈˘
      step-≈ = step-≈-⟩
      {-# WARNING_ON_USAGE step-≈
      "Warning: step-≈ was deprecated in v2.0.
      Please use step-≈-⟩ instead."
      #-}
      step-≈˘ = step-≈-⟨
      {-# WARNING_ON_USAGE step-≈˘
      "Warning: step-≈˘ and _≈˘⟨_⟩_ was deprecated in v2.0.
      Please use step-≈-⟨ and _≈⟨_⟨_ instead."
      #-}
      syntax step-≈˘ x yRz y≈x = x ≈˘⟨ y≈x  yRz


    -- Container equality syntax
    module ≋-syntax where
      infixr 2 step-≋-⟩ step-≋-⟨
      step-≋-⟩ = forward
      step-≋-⟨ = backward
      syntax step-≋-⟩ x yRz x≋y = x ≋⟨ x≋y  yRz
      syntax step-≋-⟨ x yRz y≋x = x ≋⟨ y≋x  yRz


      -- Don't remove until https://github.com/agda/agda/issues/5617 fixed.
      infixr 2 step-≋ step-≋˘
      step-≋ = step-≋-⟩
      {-# WARNING_ON_USAGE step-≋
      "Warning: step-≋ was deprecated in v2.0.
      Please use step-≋-⟩ instead."
      #-}
      step-≋˘ = step-≋-⟨
      {-# WARNING_ON_USAGE step-≋˘
      "Warning: step-≋˘ and _≋˘⟨_⟩_ was deprecated in v2.0.
      Please use step-≋-⟨ and _≋⟨_⟨_ instead."
      #-}
      syntax step-≋˘ x yRz y≋x = x ≋˘⟨ y≋x  yRz


    -- Other equality syntax
    module ≃-syntax where
      infixr 2 step-≃-⟩ step-≃-⟨
      step-≃-⟩ = forward
      step-≃-⟨ = backward
      syntax step-≃-⟩ x yRz x≃y = x ≃⟨ x≃y  yRz
      syntax step-≃-⟨ x yRz y≃x = x ≃⟨ y≃x  yRz


    -- Apartness relation syntax
    module #-syntax where
      infixr 2 step-#-⟩ step-#-⟨
      step-#-⟩ = forward
      step-#-⟨ = backward
      syntax step-#-⟩ x yRz x#y = x #⟨ x#y  yRz
      syntax step-#-⟨ x yRz y#x = x #⟨ y#x  yRz

      -- Don't remove until https://github.com/agda/agda/issues/5617 fixed.
      infixr 2 step-# step-#˘
      step-# = step-#-⟩
      {-# WARNING_ON_USAGE step-#
      "Warning: step-# was deprecated in v2.0.
      Please use step-#-⟩ instead."
      #-}
      step-#˘ = step-#-⟨
      {-# WARNING_ON_USAGE step-#˘
      "Warning: step-#˘ and _#˘⟨_⟩_ was deprecated in v2.0.
      Please use step-#-⟨ and _#⟨_⟨_ instead."
      #-}
      syntax step-#˘ x yRz y#x = x #˘⟨ y#x  yRz


    -- Bijection syntax
    module ⤖-syntax where
      infixr 2 step-⤖ step-⬻
      step-⤖ = forward
      step-⬻ = backward
      syntax step-⤖ x yRz x⤖y = x ⤖⟨ x⤖y  yRz
      syntax step-⬻ x yRz y⤖x = x ⬻⟨ y⤖x  yRz


    -- Inverse syntax
    module ↔-syntax where
      infixr 2 step-↔-⟩ step-↔-⟨
      step-↔-⟩ = forward
      step-↔-⟨ = backward
      syntax step-↔-⟩ x yRz x↔y = x ↔⟨ x↔y  yRz
      syntax step-↔-⟨ x yRz y↔x = x ↔⟨ y↔x  yRz


    -- Inverse syntax
    module ↭-syntax where
      infixr 2 step-↭-⟩ step-↭-⟨
      step-↭-⟩ = forward
      step-↭-⟨ = backward
      syntax step-↭-⟩ x yRz x↭y = x ↭⟨ x↭y  yRz
      syntax step-↭-⟨ x yRz y↭x = x ↭⟨ y↭x  yRz


      -- Don't remove until https://github.com/agda/agda/issues/5617 fixed.
      infixr 2 step-↭ step-↭˘
      step-↭ = forward
      {-# WARNING_ON_USAGE step-↭
      "Warning: step-↭ was deprecated in v2.0.
      Please use step-↭-⟩ instead."
      #-}
      step-↭˘ = backward
      {-# WARNING_ON_USAGE step-↭˘
      "Warning: step-↭˘ and _↭˘⟨_⟩_ was deprecated in v2.0.
      Please use step-↭-⟨ and _↭⟨_⟨_ instead."
      #-}
      syntax step-↭˘ x yRz y↭x = x ↭˘⟨ y↭x  yRz

------------------------------------------------------------------------
-- Propositional equality

-- Crucially often the step function cannot just be `subst` or pattern
-- match on `refl` as we often want to compute which constructor the
-- relation begins with, in order for the implicit subrelation
-- arguments to resolve. See `≡-noncomputable-syntax` below if this
-- is not required.
module ≡-syntax
  (R : REL A B ℓ₁)
  (step : Trans _≡_ R R)
  where

  infixr 2 step-≡-⟩  step-≡-∣ step-≡-⟨
  step-≡-⟩ = forward R R step

  step-≡-∣ :  x {y}  R x y  R x y
  step-≡-∣ x xRy = xRy

  step-≡-⟨ = backward R R step P.sym

  syntax step-≡-⟩ x yRz x≡y = x ≡⟨ x≡y  yRz
  syntax step-≡-∣ x xRy     = x ≡⟨⟩ xRy
  syntax step-≡-⟨ x yRz y≡x = x ≡⟨ y≡x  yRz


  -- Don't remove until https://github.com/agda/agda/issues/5617 fixed.
  infixr 2 step-≡ step-≡˘
  step-≡ = step-≡-⟩
  {-# WARNING_ON_USAGE step-≡
  "Warning: step-≡ was deprecated in v2.0.
  Please use step-≡-⟩ instead."
  #-}
  step-≡˘ = step-≡-⟨
  {-# WARNING_ON_USAGE step-≡˘
  "Warning: step-≡˘ and _≡˘⟨_⟩_ was deprecated in v2.0.
  Please use step-≡-⟨ and _≡⟨_⟨_ instead."
  #-}
  syntax step-≡˘ x yRz y≡x = x ≡˘⟨ y≡x  yRz


-- Unlike ≡-syntax above, chains of reasoning using this syntax will not
-- reduce when proofs of propositional equality which are not definitionally
-- equal to `refl` are passed.
module ≡-noncomputing-syntax (R : REL A B ℓ₁) where

  private
    step : Trans _≡_ R R
    step P.refl xRy = xRy

  open ≡-syntax R step public

------------------------------------------------------------------------
-- Syntax for ending a chain of reasoning
------------------------------------------------------------------------

module end-syntax
  (R : Rel A ℓ₁)
  (reflexive : Reflexive R)
  where

  infix 3 _∎

  _∎ :  x  R x x
  x  = reflexive