------------------------------------------------------------------------
-- The syntax of, and a type system for, an untyped λ-calculus with
-- booleans and recursive unary function calls
------------------------------------------------------------------------

open import Prelude

module Lambda.Syntax (Name : Type) where

open import Equality.Propositional
open import Prelude.Size

open import Vec.Data equality-with-J

------------------------------------------------------------------------
-- Terms

-- Variables are represented using de Bruijn indices.

infixl 9 _·_

data Tm (n : ℕ) : Type where
  var  : Fin n → Tm n
  lam  : Tm (suc n) → Tm n
  _·_  : Tm n → Tm n → Tm n
  call : Name → Tm n → Tm n
  con  : Bool → Tm n
  if   : Tm n → Tm n → Tm n → Tm n

------------------------------------------------------------------------
-- Closure-based definition of values

-- Environments and values. Defined in a module parametrised by the
-- type of terms.

module Closure (Tm : ℕ → Type) where

  mutual

    -- Environments.

    Env : ℕ → Type
    Env n = Vec Value n

    -- Values. Lambdas are represented using closures, so values do
    -- not contain any free variables.

    data Value : Type where
      lam : ∀ {n} → Tm (suc n) → Env n → Value
      con : Bool → Value

------------------------------------------------------------------------
-- Type system

-- Recursive, simple types, defined coinductively.

infixr 8 _⇾_ _⇾′_

mutual

  data Ty (i : Size) : Type where
    bool : Ty i
    _⇾′_ : (σ τ : Ty′ i) → Ty i

  record Ty′ (i : Size) : Type where
    coinductive
    field
      force : {j : Size< i} → Ty j

open Ty′ public

-- Some type formers.

_⇾_ : ∀ {i} → Ty i → Ty i → Ty i
σ ⇾ τ = (λ { .force → σ }) ⇾′ (λ { .force → τ })

-- Contexts.

Ctxt : ℕ → Type
Ctxt n = Vec (Ty ∞) n

-- Type system.

infix 4 _,_⊢_∈_

data _,_⊢_∈_ (Σ : Name → Ty ∞ × Ty ∞) {n} (Γ : Ctxt n) :
             Tm n → Ty ∞ → Type where
  var  : ∀ {x} → Σ , Γ ⊢ var x ∈ index Γ x
  lam  : ∀ {t σ τ} →
         Σ , force σ ∷ Γ ⊢ t ∈ force τ →
         Σ , Γ ⊢ lam t ∈ σ ⇾′ τ
  _·_  : ∀ {t₁ t₂ σ τ} →
         Σ , Γ ⊢ t₁ ∈ σ ⇾′ τ →
         Σ , Γ ⊢ t₂ ∈ force σ →
         Σ , Γ ⊢ t₁ · t₂ ∈ force τ
  call : ∀ {f t} →
         Σ , Γ ⊢ t ∈ proj₁ (Σ f) →
         Σ , Γ ⊢ call f t ∈ proj₂ (Σ f)
  con  : ∀ {b} → Σ , Γ ⊢ con b ∈ bool
  if   : ∀ {t₁ t₂ t₃ σ} →
         Σ , Γ ⊢ t₁ ∈ bool →
         Σ , Γ ⊢ t₂ ∈ σ →
         Σ , Γ ⊢ t₃ ∈ σ →
         Σ , Γ ⊢ if t₁ t₂ t₃ ∈ σ

------------------------------------------------------------------------
-- Examples

-- A non-terminating term.

ω-body : Tm 1
ω-body = var fzero · var fzero

ω : Tm 0
ω = lam ω-body

Ω : Tm 0
Ω = ω · ω

-- Ω is well-typed.

Ω-well-typed : ∀ {Σ} (τ : Ty ∞) → Σ , [] ⊢ Ω ∈ τ
Ω-well-typed τ =
  _·_ {σ = σ} {τ = λ { .force → τ }} (lam (var · var)) (lam (var · var))
  where
  σ : ∀ {i} → Ty′ i
  force σ = σ ⇾′ λ { .force → τ }

-- A call-by-value fixpoint combinator.

Z : Tm 0
Z = lam (t · t)
  where
  t = lam (var (fsuc fzero) ·
         lam (var (fsuc fzero) · var (fsuc fzero) · var fzero))

-- This combinator is also well-typed.

Z-well-typed :
  ∀ {Σ} {σ τ : Ty ∞} →
  Σ , [] ⊢ Z ∈ ((σ ⇾ τ) ⇾ (σ ⇾ τ)) ⇾ (σ ⇾ τ)
Z-well-typed {σ = σ} {τ = τ} =
  lam (_·_ {σ = υ} {τ = λ { .force → σ ⇾ τ }}
           (lam (var · lam (var · var · var)))
           (lam (var · lam (var · var · var))))
  where
  υ : ∀ {i} → Ty′ i
  force υ = υ ⇾′ λ { .force → σ ⇾ τ }


------------------------------------------------------------------------------
-- The division result is correct
------------------------------------------------------------------------------

{-# OPTIONS --exact-split              #-}
{-# OPTIONS --no-sized-types           #-}
{-# OPTIONS --no-universe-polymorphism #-}
{-# OPTIONS --without-K                #-}

module FOTC.Program.Division.ResultATP where

open import FOTC.Base
open import FOTC.Data.Nat
open import FOTC.Data.Nat.Inequalities
open import FOTC.Data.Nat.PropertiesATP
open import FOTC.Program.Division.Division
open import FOTC.Program.Division.Specification

------------------------------------------------------------------------------
-- The division result is correct when the dividend is less than
-- the divisor.

postulate div-x<y-helper : ∀ {i j} → N i → N j → i < j → i ≡ j * div i j + i
{-# ATP prove div-x<y-helper *-rightZero #-}

div-x<y-resultCorrect : ∀ {i j} → N i → N j → i < j →
                        ∃[ r ] N r ∧ r < j ∧ i ≡ j * div i j + r
div-x<y-resultCorrect Ni Nj i<j = _ , Ni , i<j , div-x<y-helper Ni Nj i<j

-- The division result is correct when the dividend is greater or equal
-- than the divisor.
-- Using the inductive hypothesis ih we know that
--
-- i ∸ j = j * (div (i ∸ j) j) + r.

-- From that we get
--
-- i = j * (succ (div (i ∸ j) j)) + r and we know
--
-- div i j = succ (div (i ∸ j) j) therefore we get
--
-- i = j * div i j + r.
postulate helper : ∀ {i j r} → N i → N j → N r →
                   i ∸ j ≡ j * div (i ∸ j) j + r →
                   i ≡ j * succ₁ (div (i ∸ j) j) + r

postulate div-x≮y-helper : ∀ {i j r} → N i → N j → N r →
                           i ≮ j →
                           i ∸ j ≡ j * div (i ∸ j) j + r →
                           i ≡ j * div i j + r
{-# ATP prove div-x≮y-helper helper #-}

postulate div-x≮y-resultCorrect : ∀ {i j} → N i → N j →
                                  (ih : divSpec (i ∸ j) j (div (i ∸ j) j)) →
                                  i ≮ j →
                                  ∃[ r ] N r ∧ r < j ∧ i ≡ j * div i j + r
{-# ATP prove div-x≮y-resultCorrect div-x≮y-helper #-}


module Base.Change.Sums where

open import Data.Sum
open import Data.Product
open import Relation.Binary.PropositionalEquality
open import Level

open import Base.Ascription
open import Base.Change.Algebra
open import Base.Change.Equivalence
open import Base.Change.Equivalence.Realizers
open import Postulate.Extensionality

module SumChanges ℓ {X Y : Set ℓ} {{CX : ChangeAlgebra X}} {{CY : ChangeAlgebra Y}} where
  open ≡-Reasoning

  -- This is an indexed datatype, so it has two constructors per argument. But
  -- erasure would probably not be smart enough to notice.

  -- Should we rewrite this as two separate datatypes?
  data SumChange : X ⊎ Y → Set ℓ where
    ch₁ : ∀ {x} → (dx : Δ x) → SumChange (inj₁ x)
    rp₁₂ : ∀ {x} → (y : Y) → SumChange (inj₁ x)
    ch₂ : ∀ {y} → (dy : Δ y) → SumChange (inj₂ y)
    rp₂₁ : ∀ {y} → (x : X) → SumChange (inj₂ y)

  _⊕_ : (v : X ⊎ Y) → SumChange v → X ⊎ Y
  inj₁ x ⊕ ch₁ dx = inj₁ (x ⊞ dx)
  inj₂ y ⊕ ch₂ dy = inj₂ (y ⊞ dy)
  inj₁ x ⊕ rp₁₂ y = inj₂ y
  inj₂ y ⊕ rp₂₁ x = inj₁ x

  _⊝_ : ∀ (v₂ v₁ : X ⊎ Y) → SumChange v₁
  inj₁ x₂ ⊝ inj₁ x₁ = ch₁ (x₂ ⊟ x₁)
  inj₂ y₂ ⊝ inj₂ y₁ = ch₂ (y₂ ⊟ y₁)
  inj₂ y₂ ⊝ inj₁ x₁ = rp₁₂ y₂
  inj₁ x₂ ⊝ inj₂ y₁ = rp₂₁ x₂

  s-nil : (v : X ⊎ Y) → SumChange v
  s-nil (inj₁ x) = ch₁ (nil x)
  s-nil (inj₂ y) = ch₂ (nil y)

  s-update-diff : ∀ (u v : X ⊎ Y) → v ⊕ (u ⊝ v) ≡ u
  s-update-diff (inj₁ x₂) (inj₁ x₁) = cong inj₁ (update-diff x₂ x₁)
  s-update-diff (inj₂ y₂) (inj₂ y₁) = cong inj₂ (update-diff y₂ y₁)
  s-update-diff (inj₁ x₂) (inj₂ y₁) = refl
  s-update-diff (inj₂ y₂) (inj₁ x₁) = refl

  s-update-nil : ∀ v → v ⊕ (s-nil v) ≡ v
  s-update-nil (inj₁ x) = cong inj₁ (update-nil x)
  s-update-nil (inj₂ y) = cong inj₂ (update-nil y)

  instance
    changeAlgebraSums : ChangeAlgebra (X ⊎ Y)
    changeAlgebraSums = record
      { Change = SumChange
      ; update = _⊕_
      ; diff = _⊝_
      ; nil = s-nil
      ; isChangeAlgebra = record
        { update-diff = s-update-diff
        ; update-nil = s-update-nil
        }
      }

  inj₁′ : Δ (inj₁ as (X → (X ⊎ Y)))
  inj₁′ = nil inj₁

  inj₁′-realizer : RawChange (inj₁ as (X → (X ⊎ Y)))
  inj₁′-realizer x dx = ch₁ dx

  inj₁′Derivative : IsDerivative (inj₁ as (X → (X ⊎ Y))) inj₁′-realizer
  inj₁′Derivative x dx = refl

  inj₁′-realizer-correct : ∀ a da → apply inj₁′ a da ≙₍ inj₁ a as (X ⊎ Y) ₎ inj₁′-realizer a da
  inj₁′-realizer-correct a da = diff-update

  inj₁′-faster-w-proof : equiv-raw-change-to-change-ResType inj₁ inj₁′-realizer
  inj₁′-faster-w-proof = equiv-raw-change-to-change inj₁ inj₁′ inj₁′-realizer inj₁′-realizer-correct
  inj₁′-faster : Δ inj₁
  inj₁′-faster = proj₁ inj₁′-faster-w-proof

  inj₂′ : Δ (inj₂ as (Y → (X ⊎ Y)))
  inj₂′ = nil inj₂

  inj₂′-realizer : RawChange (inj₂ as (Y → (X ⊎ Y)))
  inj₂′-realizer y dy = ch₂ dy

  inj₂′Derivative : IsDerivative (inj₂ as (Y → (X ⊎ Y))) inj₂′-realizer
  inj₂′Derivative y dy = refl

  inj₂′-realizer-correct : ∀ b db → apply inj₂′ b db ≙₍ inj₂ b as (X ⊎ Y) ₎ inj₂′-realizer b db
  inj₂′-realizer-correct b db = diff-update

  inj₂′-faster-w-proof : equiv-raw-change-to-change-ResType inj₂ inj₂′-realizer
  inj₂′-faster-w-proof = equiv-raw-change-to-change inj₂ inj₂′ inj₂′-realizer inj₂′-realizer-correct
  inj₂′-faster : Δ inj₂
  inj₂′-faster = proj₁ inj₂′-faster-w-proof

  module _ {Z : Set ℓ} {{CZ : ChangeAlgebra Z}} where
    -- Elimination form for sums. This is a less dependently-typed version of
    -- [_,_].
    match : (X → Z) → (Y → Z) → X ⊎ Y → Z
    match f g (inj₁ x) = f x
    match f g (inj₂ y) = g y

    match′ : Δ match
    match′ = nil match

    match′-realizer : (f : X → Z) → Δ f → (g : Y → Z) → Δ g → (s : X ⊎ Y) → Δ s → Δ (match f g s)
    match′-realizer f df g dg (inj₁ x) (ch₁ dx) = apply df x dx
    match′-realizer f df g dg (inj₁ x) (rp₁₂ y) = ((g ⊞ dg) y) ⊟ (f x)
    match′-realizer f df g dg (inj₂ y) (rp₂₁ x) = ((f ⊞ df) x) ⊟ (g y)
    match′-realizer f df g dg (inj₂ y) (ch₂ dy) = apply dg y dy

    match′-realizer-correct :
      (f : X → Z) → (df : Δ f) → (g : Y → Z) → (dg : Δ g) → (s : X ⊎ Y) → (ds : Δ s) →
      apply (apply (apply match′ f df) g dg) s ds ≙₍ match f g s ₎ match′-realizer f df g dg s ds
    match′-realizer-correct f df g dg (inj₁ x) (ch₁ dx) = ≙-incrementalization f df x dx
    match′-realizer-correct f df g dg (inj₁ x) (rp₁₂ y) = ≙-refl
    match′-realizer-correct f df g dg (inj₂ y) (ch₂ dy) = ≙-incrementalization g dg y dy
    match′-realizer-correct f df g dg (inj₂ y) (rp₂₁ x) = ≙-refl

    -- We need a ternary variant of the lemma here.
    match′-faster-w-proof : equiv-raw-change-to-change-ternary-ResType match match′-realizer
    match′-faster-w-proof = equiv-raw-change-to-change-ternary match match′ match′-realizer match′-realizer-correct

    match′-faster : Δ match
    match′-faster = proj₁ match′-faster-w-proof


module Data.Real.Order where

open import Assume
open import Data.Real.Base
open import Data.Bool using (T; T?)
open import Data.Unit using (⊤; tt)
open import Relation.Nullary using (Dec; yes; no; ¬_)
open import Relation.Binary.PropositionalEquality using (_≡_)
open import Relation.Binary

open import Level using (0ℓ)

-- TODO
-- should this move to Data.Real.Equality?
_≉_ : Rel ℝ 0ℓ
x ≉ y = ¬ x ≈ y

≉-isApartnessRelation : IsApartnessRelation _≈_ _≉_
≉-isApartnessRelation = assume

≉-apartnessRelation : ApartnessRelation 0ℓ 0ℓ 0ℓ
≉-apartnessRelation = record { isApartnessRelation = ≉-isApartnessRelation }

_≤_ : ℝ → ℝ → Set
x ≤ y = T (x ≤ᵇ y)

open import Relation.Binary.Construct.NonStrictToStrict _≈_ _≤_ public
  using (_<_; <-isStrictTotalOrder₁)

_≤?_ : ∀ x y → Dec (x ≤ y)
x ≤? y = T? (x ≤ᵇ y)

≤-isTotalOrder : IsTotalOrder _≈_ _≤_
≤-isTotalOrder = assume

≤-isDecTotalOrder : IsDecTotalOrder _≈_ _≤_
≤-isDecTotalOrder = record { isTotalOrder = ≤-isTotalOrder ; _≟_ = _≈?_ ; _≤?_ = _≤?_ }

≤-decTotalOrder : DecTotalOrder 0ℓ 0ℓ 0ℓ
≤-decTotalOrder = record { isDecTotalOrder = ≤-isDecTotalOrder }

<-isStrictTotalOrder : IsStrictTotalOrder _≈_ _<_
<-isStrictTotalOrder = <-isStrictTotalOrder₁ _≈?_ ≤-isTotalOrder

abs : ℝ → ℝ
abs x = if does (0.0 ≤? x) then x else - x
  where
    open import Data.Bool using (if_then_else_)
    open import Relation.Nullary using (does)


module Structure.Container.SetLike where
{-
open import Data.Boolean
open import Data.Boolean.Stmt
open import Functional
open import Lang.Instance
import      Lvl
open import Logic
open import Logic.Propositional
open import Logic.Predicate
open import Structure.Setoid renaming (_≡_ to _≡ₛ_ ; _≢_ to _≢ₛ_)
open import Structure.Function.Domain
open import Structure.Function
open import Structure.Operator
open import Structure.Relator.Equivalence
open import Structure.Relator.Properties
open import Structure.Relator hiding (module Names)
open import Type.Properties.Inhabited
open import Type

private variable ℓ ℓ₁ ℓ₂ ℓ₃ ℓ₄ ℓ₅ ℓ₆ ℓ₇ ℓ₈ ℓ₉ ℓ₁₀ ℓₗ ℓₗ₁ ℓₗ₂ ℓₗ₃ : Lvl.Level
private variable A B C C₁ C₂ Cₒ Cᵢ E E₁ E₂ : Type{ℓ}
private variable _∈_ _∈ₒ_ _∈ᵢ_ : E → C

module _ {C : Type{ℓ₁}} {E : Type{ℓ₂}} (_∈_ : E → C → Stmt{ℓ₃}) where -- TODO: Maybe generalize C so that it becomes "indexed": `(C : (i : I) → Type{ℓ₁(i)})`? Is it neccessary? Which set-like structures does not fit with the definitions below?
  record SetLike {ℓ₄} : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ Lvl.𝐒(ℓ₄)} where
    field
      _≡_ : C → C → Stmt{ℓ₄}

    field
      [≡]-membership : ∀{a b} → (a ≡ b) ↔ (∀{x} → (x ∈ a) ↔ (x ∈ b))

    _∋_ : C → E → Stmt
    _∋_ = swap(_∈_)

    _∉_ : E → C → Stmt
    _∉_ = (¬_) ∘₂ (_∈_)

    _≢_ : C → C → Stmt
    _≢_ = (¬_) ∘₂ (_≡_)

  -- A type such that its inhabitants is the elements of the set `S`.
  SetElement : C → Stmt
  SetElement(S) = ∃(_∈ S)

  record SubsetRelation {ℓ₄} : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ Lvl.𝐒(ℓ₄)} where
    field _⊆_ : C → C → Stmt{ℓ₄}
    Membership = ∀{a b} → (a ⊆ b) ↔ (∀{x} → (x ∈ a) → (x ∈ b))
    field [⊆]-membership : Membership

    _⊇_ : C → C → Stmt
    _⊇_ = swap(_⊆_)

    _⊈_ : C → C → Stmt
    _⊈_ = (¬_) ∘₂ (_⊆_)

    _⊉_ : C → C → Stmt
    _⊉_ = (¬_) ∘₂ (_⊇_)
  open SubsetRelation ⦃ ... ⦄ hiding (Membership ; membership) public
  module Subset ⦃ inst ⦄ = SubsetRelation(inst)

  module FunctionProperties where
    module Names where
      _closed-under₁_ : C → (E → E) → Stmt -- TODO: Maybe possible to generalize over n
      S closed-under₁ f = (∀{x} → (x ∈ S) → (f(x) ∈ S))

      _closed-under₂_ : C → (E → E → E) → Stmt
      S closed-under₂ (_▫_) = (∀{x y} → (x ∈ S) → (y ∈ S) → ((x ▫ y) ∈ S))

    open import Lang.Instance
    module _ (S : C) (f : E → E) where
      record _closed-under₁_ : Stmt{Lvl.of(S Names.closed-under₁ f)} where
        constructor intro
        field proof : S Names.closed-under₁ f
      _closureUnder₁_ = inst-fn _closed-under₁_.proof

    module _ (S : C) (_▫_ : E → E → E) where
      record _closed-under₂_ : Stmt{Lvl.of(S Names.closed-under₂ (_▫_))} where
        constructor intro
        field proof : S Names.closed-under₂ (_▫_)
      _closureUnder₂_ = inst-fn _closed-under₂_.proof

module _ (_∈_ : _) ⦃ setLike : SetLike{ℓ₁}{ℓ₂}{ℓ₃}{C}{E} (_∈_) {ℓ₄} ⦄ where
  open SetLike(setLike)

  module Names where

  record EmptySet : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field ∅ : C
    Membership = ∀{x} → (x ∉ ∅)
    field membership : Membership
  open EmptySet ⦃ ... ⦄ hiding (Membership ; membership) public
  module Empty ⦃ inst ⦄ = EmptySet(inst)
  {-# DISPLAY EmptySet.∅ = ∅ #-}

  record UniversalSet : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field 𝐔 : C
    Membership = ∀{x} → (x ∈ 𝐔)
    field membership : Membership
  open UniversalSet ⦃ ... ⦄ hiding (Membership ; membership) public
  module Universal ⦃ inst ⦄ = UniversalSet(inst)

  record UnionOperator : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field _∪_ : C → C → C
    Membership = ∀{a b}{x} → (x ∈ (a ∪ b)) ↔ ((x ∈ a) ∨ (x ∈ b))
    field membership : Membership
  open UnionOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module Union ⦃ inst ⦄ = UnionOperator(inst)

  record IntersectionOperator : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field _∩_ : C → C → C
    Membership = ∀{a b}{x} → (x ∈ (a ∩ b)) ↔ ((x ∈ a) ∧ (x ∈ b))
    field membership : Membership
  open IntersectionOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module Intersection ⦃ inst ⦄ = IntersectionOperator(inst)
  {-# DISPLAY IntersectionOperator._∩_ = _∩_ #-}

  record WithoutOperator : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field _∖_ : C → C → C
    Membership = ∀{a b}{x} → (x ∈ (a ∖ b)) ↔ ((x ∈ a) ∧ (x ∉ b))
    field membership : Membership
  open WithoutOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module Without ⦃ inst ⦄ = WithoutOperator(inst)

  record ComplementOperator : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field ∁ : C → C
    Membership = ∀{a}{x} → (x ∈ (∁ a)) ↔ (x ∉ a)
    field membership : Membership
  open ComplementOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module Complement ⦃ inst ⦄ = ComplementOperator(inst)

  module _ {I : Type{ℓ}} ⦃ equiv-I : Equiv{ℓₗ₁}(I) ⦄ ⦃ equiv-E : Equiv{ℓₗ₂}(E) ⦄ where
    record ImageOperator : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓ Lvl.⊔ ℓₗ₁ Lvl.⊔ ℓₗ₂} where
      field ⊶ : (f : I → E) → ⦃ func : Function(f) ⦄ → C
      Membership = ∀{f} ⦃ func : Function(f) ⦄ → ∀{y} → (y ∈ (⊶ f)) ↔ ∃(x ↦ f(x) ≡ₛ y)
      field membership : Membership
    open ImageOperator ⦃ ... ⦄ hiding (Membership ; membership) public
    module Image ⦃ inst ⦄ = ImageOperator(inst)

  module _ ⦃ _ : Equiv{ℓₗ}(E) ⦄ where
    record SingletonSet : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓₗ} where
      field singleton : E → C
      Membership = ∀{y}{x} → (x ∈ singleton(y)) ↔ (x ≡ₛ y)
      field membership : Membership
    open SingletonSet ⦃ ... ⦄ hiding (Membership ; membership) public
    module Singleton ⦃ inst ⦄ = SingletonSet(inst)

    record PairSet : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓₗ} where
      field pair : E → E → C
      Membership = ∀{y₁ y₂}{x} → (x ∈ pair y₁ y₂) ↔ (x ≡ₛ y₁)∨(x ≡ₛ y₂)
      field membership : Membership
    open PairSet ⦃ ... ⦄ hiding (Membership ; membership) public
    module Pair ⦃ inst ⦄ = PairSet(inst)

    record AddFunction : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓₗ} where
      field add : E → C → C
      Membership = ∀{y}{a}{x} → (x ∈ add y a) ↔ ((x ∈ a) ∨ (x ≡ₛ y))
      field membership : Membership
    open AddFunction ⦃ ... ⦄ hiding (Membership ; membership) public
    module Add ⦃ inst ⦄ = AddFunction(inst)

    record RemoveFunction : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓₗ} where
      field remove : E → C → C
      Membership = ∀{y}{a}{x} → (x ∈ remove y a) ↔ ((x ∈ a) ∧ (x ≢ₛ y))
      field membership : Membership
    open RemoveFunction ⦃ ... ⦄ hiding (Membership ; membership) public
    module Remove ⦃ inst ⦄ = RemoveFunction(inst)

    module _ {ℓ} where
      record FilterFunction : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ Lvl.𝐒(ℓ) Lvl.⊔ ℓₗ} where
        field filter : (P : E → Stmt{ℓ}) ⦃ unaryRelator : UnaryRelator(P) ⦄ → (C → C)
        Membership = ∀{A}{P} ⦃ unaryRelator : UnaryRelator(P) ⦄ {x} → (x ∈ filter P(A)) ↔ ((x ∈ A) ∧ P(x))
        field membership : Membership
      open FilterFunction ⦃ ... ⦄ hiding (Membership ; membership) public
      module Filter ⦃ inst ⦄ = FilterFunction(inst)

  record BooleanFilterFunction : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field boolFilter : (E → Bool) → (C → C)
    Membership = ∀{A}{P}{x} → (x ∈ boolFilter P(A)) ↔ ((x ∈ A) ∧ IsTrue(P(x)))
    field membership : Membership
  open BooleanFilterFunction ⦃ ... ⦄ hiding (Membership ; membership) public
  module BooleanFilter ⦃ inst ⦄ = BooleanFilterFunction(inst)

module _ (_∈_ : _) ⦃ setLike : SetLike{ℓ₁}{ℓ₂}{ℓ₃}{C}{E} (_∈_) {ℓ₄} ⦄ ⦃ equiv-E : Equiv{ℓₗ₁}(E) ⦄ {O : Type{ℓ₆}} ⦃ equiv-O : Equiv{ℓₗ₂}(O) ⦄ where
  record UnapplyFunction : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓ₆ Lvl.⊔ ℓₗ₁ Lvl.⊔ ℓₗ₂} where
    field unapply : (f : E → O) ⦃ func : Function(f) ⦄ → O → C
    Membership = ∀{f} ⦃ func : Function(f) ⦄ {y}{x} → (x ∈ unapply f(y)) ↔ (f(x) ≡ₛ y)
    field membership : Membership
  open UnapplyFunction ⦃ ... ⦄ hiding (Membership ; membership) public
  module Unapply ⦃ inst ⦄ = UnapplyFunction(inst)

module _
  ⦃ equiv-E₁ : Equiv{ℓₗ₁}(E₁) ⦄
  (_∈₁_ : _) ⦃ setLike₁ : SetLike{ℓ₁}{ℓ₂}{ℓ₃}{C₁}{E₁} (_∈₁_) {ℓ₄} ⦄
  ⦃ equiv-E₂ : Equiv{ℓₗ₂}(E₂) ⦄
  (_∈₂_ : _) ⦃ setLike₂ : SetLike{ℓ₆}{ℓ₇}{ℓ₈}{C₂}{E₂} (_∈₂_) {ℓ₉} ⦄
  where

  open SetLike ⦃ … ⦄
  record MapFunction : Type{ℓₗ₁ Lvl.⊔ ℓₗ₂ Lvl.⊔ ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓ₆ Lvl.⊔ ℓ₇ Lvl.⊔ ℓ₈} where
    field map : (f : E₁ → E₂) ⦃ func : Function(f) ⦄ → (C₁ → C₂)
    Membership = ∀{f} ⦃ func : Function(f) ⦄ {A}{y} → (y ∈₂ map f(A)) ↔ ∃(x ↦ (x ∈₁ A) ∧ (f(x) ≡ₛ y))
    field membership : Membership
  open MapFunction ⦃ ... ⦄ hiding (Membership ; membership) public
  module Map ⦃ inst ⦄ = MapFunction(inst)

  record UnmapFunction : Type{ℓₗ₁ Lvl.⊔ ℓₗ₂ Lvl.⊔ ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓ₆ Lvl.⊔ ℓ₇ Lvl.⊔ ℓ₈} where
    field unmap : (f : E₁ → E₂) ⦃ func : Function(f) ⦄ → (C₂ → C₁)
    Membership = ∀{f} ⦃ func : Function(f) ⦄ {A}{x} → (x ∈₁ unmap f(A)) ↔ (f(x) ∈₂ A)
    field membership : Membership
  open UnmapFunction ⦃ ... ⦄ hiding (Membership ; membership) public
  module Unmap ⦃ inst ⦄ = UnmapFunction(inst)

module _ (_∈ₒ_ : _) ⦃ outer-setLike : SetLike{ℓ₁}{ℓ₂}{ℓ₃}{Cₒ}{Cᵢ} (_∈ₒ_) {ℓ₄} ⦄ (_∈ᵢ_ : _) ⦃ inner-setLike : SetLike{ℓ₂}{ℓ₆}{ℓ₇}{Cᵢ}{E} (_∈ᵢ_) {ℓ₈} ⦄ where
  open SetLike ⦃ … ⦄

  record PowerFunction ⦃ subset : SubsetRelation(_∈ᵢ_){ℓ₄ = ℓ₉} ⦄ : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓ₈} where
    field ℘ : Cᵢ → Cₒ
    Membership = ∀{A x} → (x ∈ₒ ℘(A)) ↔ (x ⊆ A)
    field membership : Membership
  open PowerFunction ⦃ ... ⦄ hiding (Membership ; membership) public
  module Power ⦃ inst ⦄ = PowerFunction(inst)

  record BigUnionOperator : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓ₆ Lvl.⊔ ℓ₇} where
    field ⋃ : Cₒ → Cᵢ
    Membership = ∀{A}{x} → (x ∈ᵢ (⋃ A)) ↔ ∃(a ↦ (a ∈ₒ A) ∧ (x ∈ᵢ a))
    field membership : Membership
  open BigUnionOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module BigUnion ⦃ inst ⦄ = BigUnionOperator(inst)

  record BigIntersectionOperator : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃ Lvl.⊔ ℓ₆ Lvl.⊔ ℓ₇} where
    field ⋂ : Cₒ → Cᵢ
    Membership = ∀{A} → ∃(_∈ₒ A) → ∀{x} → (x ∈ᵢ (⋂ A)) ↔ (∀{a} → (a ∈ₒ A) → (x ∈ᵢ a))
    field membership : Membership
  open BigIntersectionOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module BigIntersection ⦃ inst ⦄ = BigIntersectionOperator(inst)

module _ {I : Type{ℓ}} ⦃ equiv-I : Equiv{ℓₗ₁}(I) ⦄ ⦃ equiv-E : Equiv{ℓₗ₂}(E) ⦄ (_∈_ : _) ⦃ setLike : SetLike{ℓ₁}{ℓ₂}{ℓ₃}{C}{E} (_∈_) {ℓ₄}{ℓ₅} ⦄ where
  record IndexedBigUnionOperator : Type{ℓ Lvl.⊔ ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field ⋃ᵢ : (I → C) → C
    Membership = ∀{Ai}{x} → (x ∈ (⋃ᵢ Ai)) ↔ ∃(i ↦ (x ∈ Ai(i)))
    field membership : Membership
  open IndexedBigUnionOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module IndexedBigUnion ⦃ inst ⦄ = IndexedBigUnionOperator(inst)

  record IndexedBigIntersectionOperator : Type{ℓ Lvl.⊔ ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓ₃} where
    field ⋂ᵢ : (I → C) → C
    Membership = ∀{Ai} → ◊(I) → ∀{x} → (x ∈ (⋂ᵢ Ai)) ↔ (∀{i} → (x ∈ Ai(i)))
    field membership : Membership
  open IndexedBigIntersectionOperator ⦃ ... ⦄ hiding (Membership ; membership) public
  module IndexedBigIntersection ⦃ inst ⦄ = IndexedBigIntersectionOperator(inst)

{-
open SetLike ⦃ … ⦄
  using (
    _∈_ ; _⊆_ ; _≡_ ;
    _∋_ ; _⊇_ ;
    _∉_ ; _⊈_ ; _⊉_ ; _≢_ ;
    ∅ ; _∪_ ; _∩_ ; _∖_ ;
    singleton ; add ; remove
  )
-}
-}


module LateMetaVariableInstantiation where

data ℕ : Set where
  zero : ℕ
  suc  : (n : ℕ) → ℕ

{-# BUILTIN NATURAL ℕ    #-}

postulate
  yippie : (A : Set) → A

slow : (A : Set) → ℕ → A
slow A zero    = yippie A
slow A (suc n) = slow _ n

data _≡_ {A : Set} (x : A) : A → Set where
  refl : x ≡ x

foo : slow ℕ 1000 ≡ yippie ℕ
foo = refl

-- Consider the function slow. Previously normalisation of slow n
-- seemed to take time proportional to n². The reason was that, even
-- though the meta-variable corresponding to the underscore was
-- solved, the stored code still contained a meta-variable:

--   slow A (suc n) = slow (_173 A n) n

-- (For some value of 173.) The evaluation proceeded as follows:

--   slow A 1000 =
--   slow (_173 A 999) 999 =
--   slow (_173 (_173 A 999) 998) 998 =
--   ...

-- Furthermore, in every iteration the Set argument was traversed, to
-- see if there was any de Bruijn index to raise.


-- Define the integers as a HIT by identifying +0 and -0
{-# OPTIONS --cubical --safe #-}
module Cubical.HITs.Ints.QuoInt.Base where

open import Cubical.Core.Everything

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Transport
open import Cubical.Foundations.Isomorphism

open import Cubical.Data.Int hiding (abs; sgn)
open import Cubical.Data.Nat

data ℤ : Type₀ where
  pos    : (n : ℕ) → ℤ
  neg    : (n : ℕ) → ℤ
  posneg : pos 0 ≡ neg 0

recℤ : ∀ {l} {A : Type l} → (pos' neg' : ℕ → A) → pos' 0 ≡ neg' 0 → ℤ → A
recℤ pos' neg' eq (pos m)    = pos' m
recℤ pos' neg' eq (neg m)    = neg' m
recℤ pos' neg' eq (posneg i) = eq i

indℤ : ∀ {l} (P : ℤ → Type l)
       → (pos' : ∀ n → P (pos n))
       → (neg' : ∀ n → P (neg n))
       → (λ i → P (posneg i)) [ pos' 0 ≡ neg' 0 ]
       → ∀ z → P z
indℤ P pos' neg' eq (pos n) = pos' n
indℤ P pos' neg' eq (neg n) = neg' n
indℤ P pos' neg' eq (posneg i) = eq i

Int→ℤ : Int → ℤ
Int→ℤ (pos n) = pos n
Int→ℤ (negsuc n) = neg (suc n)

ℤ→Int : ℤ → Int
ℤ→Int (pos n) = pos n
ℤ→Int (neg zero) = pos 0
ℤ→Int (neg (suc n)) = negsuc n
ℤ→Int (posneg _) = pos 0

ℤ→Int→ℤ : ∀ (n : ℤ) → Int→ℤ (ℤ→Int n) ≡ n
ℤ→Int→ℤ (pos n) _       = pos n
ℤ→Int→ℤ (neg zero) i    = posneg i
ℤ→Int→ℤ (neg (suc n)) _ = neg (suc n)
ℤ→Int→ℤ (posneg j) i    = posneg (j ∧ i)

Int→ℤ→Int : ∀ (n : Int) → ℤ→Int (Int→ℤ n) ≡ n
Int→ℤ→Int (pos n) _ = pos n
Int→ℤ→Int (negsuc n) _ = negsuc n

Int≡ℤ : Int ≡ ℤ
Int≡ℤ = isoToPath (iso Int→ℤ ℤ→Int ℤ→Int→ℤ Int→ℤ→Int)

isSetℤ : isSet ℤ
isSetℤ = subst isSet Int≡ℤ isSetInt

sucℤ : ℤ → ℤ
sucℤ (pos n)       = pos (suc n)
sucℤ (neg zero)    = pos 1
sucℤ (neg (suc n)) = neg n
sucℤ (posneg _)    = pos 1

predℤ : ℤ → ℤ
predℤ (pos zero)    = neg 1
predℤ (pos (suc n)) = pos n
predℤ (neg n)       = neg (suc n)
predℤ (posneg _)    = neg 1

sucPredℤ : ∀ n → sucℤ (predℤ n) ≡ n
sucPredℤ (pos zero)    = sym posneg
sucPredℤ (pos (suc _)) = refl
sucPredℤ (neg _)       = refl
sucPredℤ (posneg i) j  = posneg (i ∨ ~ j)

predSucℤ : ∀ n → predℤ (sucℤ n) ≡ n
predSucℤ (pos _)       = refl
predSucℤ (neg zero)    = posneg
predSucℤ (neg (suc _)) = refl
predSucℤ (posneg i) j  = posneg (i ∧ j)

_+ℤ_ : ℤ → ℤ → ℤ
m +ℤ (pos (suc n)) = sucℤ   (m +ℤ pos n)
m +ℤ (neg (suc n)) = predℤ  (m +ℤ neg n)
m +ℤ _             = m

sucPathℤ : ℤ ≡ ℤ
sucPathℤ  = isoToPath (iso sucℤ predℤ sucPredℤ predSucℤ)

-- We do the same trick as in Cubical.Data.Int to prove that addition
-- is an equivalence
addEqℤ : ℕ → ℤ ≡ ℤ
addEqℤ zero    = refl
addEqℤ (suc n) = addEqℤ n ∙ sucPathℤ

predPathℤ : ℤ ≡ ℤ
predPathℤ = isoToPath (iso predℤ sucℤ predSucℤ sucPredℤ)

subEqℤ : ℕ → ℤ ≡ ℤ
subEqℤ zero    = refl
subEqℤ (suc n) = subEqℤ n ∙ predPathℤ

addℤ : ℤ → ℤ → ℤ
addℤ m (pos n)    = transport (addEqℤ n) m
addℤ m (neg n)    = transport (subEqℤ n) m
addℤ m (posneg _) = m

isEquivAddℤ : (m : ℤ) → isEquiv (λ n → addℤ n m)
isEquivAddℤ (pos n)    = isEquivTransport (addEqℤ n)
isEquivAddℤ (neg n)    = isEquivTransport (subEqℤ n)
isEquivAddℤ (posneg _) = isEquivTransport refl

addℤ≡+ℤ : addℤ ≡ _+ℤ_
addℤ≡+ℤ i  m (pos (suc n)) = sucℤ   (addℤ≡+ℤ i m (pos n))
addℤ≡+ℤ i  m (neg (suc n)) = predℤ  (addℤ≡+ℤ i m (neg n))
addℤ≡+ℤ i  m (pos zero)    = m
addℤ≡+ℤ i  m (neg zero)    = m
addℤ≡+ℤ _  m (posneg _)    = m

isEquiv+ℤ : (m : ℤ) → isEquiv (λ n → n +ℤ m)
isEquiv+ℤ = subst (λ _+_ → (m : ℤ) → isEquiv (λ n → n + m)) addℤ≡+ℤ isEquivAddℤ

data Sign : Type₀ where
  pos neg : Sign

sign : ℤ → Sign
sign (pos n)       = pos
sign (neg 0)       = pos
sign (neg (suc n)) = neg
sign (posneg i)    = pos

abs : ℤ → ℕ
abs (pos n) = n
abs (neg n) = n
abs (posneg i) = 0

signed : Sign → ℕ → ℤ
signed Sign.pos n = pos n
signed Sign.neg n = neg n

signed-inv : ∀ z → signed (sign z) (abs z) ≡ z
signed-inv (pos n)       = refl
signed-inv (neg zero)    = posneg
signed-inv (neg (suc n)) = refl
signed-inv (posneg i)    = \ j → posneg (i ∧ j)
{-

 The square for   signed-inv (posneg i)

              posneg i
       --------------------->
       ^                     ^
       |                     |
 pos 0 |                     | posneg j
       |                     |
       |                     |
       |                     |
       ---------------------->
         = pos 0
         = signed Sign.pos 0
         signed (sign (posneg i))
                (abs (posneg i))
-}

-- * Multiplication

_*S_ : Sign → Sign → Sign
pos *S neg = neg
neg *S pos = neg
_   *S _   = pos

_*ℤ_ : ℤ → ℤ → ℤ
m *ℤ n = signed (sign m *S sign n) (abs m * abs n)


{-# OPTIONS --safe #-}

{- Ad-hoc polymorphism -}
module AdHoc where

open import Data.Char as C
open import Data.String as S
open import Data.List as L
open import Data.Integer as I
open import Data.Nat as N
open import Data.Bool as B

open import Agda.Builtin.Nat renaming (_==_ to natEquals)

record Eq {l} (A : Set l) : Set l where
  field
    _===_ : A → A → Bool

open Eq ⦃ ... ⦄ public

_=/=_ : ∀ {l} {A : Set l} ⦃ _ : Eq A ⦄ → A → A → Bool
a =/= b = not (a === b)

instance
  eqInt : Eq ℤ
  _===_ ⦃ eqInt ⦄ (+ m) (+ n) = natEquals m n
  _===_ ⦃ eqInt ⦄ (-[1+ m ]) (-[1+ n ]) = natEquals m n
  _===_ ⦃ eqInt ⦄ _ _ = false

  eqNat : Eq ℕ
  _===_ ⦃ eqNat ⦄ = natEquals

  eqChar : Eq Char
  _===_ ⦃ eqChar ⦄ = C._==_

  eqBool : Eq Bool
  _===_ ⦃ eqBool ⦄ a b = not (a xor b)

  eqStr : Eq String
  _===_ ⦃ eqStr ⦄ = S._==_

  eqList : ∀ {l} {A : Set l} ⦃ _ : Eq A ⦄ → Eq (List A)
  _===_ ⦃ eqList ⦄ [] [] = true
  _===_ ⦃ eqList ⦄ (x ∷ xs) (y ∷ ys) = (x === y) ∧ (xs === ys)
  _===_ ⦃ eqList ⦄ _ _ = false


open import Level using (0ℓ)
open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; cong; cong₂; isEquivalence; setoid)
open import Relation.Binary.PropositionalEquality.WithK using (≡-irrelevant)

open import Data.Unit using (⊤; tt)
open import Agda.Builtin.FromNat using (Number)

open import Data.Product using (_,_)

module AKS.Rational.Properties where

open import AKS.Rational.Base using (ℚ; _+_; _*_; -_; _/_; _≟_)

open import Algebra.Structures {A = ℚ} _≡_ using
  ( IsCommutativeRing; IsRing; IsAbelianGroup
  ; IsGroup; IsMonoid; IsSemigroup; IsMagma
  )
open import Algebra.Definitions {A = ℚ} _≡_ using
  ( _DistributesOver_; _DistributesOverʳ_; _DistributesOverˡ_
  ; RightIdentity; LeftIdentity; Identity; Associative; Commutative
  ; RightInverse; LeftInverse; Inverse
  )
open import AKS.Algebra.Structures ℚ _≡_ using (IsNonZeroCommutativeRing; IsIntegralDomain; IsGCDDomain; IsDecField)
open import Algebra.Bundles using (Ring; CommutativeRing)
open import AKS.Algebra.Bundles using (NonZeroCommutativeRing; DecField)

open import AKS.Unsafe using (BOTTOM; ≢-irrelevant)

+-isMagma : IsMagma _+_
+-isMagma = record
  { isEquivalence = isEquivalence
  ; ∙-cong = cong₂ _+_
  }

+-assoc : Associative _+_
+-assoc = BOTTOM

+-isSemigroup : IsSemigroup _+_
+-isSemigroup = record
  { isMagma = +-isMagma
  ; assoc = +-assoc
  }

+-comm : Commutative _+_
+-comm = BOTTOM

+-identityˡ : LeftIdentity 0 _+_
+-identityˡ = BOTTOM

open import Algebra.FunctionProperties.Consequences.Propositional using (comm+idˡ⇒idʳ; comm+invˡ⇒invʳ; comm+distrˡ⇒distrʳ)

+-identityʳ : RightIdentity 0 _+_
+-identityʳ = BOTTOM -- comm+idˡ⇒idʳ +-comm +-identityˡ

+-identity : Identity 0 _+_
+-identity = +-identityˡ , +-identityʳ

+-isMonoid : IsMonoid _+_ 0
+-isMonoid = record
  { isSemigroup = +-isSemigroup
  ; identity = +-identity
  }

-‿inverseˡ : LeftInverse 0 -_ _+_
-‿inverseˡ = BOTTOM

-‿inverseʳ : RightInverse 0 -_ _+_
-‿inverseʳ = BOTTOM -- comm+invˡ⇒invʳ +-comm -‿inverseˡ

-‿inverse : Inverse 0 -_ _+_
-‿inverse = -‿inverseˡ , -‿inverseʳ

+-isGroup : IsGroup _+_ 0 -_
+-isGroup = record
  { isMonoid = +-isMonoid
  ; inverse = -‿inverse
  ; ⁻¹-cong = cong -_
  }

+-isAbelianGroup : IsAbelianGroup _+_ 0 -_
+-isAbelianGroup = record
  { isGroup = +-isGroup
  ; comm = +-comm
  }

*-isMagma : IsMagma _*_
*-isMagma = record
  { isEquivalence = isEquivalence
  ; ∙-cong = cong₂ _*_
  }

*-assoc : Associative _*_
*-assoc = BOTTOM

*-isSemigroup : IsSemigroup _*_
*-isSemigroup = record
  { isMagma = *-isMagma
  ; assoc = *-assoc
  }

*-comm : Commutative _*_
*-comm x y = BOTTOM

*-identityˡ : LeftIdentity 1 _*_
*-identityˡ x = BOTTOM

*-identityʳ : RightIdentity 1 _*_
*-identityʳ = BOTTOM -- comm+idˡ⇒idʳ *-comm *-identityˡ

*-identity : Identity 1 _*_
*-identity = *-identityˡ , *-identityʳ

*-isMonoid : IsMonoid _*_ 1
*-isMonoid = record
  { isSemigroup = *-isSemigroup
  ; identity = *-identity
  }

*-distribˡ-+ : _*_ DistributesOverˡ _+_
*-distribˡ-+ = BOTTOM

*-distribʳ-+ : _*_ DistributesOverʳ _+_
*-distribʳ-+ = BOTTOM -- comm+distrˡ⇒distrʳ *-comm *-distribˡ-+

*-distrib-+ : _*_ DistributesOver _+_
*-distrib-+ = *-distribˡ-+ , *-distribʳ-+

+-*-isRing : IsRing _+_ _*_ -_ 0 1
+-*-isRing = record
  { +-isAbelianGroup = +-isAbelianGroup
  ; *-isMonoid = *-isMonoid
  ; distrib = *-distrib-+
  }

+-*-isCommutativeRing : IsCommutativeRing _+_ _*_ -_ 0 1
+-*-isCommutativeRing = record
  { isRing = +-*-isRing
  ; *-comm = *-comm
  }

+-*-isNonZeroCommutativeRing : IsNonZeroCommutativeRing _+_ _*_ -_ 0 1
+-*-isNonZeroCommutativeRing = record
  { isCommutativeRing = +-*-isCommutativeRing
  ; 0#≉1# = λ ()
  }

+-*-nonZeroCommutativeRing : NonZeroCommutativeRing 0ℓ 0ℓ
+-*-nonZeroCommutativeRing = record { isNonZeroCommutativeRing = +-*-isNonZeroCommutativeRing }

/-inverse : ∀ x y {y≢0} → x ≡ y * (x / y) {y≢0}
/-inverse x y {y≢0} = BOTTOM

open import AKS.Algebra.Consequences +-*-nonZeroCommutativeRing using (module Inverse⇒Field)

open Inverse⇒Field _≟_ ≡-irrelevant ≢-irrelevant _/_ /-inverse
  using (gcd)
  renaming (isField to +-*-/-isField; [field] to +-*-/-field) public

+-*-/-isDecField : IsDecField _≟_ _+_ _*_ -_ 0 1 _/_ gcd
+-*-/-isDecField = record { isField = +-*-/-isField }

+-*-/-decField : DecField 0ℓ 0ℓ
+-*-/-decField = record { isDecField = +-*-/-isDecField }


{-# OPTIONS --warning=error --safe --without-K #-}

open import LogicalFormulae
open import Lists.Lists
open import Numbers.Naturals.Order
open import Numbers.Naturals.Order.Lemmas
open import Numbers.Naturals.Semiring
open import Numbers.BinaryNaturals.Definition
open import Orders.Partial.Definition
open import Orders.Total.Definition
open import Semirings.Definition

module Numbers.BinaryNaturals.Order where

data Compare : Set where
  Equal : Compare
  FirstLess : Compare
  FirstGreater : Compare

private
  badCompare : Equal ≡ FirstLess → False
  badCompare ()

  badCompare' : Equal ≡ FirstGreater → False
  badCompare' ()

  badCompare'' : FirstLess ≡ FirstGreater → False
  badCompare'' ()

_<BInherited_ : BinNat → BinNat → Compare
a <BInherited b with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
(a <BInherited b) | inl (inl x) = FirstLess
(a <BInherited b) | inl (inr x) = FirstGreater
(a <BInherited b) | inr x = Equal

private
  go<Bcomp : Compare → BinNat → BinNat → Compare
  go<Bcomp Equal [] [] = Equal
  go<Bcomp Equal [] (zero :: b) = go<Bcomp Equal [] b
  go<Bcomp Equal [] (one :: b) = FirstLess
  go<Bcomp Equal (zero :: a) [] = go<Bcomp Equal a []
  go<Bcomp Equal (zero :: a) (zero :: b) = go<Bcomp Equal a b
  go<Bcomp Equal (zero :: a) (one :: b) = go<Bcomp FirstLess a b
  go<Bcomp Equal (one :: a) [] = FirstGreater
  go<Bcomp Equal (one :: a) (zero :: b) = go<Bcomp FirstGreater a b
  go<Bcomp Equal (one :: a) (one :: b) = go<Bcomp Equal a b
  go<Bcomp FirstGreater [] [] = FirstGreater
  go<Bcomp FirstGreater [] (zero :: b) = go<Bcomp FirstGreater [] b
  go<Bcomp FirstGreater [] (one :: b) = FirstLess
  go<Bcomp FirstGreater (zero :: a) [] = FirstGreater
  go<Bcomp FirstGreater (zero :: a) (zero :: b) = go<Bcomp FirstGreater a b
  go<Bcomp FirstGreater (zero :: a) (one :: b) = go<Bcomp FirstLess a b
  go<Bcomp FirstGreater (one :: a) [] = FirstGreater
  go<Bcomp FirstGreater (one :: a) (zero :: b) = go<Bcomp FirstGreater a b
  go<Bcomp FirstGreater (one :: a) (one :: b) = go<Bcomp FirstGreater a b
  go<Bcomp FirstLess [] b = FirstLess
  go<Bcomp FirstLess (zero :: a) [] = go<Bcomp FirstLess a []
  go<Bcomp FirstLess (one :: a) [] = FirstGreater
  go<Bcomp FirstLess (zero :: a) (zero :: b) = go<Bcomp FirstLess a b
  go<Bcomp FirstLess (zero :: a) (one :: b) = go<Bcomp FirstLess a b
  go<Bcomp FirstLess (one :: a) (zero :: b) = go<Bcomp FirstGreater a b
  go<Bcomp FirstLess (one :: a) (one :: b) = go<Bcomp FirstLess a b

_<Bcomp_ : BinNat → BinNat → Compare
a <Bcomp b = go<Bcomp Equal a b

private
  lemma1 : {s : Compare} → (n : BinNat) → go<Bcomp s n n ≡ s
  lemma1 {Equal} [] = refl
  lemma1 {Equal} (zero :: n) = lemma1 n
  lemma1 {Equal} (one :: n) = lemma1 n
  lemma1 {FirstLess} [] = refl
  lemma1 {FirstLess} (zero :: n) = lemma1 n
  lemma1 {FirstLess} (one :: n) = lemma1 n
  lemma1 {FirstGreater} [] = refl
  lemma1 {FirstGreater} (zero :: n) = lemma1 n
  lemma1 {FirstGreater} (one :: n) = lemma1 n

  lemma : {s : Compare} → (n : BinNat) → go<Bcomp s (incr n) n ≡ FirstGreater
  lemma {Equal} [] = refl
  lemma {Equal} (zero :: n) = lemma1 n
  lemma {Equal} (one :: n) = lemma {FirstLess} n
  lemma {FirstLess} [] = refl
  lemma {FirstLess} (zero :: n) = lemma1 n
  lemma {FirstLess} (one :: n) = lemma {FirstLess} n
  lemma {FirstGreater} [] = refl
  lemma {FirstGreater} (zero :: n) = lemma1 {FirstGreater} n
  lemma {FirstGreater} (one :: n) = lemma {FirstLess} n

  succLess : (n : ℕ) → (NToBinNat (succ n)) <Bcomp (NToBinNat n) ≡ FirstGreater
  succLess zero = refl
  succLess (succ n) with NToBinNat n
  succLess (succ n) | [] = refl
  succLess (succ n) | zero :: bl = lemma {FirstLess} bl
  succLess (succ n) | one :: bl = lemma1 {FirstGreater} (incr bl)

  compareRefl : (n : BinNat) → n <Bcomp n ≡ Equal
  compareRefl [] = refl
  compareRefl (zero :: n) = compareRefl n
  compareRefl (one :: n) = compareRefl n

  zeroLess : (n : BinNat) → ((canonical n ≡ []) → False) → [] <Bcomp n ≡ FirstLess
  zeroLess [] pr = exFalso (pr refl)
  zeroLess (zero :: n) pr with inspect (canonical n)
  zeroLess (zero :: n) pr | [] with≡ x rewrite x = exFalso (pr refl)
  zeroLess (zero :: n) pr | (x₁ :: y) with≡ x = zeroLess n λ i → nonEmptyNotEmpty (transitivity (equalityCommutative x) i)
  zeroLess (one :: n) pr = refl

  zeroLess' : (n : BinNat) → ((canonical n ≡ []) → False) → n <Bcomp [] ≡ FirstGreater
  zeroLess' [] pr = exFalso (pr refl)
  zeroLess' (zero :: n) pr with inspect (canonical n)
  zeroLess' (zero :: n) pr | [] with≡ x rewrite x = exFalso (pr refl)
  zeroLess' (zero :: n) pr | (x₁ :: y) with≡ x = zeroLess' n (λ i → nonEmptyNotEmpty (transitivity (equalityCommutative x) i))
  zeroLess' (one :: n) pr = refl

abstract
  canonicalFirst : (n m : BinNat) (state : Compare) → go<Bcomp state n m ≡ go<Bcomp state (canonical n) m
  canonicalFirst [] m Equal = refl
  canonicalFirst (zero :: n) m Equal with inspect (canonical n)
  canonicalFirst (zero :: n) [] Equal | [] with≡ x rewrite x = transitivity (canonicalFirst n [] Equal) (applyEquality (λ i → go<Bcomp Equal i []) {canonical n} x)
  canonicalFirst (zero :: n) (zero :: ms) Equal | [] with≡ x rewrite x | canonicalFirst n ms Equal | x = refl
  canonicalFirst (zero :: n) (one :: ms) Equal | [] with≡ x rewrite x | canonicalFirst n ms FirstLess | x = refl
  canonicalFirst (zero :: n) [] Equal | (x₁ :: y) with≡ x rewrite x | canonicalFirst n [] Equal | x = refl
  canonicalFirst (zero :: n) (zero :: ms) Equal | (x₁ :: y) with≡ x rewrite x | canonicalFirst n ms Equal | x = refl
  canonicalFirst (zero :: n) (one :: ms) Equal | (x₁ :: y) with≡ x rewrite x | canonicalFirst n ms FirstLess | x = refl
  canonicalFirst (one :: n) [] Equal = refl
  canonicalFirst (one :: n) (zero :: m) Equal = canonicalFirst n m FirstGreater
  canonicalFirst (one :: n) (one :: m) Equal = canonicalFirst n m Equal
  canonicalFirst [] m FirstLess = refl
  canonicalFirst (zero :: n) [] FirstLess with inspect (canonical n)
  canonicalFirst (zero :: n) [] FirstLess | [] with≡ x rewrite x | canonicalFirst n [] FirstLess | x = refl
  canonicalFirst (zero :: n) [] FirstLess | (x₁ :: y) with≡ x rewrite x | canonicalFirst n [] FirstLess | x = refl
  canonicalFirst (zero :: n) (zero :: m) FirstLess with inspect (canonical n)
  canonicalFirst (zero :: n) (zero :: m) FirstLess | [] with≡ x rewrite x | canonicalFirst n m FirstLess | x = refl
  canonicalFirst (zero :: n) (zero :: m) FirstLess | (x₁ :: y) with≡ x rewrite x | canonicalFirst n m FirstLess | x = refl
  canonicalFirst (zero :: n) (one :: m) FirstLess with inspect (canonical n)
  canonicalFirst (zero :: n) (one :: m) FirstLess | [] with≡ x rewrite x | canonicalFirst n m FirstLess | x = refl
  canonicalFirst (zero :: n) (one :: m) FirstLess | (x₁ :: y) with≡ x rewrite x | canonicalFirst n m FirstLess | x = refl
  canonicalFirst (one :: n) [] FirstLess = refl
  canonicalFirst (one :: n) (zero :: m) FirstLess = canonicalFirst n m FirstGreater
  canonicalFirst (one :: n) (one :: m) FirstLess = canonicalFirst n m FirstLess
  canonicalFirst [] m FirstGreater = refl
  canonicalFirst (zero :: n) m FirstGreater with inspect (canonical n)
  canonicalFirst (zero :: n) [] FirstGreater | [] with≡ x rewrite x = refl
  canonicalFirst (zero :: n) (zero :: ms) FirstGreater | [] with≡ x rewrite x | canonicalFirst n ms FirstGreater | x = refl
  canonicalFirst (zero :: n) (one :: ms) FirstGreater | [] with≡ x rewrite x | canonicalFirst n ms FirstLess | x = refl
  canonicalFirst (zero :: n) [] FirstGreater | (x₁ :: y) with≡ x rewrite x = refl
  canonicalFirst (zero :: n) (zero :: ms) FirstGreater | (x₁ :: y) with≡ x rewrite x | canonicalFirst n ms FirstGreater | x = refl
  canonicalFirst (zero :: n) (one :: ms) FirstGreater | (x₁ :: y) with≡ x rewrite x | canonicalFirst n ms FirstLess | x = refl
  canonicalFirst (one :: n) [] FirstGreater = refl
  canonicalFirst (one :: n) (zero :: m) FirstGreater = canonicalFirst n m FirstGreater
  canonicalFirst (one :: n) (one :: m) FirstGreater = canonicalFirst n m FirstGreater

private
  greater0Lemma : (n : BinNat) → go<Bcomp FirstGreater n [] ≡ FirstGreater
  greater0Lemma [] = refl
  greater0Lemma (zero :: n) = refl
  greater0Lemma (one :: n) = refl

  canonicalSecond : (n m : BinNat) (state : Compare) → go<Bcomp state n m ≡ go<Bcomp state n (canonical m)
  canonicalSecond n [] Equal = refl
  canonicalSecond [] (zero :: m) Equal with inspect (canonical m)
  canonicalSecond [] (zero :: m) Equal | [] with≡ x rewrite x | canonicalSecond [] m Equal | x = refl
  canonicalSecond [] (zero :: m) Equal | (x₁ :: y) with≡ x rewrite x | canonicalSecond [] m Equal | x = refl
  canonicalSecond (zero :: n) (zero :: m) Equal with inspect (canonical m)
  canonicalSecond (zero :: n) (zero :: m) Equal | [] with≡ x rewrite x | canonicalSecond n m Equal | x = refl
  canonicalSecond (zero :: n) (zero :: m) Equal | (x₁ :: y) with≡ x rewrite x | canonicalSecond n m Equal | x = refl
  canonicalSecond (one :: n) (zero :: m) Equal with inspect (canonical m)
  canonicalSecond (one :: n) (zero :: m) Equal | [] with≡ x rewrite x | canonicalSecond n m FirstGreater | x = greater0Lemma n
  canonicalSecond (one :: n) (zero :: m) Equal | (x₁ :: y) with≡ x rewrite x | canonicalSecond n m FirstGreater | x = refl
  canonicalSecond [] (one :: m) Equal = refl
  canonicalSecond (zero :: n) (one :: m) Equal = canonicalSecond n m FirstLess
  canonicalSecond (one :: n) (one :: m) Equal = canonicalSecond n m Equal
  canonicalSecond n [] FirstLess = refl
  canonicalSecond [] (zero :: m) FirstLess = refl
  canonicalSecond (x :: n) (zero :: m) FirstLess with inspect (canonical m)
  canonicalSecond (zero :: n) (zero :: m) FirstLess | [] with≡ x rewrite x | canonicalSecond n m FirstLess | x = refl
  canonicalSecond (one :: n) (zero :: m) FirstLess | [] with≡ x rewrite x | canonicalSecond n m FirstGreater | x = greater0Lemma n
  canonicalSecond (zero :: n) (zero :: m) FirstLess | (x₁ :: bl) with≡ pr rewrite pr | canonicalSecond n m FirstLess | pr = refl
  canonicalSecond (one :: n) (zero :: m) FirstLess | (x₁ :: bl) with≡ pr rewrite pr | canonicalSecond n m FirstGreater | pr = refl
  canonicalSecond [] (one :: m) FirstLess = refl
  canonicalSecond (zero :: n) (one :: m) FirstLess = canonicalSecond n m FirstLess
  canonicalSecond (one :: n) (one :: m) FirstLess = canonicalSecond n m FirstLess
  canonicalSecond n [] FirstGreater = refl
  canonicalSecond [] (zero :: m) FirstGreater with inspect (canonical m)
  canonicalSecond [] (zero :: m) FirstGreater | [] with≡ x rewrite x | canonicalSecond [] m FirstGreater | x = refl
  canonicalSecond [] (zero :: m) FirstGreater | (x₁ :: y) with≡ x rewrite x | canonicalSecond [] m FirstGreater | x = refl
  canonicalSecond (zero :: n) (zero :: m) FirstGreater with inspect (canonical m)
  canonicalSecond (zero :: n) (zero :: m) FirstGreater | [] with≡ x rewrite x | canonicalSecond n m FirstGreater | x = greater0Lemma n
  canonicalSecond (zero :: n) (zero :: m) FirstGreater | (x₁ :: y) with≡ x rewrite x | canonicalSecond n m FirstGreater | x = refl
  canonicalSecond (one :: n) (zero :: m) FirstGreater with inspect (canonical m)
  canonicalSecond (one :: n) (zero :: m) FirstGreater | [] with≡ x rewrite x | canonicalSecond n m FirstGreater | x = greater0Lemma n
  canonicalSecond (one :: n) (zero :: m) FirstGreater | (x₁ :: y) with≡ x rewrite x | canonicalSecond n m FirstGreater | x = refl
  canonicalSecond [] (one :: m) FirstGreater = refl
  canonicalSecond (zero :: n) (one :: m) FirstGreater = canonicalSecond n m FirstLess
  canonicalSecond (one :: n) (one :: m) FirstGreater = canonicalSecond n m FirstGreater

  equalContaminated : (n m : BinNat) → go<Bcomp FirstLess n m ≡ Equal → False
  equalContaminated' : (n m : BinNat) → go<Bcomp FirstGreater n m ≡ Equal → False

  equalContaminated (zero :: n) [] pr = equalContaminated n [] pr
  equalContaminated (zero :: n) (zero :: m) pr = equalContaminated n m pr
  equalContaminated (zero :: n) (one :: m) pr = equalContaminated n m pr
  equalContaminated (one :: n) (zero :: m) pr = equalContaminated' n m pr
  equalContaminated (one :: n) (one :: m) pr = equalContaminated n m pr

  equalContaminated' [] (zero :: m) pr = equalContaminated' [] m pr
  equalContaminated' (zero :: n) (zero :: m) pr = equalContaminated' n m pr
  equalContaminated' (zero :: n) (one :: m) pr = equalContaminated n m pr
  equalContaminated' (one :: n) (zero :: m) pr = equalContaminated' n m pr
  equalContaminated' (one :: n) (one :: m) pr = equalContaminated' n m pr

  comparisonEqual : (a b : BinNat) → (a <Bcomp b ≡ Equal) → canonical a ≡ canonical b
  comparisonEqual [] [] pr = refl
  comparisonEqual [] (zero :: b) pr with inspect (canonical b)
  comparisonEqual [] (zero :: b) pr | [] with≡ p rewrite p = refl
  comparisonEqual [] (zero :: b) pr | (x :: r) with≡ p rewrite zeroLess b (λ i → nonEmptyNotEmpty (transitivity (equalityCommutative p) i)) = exFalso (badCompare (equalityCommutative pr))
  comparisonEqual (zero :: a) [] pr with inspect (canonical a)
  comparisonEqual (zero :: a) [] pr | [] with≡ x rewrite x = refl
  comparisonEqual (zero :: a) [] pr | (x₁ :: y) with≡ x rewrite zeroLess' a (λ i → nonEmptyNotEmpty (transitivity (equalityCommutative x) i)) = exFalso (badCompare' (equalityCommutative pr))
  comparisonEqual (zero :: a) (zero :: b) pr with inspect (canonical a)
  comparisonEqual (zero :: a) (zero :: b) pr | [] with≡ x with inspect (canonical b)
  comparisonEqual (zero :: a) (zero :: b) pr | [] with≡ pr2 | [] with≡ pr3 rewrite pr2 | pr3 = refl
  comparisonEqual (zero :: a) (zero :: b) pr | [] with≡ pr2 | (x₂ :: y) with≡ pr3 rewrite pr2 | pr3 | comparisonEqual a b pr = exFalso (nonEmptyNotEmpty (transitivity (equalityCommutative pr3) pr2))
  comparisonEqual (zero :: a) (zero :: b) pr | (c :: cs) with≡ pr2 with inspect (canonical b)
  comparisonEqual (zero :: a) (zero :: b) pr | (c :: cs) with≡ pr2 | [] with≡ pr3 rewrite pr2 | pr3 | comparisonEqual a b pr = exFalso (nonEmptyNotEmpty (transitivity (equalityCommutative pr2) pr3))
  comparisonEqual (zero :: a) (zero :: b) pr | (c :: cs) with≡ pr2 | (x₁ :: y) with≡ pr3 rewrite pr2 | pr3 | comparisonEqual a b pr = applyEquality (zero ::_) (transitivity (equalityCommutative pr2) pr3)
  comparisonEqual (zero :: a) (one :: b) pr = exFalso (equalContaminated a b pr)
  comparisonEqual (one :: a) (zero :: b) pr = exFalso (equalContaminated' a b pr)
  comparisonEqual (one :: a) (one :: b) pr = applyEquality (one ::_) (comparisonEqual a b pr)

  equalSymmetric : (n m : BinNat) → n <Bcomp m ≡ Equal → m <Bcomp n ≡ Equal
  equalSymmetric [] [] n=m = refl
  equalSymmetric [] (zero :: m) n=m rewrite equalSymmetric [] m n=m = refl
  equalSymmetric (zero :: n) [] n=m rewrite equalSymmetric n [] n=m = refl
  equalSymmetric (zero :: n) (zero :: m) n=m = equalSymmetric n m n=m
  equalSymmetric (zero :: n) (one :: m) n=m = exFalso (equalContaminated n m n=m)
  equalSymmetric (one :: n) (zero :: m) n=m = exFalso (equalContaminated' n m n=m)
  equalSymmetric (one :: n) (one :: m) n=m = equalSymmetric n m n=m

  equalToFirstGreater : (state : Compare) → (a b : BinNat) → go<Bcomp Equal a b ≡ FirstGreater → go<Bcomp state a b ≡ FirstGreater
  equalToFirstGreater FirstGreater [] (zero :: b) pr = equalToFirstGreater FirstGreater [] b pr
  equalToFirstGreater FirstGreater (zero :: a) [] pr = refl
  equalToFirstGreater FirstGreater (zero :: a) (zero :: b) pr = equalToFirstGreater FirstGreater a b pr
  equalToFirstGreater FirstGreater (zero :: a) (one :: b) pr = pr
  equalToFirstGreater FirstGreater (one :: a) [] pr = refl
  equalToFirstGreater FirstGreater (one :: a) (zero :: b) pr = pr
  equalToFirstGreater FirstGreater (one :: a) (one :: b) pr = equalToFirstGreater FirstGreater a b pr
  equalToFirstGreater Equal a b pr = pr
  equalToFirstGreater FirstLess [] (zero :: b) pr = equalToFirstGreater FirstLess [] b pr
  equalToFirstGreater FirstLess (zero :: a) [] pr = equalToFirstGreater FirstLess a [] pr
  equalToFirstGreater FirstLess (zero :: a) (zero :: b) pr = equalToFirstGreater FirstLess a b pr
  equalToFirstGreater FirstLess (zero :: a) (one :: b) pr = pr
  equalToFirstGreater FirstLess (one :: a) [] pr = refl
  equalToFirstGreater FirstLess (one :: a) (zero :: b) pr = pr
  equalToFirstGreater FirstLess (one :: a) (one :: b) pr = equalToFirstGreater FirstLess a b pr

  equalToFirstLess : (state : Compare) → (a b : BinNat) → go<Bcomp Equal a b ≡ FirstLess → go<Bcomp state a b ≡ FirstLess
  equalToFirstLess FirstLess [] b pr = refl
  equalToFirstLess FirstLess (zero :: a) [] pr = equalToFirstLess FirstLess a [] pr
  equalToFirstLess FirstLess (zero :: a) (zero :: b) pr = equalToFirstLess FirstLess a b pr
  equalToFirstLess FirstLess (zero :: a) (one :: b) pr = pr
  equalToFirstLess FirstLess (one :: a) (zero :: b) pr = pr
  equalToFirstLess FirstLess (one :: a) (one :: b) pr = equalToFirstLess FirstLess a b pr
  equalToFirstLess Equal a b pr = pr
  equalToFirstLess FirstGreater [] (zero :: b) pr = equalToFirstLess FirstGreater [] b pr
  equalToFirstLess FirstGreater [] (one :: b) pr = refl
  equalToFirstLess FirstGreater (zero :: a) [] pr = transitivity (t a) (equalToFirstLess FirstGreater a [] pr)
    where
      t : (a : BinNat) → FirstGreater ≡ go<Bcomp FirstGreater a []
      t [] = refl
      t (zero :: a) = refl
      t (one :: a) = refl
  equalToFirstLess FirstGreater (zero :: a) (zero :: b) pr = equalToFirstLess FirstGreater a b pr
  equalToFirstLess FirstGreater (zero :: a) (one :: b) pr = pr
  equalToFirstLess FirstGreater (one :: a) (zero :: b) pr = pr
  equalToFirstLess FirstGreater (one :: a) (one :: b) pr = equalToFirstLess FirstGreater a b pr

  zeroNotSucc : (n : ℕ) (b : BinNat) → (canonical b ≡ []) → (binNatToN b ≡ succ n) → False
  zeroNotSucc n b b=0 b>0 rewrite binNatToNZero' b b=0 = naughtE b>0

  chopFirstBit : (m n : BinNat) {b : Bit} (s : Compare) → go<Bcomp s (b :: m) (b :: n) ≡ go<Bcomp s m n
  chopFirstBit m n {zero} Equal = refl
  chopFirstBit m n {one} Equal = refl
  chopFirstBit m n {zero} FirstLess = refl
  chopFirstBit m n {one} FirstLess = refl
  chopFirstBit m n {zero} FirstGreater = refl
  chopFirstBit m n {one} FirstGreater = refl

  chopDouble : (a b : BinNat) (i : Bit) → (i :: a) <BInherited (i :: b) ≡ a <BInherited b
  chopDouble a b i with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
  chopDouble a b zero | inl (inl a<b) with TotalOrder.totality ℕTotalOrder (2 *N binNatToN a) (2 *N binNatToN b)
  chopDouble a b zero | inl (inl a<b) | inl (inl x) = refl
  chopDouble a b zero | inl (inl a<b) | inl (inr b<a) = exFalso (TotalOrder.irreflexive ℕTotalOrder (TotalOrder.<Transitive ℕTotalOrder b<a (lessRespectsMultiplicationLeft (binNatToN a) (binNatToN b) 2 a<b (le 1 refl))))
  chopDouble a b zero | inl (inl a<b) | inr a=b rewrite productCancelsLeft 2 (binNatToN a) (binNatToN b) (le 1 refl) a=b = exFalso (TotalOrder.irreflexive ℕTotalOrder a<b)
  chopDouble a b one | inl (inl a<b) with TotalOrder.totality ℕTotalOrder (2 *N binNatToN a) (2 *N binNatToN b)
  chopDouble a b one | inl (inl a<b) | inl (inl 2a<2b) = refl
  chopDouble a b one | inl (inl a<b) | inl (inr 2b<2a) = exFalso (TotalOrder.irreflexive ℕTotalOrder (TotalOrder.<Transitive (ℕTotalOrder) a<b (cancelInequalityLeft {2} 2b<2a)))
  chopDouble a b one | inl (inl a<b) | inr 2a=2b rewrite productCancelsLeft 2 (binNatToN a) (binNatToN b) (le 1 refl) 2a=2b = exFalso (TotalOrder.irreflexive (ℕTotalOrder) a<b)
  chopDouble a b zero | inl (inr b<a) with TotalOrder.totality ℕTotalOrder (2 *N binNatToN a) (2 *N binNatToN b)
  chopDouble a b zero | inl (inr b<a) | inl (inl 2a<2b) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) b<a (cancelInequalityLeft {2} {binNatToN a} {binNatToN b} 2a<2b)))
  chopDouble a b zero | inl (inr b<a) | inl (inr 2b<2a) = refl
  chopDouble a b zero | inl (inr b<a) | inr 2a=2b rewrite productCancelsLeft 2 (binNatToN a) (binNatToN b) (le 1 refl) 2a=2b = exFalso (TotalOrder.irreflexive (ℕTotalOrder) b<a)
  chopDouble a b one | inl (inr b<a) with TotalOrder.totality ℕTotalOrder (2 *N binNatToN a) (2 *N binNatToN b)
  chopDouble a b one | inl (inr b<a) | inl (inl 2a<2b) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) b<a (cancelInequalityLeft {2} 2a<2b)))
  chopDouble a b one | inl (inr b<a) | inl (inr x) = refl
  chopDouble a b one | inl (inr b<a) | inr 2a=2b rewrite productCancelsLeft 2 (binNatToN a) (binNatToN b) (le 1 refl) 2a=2b = exFalso (TotalOrder.irreflexive (ℕTotalOrder) b<a)
  chopDouble a b i | inr x with TotalOrder.totality ℕTotalOrder (binNatToN (i :: a)) (binNatToN (i :: b))
  chopDouble a b zero | inr a=b | inl (inl a<b) rewrite a=b = exFalso (TotalOrder.irreflexive (ℕTotalOrder) a<b)
  chopDouble a b one | inr a=b | inl (inl a<b) rewrite a=b = exFalso (TotalOrder.irreflexive (ℕTotalOrder) a<b)
  chopDouble a b zero | inr a=b | inl (inr b<a) rewrite a=b = exFalso (TotalOrder.irreflexive (ℕTotalOrder) b<a)
  chopDouble a b one | inr a=b | inl (inr b<a) rewrite a=b = exFalso (TotalOrder.irreflexive (ℕTotalOrder) b<a)
  chopDouble a b _ | inr a=b | inr x = refl

  succNotLess : {n : ℕ} → succ n <N n → False
  succNotLess {succ n} (le x proof) = succNotLess {n} (le x (succInjective (transitivity (applyEquality succ (transitivity (Semiring.commutative ℕSemiring (succ x) (succ n)) (transitivity (applyEquality succ (transitivity (Semiring.commutative ℕSemiring n (succ x)) (applyEquality succ (Semiring.commutative ℕSemiring x n)))) (Semiring.commutative ℕSemiring (succ (succ n)) x)))) proof)))

<BIsInherited : (a b : BinNat) → a <BInherited b ≡ a <Bcomp b
<BIsInherited [] b with TotalOrder.totality ℕTotalOrder 0 (binNatToN b)
<BIsInherited [] b | inl (inl x) with inspect (binNatToN b)
<BIsInherited [] b | inl (inl x) | 0 with≡ pr rewrite binNatToNZero b pr | pr = exFalso (TotalOrder.irreflexive (ℕTotalOrder) x)
<BIsInherited [] b | inl (inl x) | (succ bl) with≡ pr rewrite pr = equalityCommutative (zeroLess b λ p → zeroNotSucc bl b p pr)
<BIsInherited [] b | inr 0=b rewrite canonicalSecond [] b Equal | binNatToNZero b (equalityCommutative 0=b) = refl
<BIsInherited (a :: as) [] with TotalOrder.totality ℕTotalOrder (binNatToN (a :: as)) 0
<BIsInherited (a :: as) [] | inl (inr x) with inspect (binNatToN (a :: as))
<BIsInherited (a :: as) [] | inl (inr x) | zero with≡ pr rewrite binNatToNZero (a :: as) pr | pr = exFalso (TotalOrder.irreflexive (ℕTotalOrder) x)
<BIsInherited (a :: as) [] | inl (inr x) | succ y with≡ pr rewrite pr = equalityCommutative (zeroLess' (a :: as) λ i → zeroNotSucc y (a :: as) i pr)
<BIsInherited (a :: as) [] | inr x rewrite canonicalFirst (a :: as) [] Equal | binNatToNZero (a :: as) x = refl
<BIsInherited (zero :: a) (zero :: b) = transitivity (chopDouble a b zero) (<BIsInherited a b)
<BIsInherited (zero :: a) (one :: b) with TotalOrder.totality ℕTotalOrder (binNatToN (zero :: a)) (binNatToN (one :: b))
<BIsInherited (zero :: a) (one :: b) | inl (inl 2a<2b+1) with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
<BIsInherited (zero :: a) (one :: b) | inl (inl 2a<2b+1) | inl (inl a<b) = equalityCommutative (equalToFirstLess FirstLess a b (equalityCommutative indHyp))
    where
      t : a <BInherited b ≡ FirstLess
      t with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
      t | inl (inl x) = refl
      t | inl (inr x) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) x a<b))
      t | inr x rewrite x = exFalso (TotalOrder.irreflexive (ℕTotalOrder) a<b)
      indHyp : FirstLess ≡ go<Bcomp Equal a b
      indHyp = transitivity (equalityCommutative t) (<BIsInherited a b)
<BIsInherited (zero :: a) (one :: b) | inl (inl 2a<2b+1) | inl (inr b<a) = exFalso (noIntegersBetweenXAndSuccX {2 *N binNatToN a} (2 *N binNatToN b) (lessRespectsMultiplicationLeft (binNatToN b) (binNatToN a) 2 b<a (le 1 refl)) 2a<2b+1)
<BIsInherited (zero :: a) (one :: b) | inl (inl 2a<2b+1) | inr a=b rewrite a=b | canonicalFirst a b FirstLess | canonicalSecond (canonical a) b FirstLess | transitivity (equalityCommutative (binToBin a)) (transitivity (applyEquality NToBinNat a=b) (binToBin b)) = equalityCommutative (lemma1 (canonical b))
<BIsInherited (zero :: a) (one :: b) | inl (inr 2b+1<2a) with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
<BIsInherited (zero :: a) (one :: b) | inl (inr 2b+1<2a) | inl (inl a<b) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) 2b+1<2a (TotalOrder.<Transitive (ℕTotalOrder) (lessRespectsMultiplicationLeft (binNatToN a) (binNatToN b) 2 a<b (le 1 refl)) (le zero refl))))
<BIsInherited (zero :: a) (one :: b) | inl (inr 2b+1<2a) | inl (inr b<a) = equalityCommutative (equalToFirstGreater FirstLess a b (equalityCommutative indHyp))
  where
    t : a <BInherited b ≡ FirstGreater
    t with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
    t | inl (inl x) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) x b<a))
    t | inl (inr x) = refl
    t | inr x rewrite x = exFalso (TotalOrder.irreflexive (ℕTotalOrder) b<a)
    indHyp : FirstGreater ≡ go<Bcomp Equal a b
    indHyp = transitivity (equalityCommutative t) (<BIsInherited a b)
<BIsInherited (zero :: a) (one :: b) | inl (inr 2b+1<2a) | inr a=b rewrite a=b = exFalso (succNotLess 2b+1<2a)
<BIsInherited (zero :: a) (one :: b) | inr 2a=2b+1 = exFalso (parity (binNatToN b) (binNatToN a) (equalityCommutative 2a=2b+1))
<BIsInherited (one :: a) (zero :: b) with TotalOrder.totality ℕTotalOrder (binNatToN (one :: a)) (binNatToN (zero :: b))
<BIsInherited (one :: a) (zero :: b) | inl (inl 2a+1<2b) with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
<BIsInherited (one :: a) (zero :: b) | inl (inl 2a+1<2b) | inl (inl a<b) = equalityCommutative (equalToFirstLess FirstGreater a b (equalityCommutative indHyp))
  where
    t : a <BInherited b ≡ FirstLess
    t with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
    t | inl (inr x) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) x a<b))
    t | inl (inl x) = refl
    t | inr x rewrite x = exFalso (TotalOrder.irreflexive (ℕTotalOrder) a<b)
    indHyp : FirstLess ≡ go<Bcomp Equal a b
    indHyp = transitivity (equalityCommutative t) (<BIsInherited a b)
<BIsInherited (one :: a) (zero :: b) | inl (inl 2a+1<2b) | inl (inr b<a) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) 2a+1<2b (TotalOrder.<Transitive (ℕTotalOrder) (lessRespectsMultiplicationLeft (binNatToN b) (binNatToN a) 2 b<a (le 1 refl)) (le zero refl))))
<BIsInherited (one :: a) (zero :: b) | inl (inl 2a+1<2b) | inr a=b rewrite a=b = exFalso (succNotLess 2a+1<2b)
<BIsInherited (one :: a) (zero :: b) | inl (inr 2b<2a+1) with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
<BIsInherited (one :: a) (zero :: b) | inl (inr 2b<2a+1) | inl (inl a<b) = exFalso (noIntegersBetweenXAndSuccX {2 *N binNatToN b} (2 *N binNatToN a) (lessRespectsMultiplicationLeft (binNatToN a) (binNatToN b) 2 a<b (le 1 refl)) 2b<2a+1)
<BIsInherited (one :: a) (zero :: b) | inl (inr 2b<2a+1) | inl (inr b<a) = equalityCommutative (equalToFirstGreater FirstGreater a b (equalityCommutative indHyp))
  where
    t : a <BInherited b ≡ FirstGreater
    t with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
    t | inl (inl x) = exFalso (TotalOrder.irreflexive (ℕTotalOrder) (TotalOrder.<Transitive (ℕTotalOrder) x b<a))
    t | inl (inr x) = refl
    t | inr x rewrite x = exFalso (TotalOrder.irreflexive (ℕTotalOrder) b<a)
    indHyp : FirstGreater ≡ go<Bcomp Equal a b
    indHyp = transitivity (equalityCommutative t) (<BIsInherited a b)
<BIsInherited (one :: a) (zero :: b) | inl (inr 2b<2a+1) | inr a=b rewrite a=b | canonicalFirst a b FirstGreater | canonicalSecond (canonical a) b FirstGreater | transitivity (equalityCommutative (binToBin a)) (transitivity (applyEquality NToBinNat a=b) (binToBin b)) = equalityCommutative (lemma1 (canonical b))
<BIsInherited (one :: a) (zero :: b) | inr x = exFalso (parity (binNatToN a) (binNatToN b) x)
<BIsInherited (one :: a) (one :: b) = transitivity (chopDouble a b one) (<BIsInherited a b)

_<B_ : BinNat → BinNat → Set
a <B b = (a <Bcomp b) ≡ FirstLess

translate : (a b : BinNat) → (a <B b) → (binNatToN a) <N (binNatToN b)
translate a b a<b with <BIsInherited a b
... | r with TotalOrder.totality ℕTotalOrder (binNatToN a) (binNatToN b)
... | inl (inl x) = x
... | inl (inr x) = exFalso (badCompare'' (transitivity (equalityCommutative a<b) (equalityCommutative r)))
... | inr x = exFalso (badCompare (transitivity r a<b))

private
  totality : (a b : BinNat) → ((a <B b) || (b <B a)) || (canonical a ≡ canonical b)
  totality [] [] = inr refl
  totality [] (zero :: b) with totality [] b
  ... | inl (inl x) = inl (inl x)
  ... | inl (inr x) = inl (inr x)
  ... | inr x with canonical b
  ... | [] = inr refl
  totality [] (one :: b) = inl (inl refl)
  totality (zero :: a) [] with totality a []
  ... | inl (inl x) = inl (inl x)
  ... | inl (inr x) = inl (inr x)
  ... | inr x with canonical a
  ... | [] = inr refl
  totality (zero :: a) (zero :: b) with totality a b
  ... | inl (inl x) = inl (inl x)
  ... | inl (inr x) = inl (inr x)
  ... | inr x rewrite x = inr refl
  totality (zero :: a) (one :: b) with totality a b
  ... | inl (inl x) = inl (inl (equalToFirstLess FirstLess a b x))
  ... | inr x rewrite canonicalSecond a b FirstLess | canonicalFirst a (canonical b) FirstLess | x = inl (inl (lemma1 (canonical b)))
  ... | inl (inr x) with equalToFirstLess FirstGreater b a x
  ... | r = inl (inr r)
  totality (one :: a) [] = inl (inr refl)
  totality (one :: a) (zero :: b) with totality a b
  ... | inr x rewrite canonicalSecond b a FirstLess | canonicalFirst b (canonical a) FirstLess | x = inl (inr (lemma1 (canonical b)))
  ... | inl (inr x) = inl (inr (equalToFirstLess FirstLess b a x))
  ... | inl (inl x) with equalToFirstLess FirstGreater a b x
  ... | r = inl (inl r)
  totality (one :: a) (one :: b) with totality a b
  ... | inl (inl x) = inl (inl x)
  ... | inl (inr x) = inl (inr x)
  ... | inr x rewrite x = inr refl

translate' : (a b : ℕ) → (a <N b) → (NToBinNat a) <B (NToBinNat b)
translate' a b a<b with totality (NToBinNat a) (NToBinNat b)
... | inl (inl x) = x
... | inl (inr x) with translate (NToBinNat b) (NToBinNat a) x
... | m = exFalso (lessIrreflexive (lessTransitive a<b (identityOfIndiscernablesLeft _<N_ (identityOfIndiscernablesRight _<N_ m (nToN a)) (nToN b))))
translate' a b a<b | inr x rewrite NToBinNatInj a b x = exFalso (lessIrreflexive a<b)

private
  <BTransitive : (a b c : BinNat) → (a <B b) → (b <B c) → a <B c
  <BTransitive a b c a<b b<c with translate' (binNatToN a) (binNatToN c) (PartialOrder.<Transitive (TotalOrder.order ℕTotalOrder) (translate a b a<b) (translate b c b<c))
  ... | r rewrite binToBin a | binToBin c = transitivity (canonicalFirst a c Equal) (transitivity (canonicalSecond (canonical a) c Equal) r)

-- This order fails to be total because [] is not literally equal to 0::[] .
BinNatOrder : PartialOrder BinNat
PartialOrder._<_ (BinNatOrder) = _<B_
PartialOrder.irreflexive (BinNatOrder) {x} bad = badCompare (transitivity (equalityCommutative (compareRefl x)) bad)
PartialOrder.<Transitive (BinNatOrder) {a} {b} {c} a<b b<c = <BTransitive a b c a<b b<c


-- Andreas, 2012-03-30
module Issue593 where

import Common.Level
open import Common.Equality
open import Common.Irrelevance

record Unit : Set where
  constructor unit

bla6 : (F : Unit -> Set) ->
  let X : Unit -> Unit -> Set
      X = _
  in (z : Unit) -> X z z ≡ F z
bla6 F z = refl
-- non-linearity for singleton types should not matter

bla7 : (F : Unit -> Set) ->
  let X : Set
      X = _
  in (z : Unit) -> X ≡ F z
bla7 F z = refl
-- should eta expand z to unit

-- * a more involved singleton type:

record R (A : Set) : Set where
  constructor r
  field
    f1 : A -> Unit
    f2 : A

Sing : Set1
Sing = (A : Set) -> A -> R (A -> Unit)

test : (F : Sing -> Set) ->
  let X : Set
      X = _
  in (z : Sing) -> X ≡ F z
test F z = refl

-- * something with irrelevance

Sing' : Set1
Sing' = (A : Set) -> A -> R (Squash A)

test' : (F : Sing' -> Set) ->
  let X : Sing' -> Sing' -> Set
      X = _
  in (z : Sing') -> X z z ≡ F z
test' F z = refl
-- non-linearity should not matter


{-# OPTIONS --cubical #-}

module Multidimensional.Data.Dir.Properties where

open import Cubical.Core.Everything

open import Cubical.Foundations.Prelude

open import Cubical.Data.Empty

open import Cubical.Relation.Nullary

open import Multidimensional.Data.Dir.Base

¬↓≡↑ : ¬ ↓ ≡ ↑
¬↓≡↑ eq = subst (caseDir Dir ⊥) eq ↓

¬↑≡↓ : ¬ ↑ ≡ ↓
¬↑≡↓ eq = subst (caseDir ⊥ Dir) eq ↓


module bool-test where

open import bool
open import eq
open import level

~~tt : ~ ~ tt ≡ tt
~~tt = refl

~~ff : ~ ~ ff ≡ ff
~~ff = refl

~~-elim2 : ∀ (b : 𝔹) → ~ ~ b ≡ b
~~-elim2 tt = ~~tt
~~-elim2 ff = ~~ff

~~tt' : ~ ~ tt ≡ tt
~~tt' = refl{lzero}{𝔹}{tt}

~~ff' : ~ ~ ff ≡ ff
~~ff' = refl{lzero}{𝔹}{ff}

test1 : 𝔹
test1 = tt && ff

test2 : 𝔹
test2 = tt && tt

test1-ff : test1 ≡ ff
test1-ff = refl

test2-tt : test2 ≡ tt
test2-tt = refl


{-

This file contains:

- An implementation of the free group of a type of generators as a HIT

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

module Cubical.HITs.FreeGroup.Base where

open import Cubical.Foundations.Prelude

private
  variable
    ℓ : Level

data FreeGroup (A : Type ℓ) : Type ℓ where
  η     : A → FreeGroup A
  _·_   : FreeGroup A → FreeGroup A → FreeGroup A
  ε     : FreeGroup A
  inv   : FreeGroup A → FreeGroup A
  assoc : ∀ x y z → x · (y · z) ≡ (x · y) · z
  idr   : ∀ x → x ≡ x · ε
  idl   : ∀ x → x ≡ ε · x
  invr  : ∀ x → x · (inv x) ≡ ε
  invl  : ∀ x → (inv x) · x ≡ ε
  trunc : isSet (FreeGroup A)


module SET where
  ----------------------------------------------------------------------------
  -- Auxiliary.
  ----------------------------------------------------------------------------
  data Fun (X Y : Set) : Set where
    fun : (X -> Y) -> Fun X Y

  {-
  Unop : Set -> Set
  Unop X = Fun X X

  Binop : Set -> Set
  Binop X = Fun X (Fun X X)
  -}

  -- We need to replace Pred X by its RHS (less readable!)

--  Pred : Set -> Set1
--  Pred X = X -> Set
--  Pow = Pred
--  Rel : Set -> Set1
--  Rel X = X -> X -> Set
  data Reflexive {X : Set} (R : X -> X -> Set) : Set where
    reflexive : ((x : X) -> R x x) -> Reflexive R

  data Symmetrical {X : Set} (R : X -> X -> Set) : Set where
    symmetrical : ( {x1 x2 : X} -> R x1 x2 -> R x2 x1) -> Symmetrical R
{-
  Transitive {X : Set}(R : X -> X -> Set) : Set
    = (x1 x2 x3 : X) |->  R x1 x2 -> R x2 x3 -> R x1 x3
  Compositional {X : Set}(R : X -> X -> Set) : Set
    = (x1 : X) |-> (x2 : X) |-> (x3 : X) |-> R x2 x3 -> R x1 x2 -> R x1 x3
-}
  data Substitutive {X : Set} (R : X -> X -> Set) : Set1 where
    substitutive : ( (P : X -> Set) -> {x1 x2 : X} -> R x1 x2 -> P x1 -> P x2)
                   -> Substitutive R
{-
  Collapsed (X : Set) : Set1
    = (P : X -> Set) -> (x1 x2 : X) |-> P x1 -> P x2
  id {X : Set} : X -> X
    = \x -> x
  cmp (|X |Y |Z : Set) : (Y -> Z) -> (X -> Y) -> X -> Z
    = \f -> \g -> \x -> f (g x)
  seq (|X |Y |Z : Set)(f : X -> Y)(g : Y -> Z) : X -> Z
    = cmp g f

  const (|X |Y : Set)(x : X)(y : Y) : X
    = x
  proj {X : Set}(Y : X -> Set)(x : X)(f : (x : X) -> Y x) : Y x
    = f x
  flip {X : Set}{Y : Set}{Z : Set}(f : X -> Y -> Z)(y : Y)(x : X) : Z
    = f x y
  FlipRel {X : Set}(R : X -> X -> Set)(x1 : X)(x2 : X) : Set
    = R x2 x1

  ----------------------------------------------------------------------------
  -- Product sets.
  ----------------------------------------------------------------------------
  Prod (X : Set)(Y : X -> Set) : Set
    = (x : X) -> Y x
  mapProd {X : Set}
          {Y1 : X -> Set}
          {Y2 : X -> Set}
          (f : (x : X) -> Y1 x -> Y2 x)
    : Prod X Y1  -> Prod X Y2
    = \g -> \x -> f x (g x)
  -- Fun(X : Set)(Y : Set) = X -> Y
  mapFun (|X1 |X2 |Y1 |Y2 : Set)
    : (X2 -> X1) -> (Y1 -> Y2) -> (X1 -> Y1) -> X2 -> Y2
    = \f -> \g -> \h -> \x ->
      g (h (f x))

  ----------------------------------------------------------------------------
  -- Identity proof sets.
  ----------------------------------------------------------------------------
  Id {X : Set} : X -> X -> Set
    = idata ref (x : X) : _ x x
  refId {X : Set} : Reflexive Id
    = \(x : X) -> ref@_  x

  elimId (|X : Set)
         (C : (x1 x2 : X)  |-> Id x1 x2 -> Set)
         (refC :  (x : X) -> C (refId x))
         (|x1 |x2 : X)
         (u : Id x1 x2) :
         C u
    = case u of { (ref x) -> refC x;}

  abstract whenId {X : Set}(C : X -> X -> Set)(c : (x : X) -> C x x)
    : (x1 x2 : X)  |-> Id x1 x2 -> C x1 x2
    = elimId (\x1 x2 |-> \(u : Id x1 x2) -> C x1 x2) c

  abstract substId {X : Set} : Substitutive Id
    = \(C : X -> Set) ->
      whenId (\x1 x2 -> C x1 -> C x2) (\x -> id)

  abstract mapId {X : Set}{Y : Set}(f : X -> Y)
    : (x1 x2 : X) |-> Id x1 x2 -> Id (f x1) (f x2)
    = whenId (\x1 x2 -> Id (f x1) (f x2)) (\(x : X) -> refId (f x))

  abstract symId {X : Set} : Symmetrical Id
    =  whenId (\(x1 x2 : X) ->  Id x2 x1) refId

  abstract cmpId {X : Set} : Compositional Id
    = let lem : (x y : X) |-> Id x y -> (z : X) |-> Id z x -> Id z y
            = whenId ( \(x y : _) -> (z : X) |-> Id z x -> Id z y)
                     ( \x -> \z |-> id)
      in  \(x1 x2 x3 : _) |->
          \(u : Id x2 x3) ->
          \(v : Id x1 x2) ->
          lem  u v

  abstract tranId {X : Set} : Transitive  Id
    = \(x1 x2 x3 : X) |->
      \(u : Id x1 x2) ->
      \(v : Id x2 x3) ->
      cmpId v u

  ----------------------------------------------------------------------------
  -- The empty set.
  ----------------------------------------------------------------------------
-}
  data Zero : Set where

{-
  abstract whenZero (X : Set)(z : Zero) : X
    = case z of { }
  elimZero (C : Zero -> Set)(z : Zero) : C z
    = case z of { }
  abstract collZero : Collapsed Zero
    = \(C : Zero -> Set) ->
      \(z1 z2 : Zero) |->
      \(c : C z1) ->
      case z1 of { }
  ----------------------------------------------------------------------------
  -- The singleton set.
  ----------------------------------------------------------------------------
-}
  data Unit : Set where
    unit : Unit
{-
  elUnit = tt
  elimUnit (C : Unit -> Set)(c_tt : C tt@_)(u : Unit) : C u
    = case u of { (tt) -> c_tt;}
  abstract collUnit : Collapsed Unit
    = \(C : Unit -> Set) ->
      \(u1 u2 : Unit) |->
      \(c : C u1) ->
      case u1 of { (tt) -> case u2 of { (tt) -> c;};}
  ----------------------------------------------------------------------------
  -- The successor set adds a new element.
  ----------------------------------------------------------------------------

  Succ (X : Set) : Set
    = data zer | suc (x : X)
  zerSucc {X : Set} : Succ X
    = zer@_
  sucSucc {X : Set}(x : X) : Succ X
    = suc@_ x
  elimSucc {X : Set}
           (C : Succ X -> Set)
           (c_z : C zer@_)
           (c_s : (x : X) -> C (suc@_ x))
           (x' : Succ X)
    : C x'
    = case x' of {
        (zer) -> c_z;
        (suc x) -> c_s x;}
  whenSucc (|X |Y : Set)(y_z : Y)(y_s : X -> Y)(x' : Succ X) : Y
    = case x' of {
        (zer) -> y_z;
        (suc x) -> y_s x;}
  mapSucc (|X |Y : Set)(f : X -> Y) : Succ X -> Succ Y
    = whenSucc zer@(Succ Y) (\(x : X) -> suc@_ (f x)) -- (Succ Y)

  ----------------------------------------------------------------------------
  -- The (binary) disjoint union.
  ----------------------------------------------------------------------------
  data Plus (X Y : Set) = inl (x : X) | inr (y : Y)

  elimPlus (|X |Y : Set)
           (C : Plus X Y -> Set)
           (c_lft : (x : X) -> C (inl@_ x))
           (c_rgt : (y : Y) -> C (inr@_ y))
           (xy : Plus X Y)
    : C xy
    = case xy of {
        (inl x) -> c_lft x;
        (inr y) -> c_rgt y;}
  when (|X |Y |Z : Set)(f : X -> Z)(g : Y -> Z) : Plus X Y -> Z
    = \xy -> case xy of {
        (inl x) -> f x;
        (inr y) -> g y;}
  whenPlus = when
  mapPlus (|X1 |X2 |Y1 |Y2 : Set)(f : X1 -> X2)(g : Y1 -> Y2)
    : Plus X1 Y1 -> Plus X2 Y2
    = when (\x1 -> inl (f x1)) (\y1 -> inr (g y1))
  swapPlus (|X |Y : Set) :  Plus X Y -> Plus Y X
    = when inr inl

  ----------------------------------------------------------------------------
  -- Dependent pairs.
  ----------------------------------------------------------------------------
  Sum (X : Set)(Y : X -> Set) : Set
    = sig{fst : X;
          snd : Y fst;}
  dep_pair {X : Set}{Y : X -> Set}(x : X)(y : Y x) : Sum X Y
    = struct {fst = x; snd = y;}
  dep_fst {X : Set}{Y : X -> Set}(xy : Sum X Y) : X
    = xy.fst
  dep_snd {X : Set}{Y : X -> Set}(xy : Sum X Y) : Y (dep_fst xy)
    = xy.snd
  dep_cur {X : Set}{Y : X -> Set}{Z : Set}(f : Sum X Y -> Z)
    : (x : X) |-> Y x -> Z
    = \x |-> \y ->  f (dep_pair  x  y)

  dep_uncur {X : Set}{Y : X -> Set}{Z : Set}
    : ((x : X) -> Y x -> Z) -> Sum X Y -> Z
    = \(f : (x : X) -> (x' : Y x) -> Z) -> \(xy : Sum X Y) -> f xy.fst xy.snd
  dep_curry {X : Set}
            {Y : X -> Set}
            (Z : Sum X Y -> Set)
            (f : (xy : Sum X Y) -> Z xy)
    : (x : X) ->  (y : Y x) -> Z (dep_pair x y)
    = \(x : X) -> \(y : Y x) -> f (dep_pair x y)

  dep_uncurry {X : Set}
              {Y : X -> Set}
              (Z : Sum X Y -> Set)
              (f : (x : X) ->
                  (y : Y x) ->
                  Z (dep_pair x y))
              (xy : Sum X Y)
    : Z xy
    = f xy.fst xy.snd
  mapSum {X : Set}{Y1 : X -> Set}{Y2 : X -> Set}(f : (x : X) -> Y1 x -> Y2 x)
    : Sum X Y1 -> Sum X Y2
    = \(p : Sum X Y1) -> dep_pair p.fst (f p.fst p.snd)

  elimSum = dep_uncurry
  ----------------------------------------------------------------------------
  -- Nondependent pairs (binary) cartesian product.
  ----------------------------------------------------------------------------
  Times (X : Set)(Y : Set) : Set
    = Sum X (\(x : X) -> Y)
  pair {X : Set}{Y : Set} : X -> Y -> Times X Y
    = \(x : X) ->
      \(y : Y) ->
      struct {
        fst = x;
        snd = y;}
  fst {X : Set}{Y : Set} : Times X Y -> X
    = \(xy : Times X Y) -> xy.fst
  snd {X : Set}{Y : Set} : Times X Y -> Y
    = \(xy : Times X Y) -> xy.snd
  pairfun {X : Set}{Y : Set}{Z : Set}(f : X -> Y)(g : X -> Z)(x : X)
    : Times Y Z
    = pair (f x) (g x)
  mapTimes {X1 : Set}{X2 : Set}{Y1 : Set}{Y2 : Set}
    : (f : X1 -> X2) -> (g : Y1 -> Y2) -> Times X1 Y1 -> Times X2 Y2
    = \(f : (x : X1) -> X2) ->
      \(g : (x : Y1) -> Y2) ->
      \(xy : Times X1 Y1) ->
      pair (f xy.fst) (g xy.snd)
  swapTimes {X : Set}{Y : Set} : Times X Y -> Times Y X
    = pairfun snd fst
  cur {X : Set}{Y : Set}{Z : Set}(f : Times X Y -> Z) : X -> Y -> Z
    = \(x : X) -> \(y : Y) -> f (pair |_ |_ x y)
  uncur {X : Set}{Y : Set}{Z : Set}(f : X -> Y -> Z) : Times X Y -> Z
    = \(xy : Times X Y) -> f xy.fst xy.snd
  curry {X : Set}
        {Y : Set}
        {Z : Times X Y -> Set}
        (f : (xy : Times X Y) -> Z xy)
    : (x : X) ->
       (y : Y) ->
       Z (pair |_ |_ x y)
    = \(x : X) ->
      \(y : Y) ->
      f (pair |_ |_ x y)

  uncurry {X : Set}
          {Y : Set}
          {Z : Times X Y -> Set}
          (f : (x : X) ->
              (y : Y) ->
              Z (pair |_ |_ x y))
    : (xy : Times X Y) -> Z xy
    = \(xy : Times X Y) -> f xy.fst xy.snd

  elimTimes = uncurry
  ----------------------------------------------------------------------------
  -- Natural numbers.
  ----------------------------------------------------------------------------
  Nat : Set
    = data zer | suc (m : Nat)
  zero : Nat
    = zer@_
  succ (x : Nat) : Nat
    = suc@_ x
  elimNat (C : Nat -> Set)
    : (c_z : C zer@_) ->
       (c_s : (x : Nat) -> C x -> C (suc@_ x)) ->
       (m : Nat) ->
       C m
    = \(c_z : C zer@_) ->
      \(c_s : (x : Nat) -> (x' : C x) -> C (suc@_ x)) ->
      \(m : Nat) ->
      case m of {
        (zer) -> c_z;
        (suc m') -> c_s m' (elimNat C c_z c_s m');}
  ----------------------------------------------------------------------------
  -- Linear universe of finite sets.
  ----------------------------------------------------------------------------
  Fin (m : Nat) : Set
    = case m of {
        (zer) -> Zero;
        (suc m') -> Succ (Fin m');}
  valFin (m : Nat) : Fin m -> Nat
    = \(n : Fin m) ->
      case m of {
        (zer) -> case n of { };
        (suc m') ->
          case n of {
            (zer) -> zer@_;
            (suc n') -> suc@_ (valFin m' n');};}
  zeroFin (m : Nat) : Fin (succ m)
    = zer@_
  succFin (m : Nat)(n : Fin m) : Fin (succ m)
    = suc@_ n
  ----------------------------------------------------------------------------
  -- Do these really belong here?
  ----------------------------------------------------------------------------
  HEAD (X : Set1)(m : Nat)(f : Fin (succ m) -> X) : X
    = f (zeroFin m)
  TAIL (X : Set1)(m : Nat)(f : Fin (succ m) -> X) : Fin m -> X
    = \(n : Fin m) -> f (succFin m n)
  ----------------------------------------------------------------------------
  -- Lists.
  ----------------------------------------------------------------------------
  List (X : Set) : Set
    = data nil | con (x : X) (xs : List X)
  nil {X : Set} : List X
    = nil@_
  con {X : Set}(x : X)(xs : List X) : List X
    = con@_ x xs
  elimList {X : Set}
           (C : List X -> Set)
           (c_nil : C (nil |_))
           (c_con : (x : X) -> (xs : List X) -> C xs -> C (con@_ x xs))
           (xs : List X)
    : C xs
    = case xs of {
        (nil) -> c_nil;
        (con x xs') -> c_con x xs' (elimList |_ C c_nil c_con xs');}
  ----------------------------------------------------------------------------
  -- Tuples are "dependently typed vectors".
  ----------------------------------------------------------------------------
  Nil : Set
    = data nil
  Con (X0 : Set)(X' : Set) : Set
    = data con (x : X0) (xs : X')
  Tuple (m : Nat)(X : Fin m -> Set) : Set
    = case m of {
        (zer) -> Nil;
        (suc m') -> Con (X zer@_) (Tuple m' (\(n : Fin m') -> X (suc@_ n)));}
  ----------------------------------------------------------------------------
  -- Vectors homogeneously typed tuples.
  ----------------------------------------------------------------------------
  Vec (X : Set)(m : Nat) : Set
    = Tuple m (\(n : Fin m) -> X)
  ----------------------------------------------------------------------------
  -- Monoidal expressions.
  ----------------------------------------------------------------------------
  Mon (X : Set) : Set
    = data unit | at (x : X) | mul (xs1 : Mon X) (xs2 : Mon X)
  ----------------------------------------------------------------------------
  -- Propositions.
  ----------------------------------------------------------------------------
  Imply (X : Set)(Y : Set) : Set
    = X -> Y
-}
  Absurd : Set
  Absurd = Zero
  Taut : Set
  Taut = Unit
{-
  Not (X : Set) : Set
    = X -> Absurd
  Exist {X : Set}(P : X -> Set) : Set
    = Sum X P
  Forall (X : Set)(P : X -> Set) : Set
    = (x : X) -> P x
  And (X : Set)(Y : Set) : Set
    = Times X Y
  Iff (X : Set)(Y : Set) : Set
    = And (Imply X Y) (Imply Y X)
  Or (X : Set)(Y : Set) : Set
    = Plus X Y
  Decidable (X : Set) : Set
    = Or X (Imply X Absurd)
  DecidablePred {X : Set}(P : X -> Set) : Set
    = (x : X) -> Decidable (P x)
  DecidableRel {X : Set}(R : X -> X -> Set) : Set
    = (x1 : X) -> (x2 : X) -> Decidable (R x1 x2)
  Least {X : Set}((<=) : X -> X -> Set)(P : X -> Set) : X -> Set
    = \(x : X) -> And (P x) ((x' : X) -> P x' -> (x <= x'))
  Greatest {X : Set}((<=) : X -> X -> Set)(P : X -> Set) : X -> Set
    = \(x : X) -> And (P x) ((x' : X) -> P x' -> (x' <= x))
  ----------------------------------------------------------------------------
  -- Booleans.
  ----------------------------------------------------------------------------
-}
  data Bool : Set where
    true  : Bool
    false : Bool
{-
  elimBool (C : Bool -> Set)(c_t : C true@_)(c_f : C false@_)(p : Bool)
    : C p
    = case p of {
        (true) -> c_t;
        (false) -> c_f;}
  whenBool (C : Set)(c_t : C)(c_f : C) : Bool -> C
    = elimBool (\(x : Bool) -> C) c_t c_f
  pred (X : Set) : Set
    = X -> Bool
-}
--  rel (X : Set) : Set
--    = X -> X -> Bool
  True : Bool -> Set
  True (true)  = Taut
  True (false) = Absurd
{-
  bool2set = True
  pred2Pred {X : Set} : pred X -> X -> Set
    = \(p : pred X) -> \(x : X) -> True (p x)
  rel2Rel {X : Set} : (X -> X -> Bool) -> X -> X -> Set
    = \(r : (X -> X -> Bool)) -> \(x : X) -> \(y : X) -> True (r x y)
  decTrue (p : Bool) : Decidable (True p)
    = case p of {
        (true) -> inl@_ tt;
        (false) -> inr@_ (id |_);}
  abstract dec_lem {P : Set}(decP : Decidable P)
    : Exist |_ (\(b : Bool) -> Iff (True b) P)
    = case decP of {
        (inl trueP) ->
          struct {
            fst = true@_;
            snd =
              struct {
                fst = const |_  |_ trueP;  -- (True true@_)
                snd = const |_ |_  tt;};};
        (inr notP) ->
          struct {
            fst = false@_;
            snd =
              struct {
                fst = whenZero P;
                snd = notP;};};}
  dec2bool : (P : Set) |-> (decP : Decidable P) -> Bool
    = \(P : Set) |-> \(decP : Decidable P) -> (dec_lem |_ decP).fst
  dec2bool_spec {P : Set}(decP : Decidable P)
    : Iff (True (dec2bool |_ decP)) P
    = (dec_lem |_ decP).snd

  abstract collTrue : (b : Bool) -> Collapsed (True b)
    = let aux (X : Set)(C : X -> Set)
            : (b : Bool) ->
               (f : True b -> X) ->
               (t1 : True b) |->
               (t2 : True b) |->
               C (f t1) -> C (f t2)
            = \(b : Bool) ->
              case b of {
                (true) ->
                  \(f : (x : True true@_) -> X) ->
                  \(t1 t2 : True true@_) |->
                  \(c : C (f t1)) ->
                  case t1 of { (tt) -> case t2 of { (tt) -> c;};};
                (false) ->
                  \(f : (x : True false@_) -> X) ->
                  \(t1 t2 : True false@_) |->
                  \(c : C (f t1)) ->
                  case t1 of { };}
      in   \(b : Bool) ->  \(P : True b -> Set) -> aux (True b) P b id

  bool2nat (p : Bool) : Nat
    = case p of {
        (true) -> succ zero;
        (false) -> zero;}
  ----------------------------------------------------------------------------
  -- Decidable subsets.
  ----------------------------------------------------------------------------
  Filter {X : Set}(p : pred X) : Set
    = Sum X (pred2Pred |_ p)
  ----------------------------------------------------------------------------
  -- Equality.
  ----------------------------------------------------------------------------
  -- "Deq" stands for "datoid equality" and represents exactly the data
  --  that has to be added to turn a set into a datoid.
  Deq (X : Set) : Set1
    = sig{eq : X -> X -> Bool;
          ref : (x : X) -> True (eq x x);
          subst :
            (C : X -> Set) -> (x1 x2 : X)|-> True (eq x1 x2) -> C x1 -> C x2;}
  -- The "Equality" type represents the data that has to be added to turna
  -- set into a setoid.
  Equality (X : Set) : Set1
    = sig{Equal : X -> X -> Set;
          ref  : Reflexive |_ Equal;
          sym  : Symmetrical |_ Equal;
          tran : Transitive |_ Equal;}
  -}
  data Datoid  : Set1 where
    datoid : (Elem : Set) ->
             (eq : Elem -> Elem -> Bool) ->
             (ref :  (x : Elem) -> True (eq x x)) ->
             (subst : Substitutive  (\x1 -> \x2 -> True (eq x1 x2))) ->
             Datoid

  pElem : Datoid -> Set
  pElem (datoid Elem _ _ _) = Elem

  {-
  ElD (X : Datoid) : Set
    = X.Elem
  eqD {X : Datoid} : ElD X -> ElD X -> Bool
    = X.eq
  EqD {X : Datoid}(x1 x2 : ElD X) : Set
    = True (X.eq x1 x2)

  Setoid : Set1
    = sig{Elem : Set;
          Equal : Elem -> Elem -> Set;
          ref : (x : Elem) -> Equal x x;
          sym : (x1 : Elem) |-> (x2 : Elem) |-> Equal x1 x2 -> Equal x2 x1;
          tran :
            (x1 : Elem) |->
            (x2 : Elem) |->
            (x3 : Elem) |->
            Equal x1 x2 -> Equal x2 x3 -> Equal x1 x3;}
  El (X : Setoid) : Set
    = X.Elem
  Eq {X : Setoid} : Rel (El X)
    = X.Equal

  NotEq {X : Setoid} : Rel (El X)
    = \x1-> \x2-> Not (Eq |X x1 x2)
  Respectable {X : Setoid}(P : El X -> Set) : Set
    = (x1 x2 : El X) |-> Eq |X x1 x2 -> P x1 -> P x2
  RspEq {X Y : Setoid}(f : El X -> El Y) : Set
    = (x1 x2 : El X)  |-> Eq |X x1 x2 -> Eq |Y (f x1) (f x2)
  RspEq2 (|X |Y |Z : Setoid)(f : El X -> El Y -> El Z)
    : Set
    = (x1 x2 :  X.Elem) |-> (y1 y2 :  Y.Elem) ->
      Eq |X x1 x2 ->
      Eq |Y y1 y2  ->
      Eq |Z (f x1 y1) (f x2 y2)
  D2S (Y : Datoid) : Setoid
    = struct {
        Elem = Y.Elem;
        Equal = \(x1 x2 : Elem) -> True (Y.eq x1 x2);
        ref = Y.ref;
        sym =
          \(x1 x2 : Elem) |->
          \(u : Equal x1 x2) ->
          Y.subst (\(x : Y.Elem) -> Equal x x1) |_ |_ u (ref x1);
        tran =
          \(x1 x2 x3 : Elem) |->
          \(u : Equal x1 x2) ->
          \(v : Equal x2 x3) ->
          Y.subst (Equal x1) |_ |_  v u;}

{-# Alfa unfoldgoals off
brief on
hidetypeannots off
wide
nd
hiding on
con "nil" as "[]" with symbolfont
con "con" infix as " : " with symbolfont
var "Forall" as "\"" with symbolfont
var "Exist" as "$" with symbolfont
var "And" infix as "&" with symbolfont
var "Or" infix as "Ú" with symbolfont
var "Iff" infix as "«" with symbolfont
var "Not" as "Ø" with symbolfont
var "Imply" infix as "É" with symbolfont
var "Taut" as "T" with symbolfont
var "Absurd" as "^" with symbolfont
var "El" mixfix as "|_|" with symbolfont
var "Eq" distfix3 as "==" with symbolfont
var "NotEq" distfix3 as "=|=" with symbolfont
var "True" mixfix as "|_|" with symbolfont
var "ElD" mixfix as "|_|" with symbolfont
var "EqD" distfix3 as "==" with symbolfont
var "Id" distfix3 as "=" with symbolfont
 #-}
-}


module CS410-Functor where

open import CS410-Prelude

record Functor (T : Set -> Set) : Set1 where
  field
    -- OPERATIONS ----------------------------------------------
    map     : forall {X Y} -> (X -> Y) -> T X -> T Y
    -- LAWS ----------------------------------------------------
    mapid   : forall {X}(x : T X) -> map id x == x
    mapcomp : forall {X Y Z}(f : Y -> Z)(g : X -> Y)(x : T X) ->
              map (f o g) x == map f (map g x)

record Applicative (T : Set -> Set) : Set1 where
  field
    -- OPERATIONS ----------------------------------------------
    pure         : forall {X} -> X -> T X
    _<*>_        : forall {X Y} -> T (X -> Y) -> T X -> T Y
    -- LAWS ----------------------------------------------------
    identity     : forall {X}(v : T X) ->

                      pure id <*> v == v

    composition  : forall {X Y Z}(u : T (Y -> Z))(v : T (X -> Y))(w : T X) ->

                      pure (\ f g x -> f (g x)) <*> u <*> v <*> w == u <*> (v <*> w)

    homomorphism : forall {X Y}(f : X -> Y)(x : X) ->

                      pure (f x) == pure f <*> pure x

    interchange  : forall {X Y}(u : T (X -> Y))(y : X) ->

                      u <*> pure y == pure (\ f -> f y) <*> u

  infixl 10 _<*>_

App2Fun : {T : Set -> Set} -> Applicative T -> Functor T
App2Fun {T} app = record {
  map     = \ f x -> pure f <*> x;
  mapid   = identity;
  mapcomp = lem}
  where
    open Applicative app
    lem : forall {X Y Z}(f : Y -> Z)(g : X -> Y)(x : T X) ->
          pure (\ x -> f (g x)) <*> x == pure f <*> (pure g <*> x)
    lem {X}{Y}{Z} f g x rewrite
        (sym (composition (pure f) (pure g) x))
      | (sym (homomorphism (\ (f : Y -> Z)(g : X -> Y) x -> f (g x)) f))
      | (sym (homomorphism (\ (g : X -> Y) x -> f (g x)) g))
      = refl

record Traversable (T : Set -> Set) : Set1 where
  field
    -- OPERATIONS ----------------------------------------------
    traverse  : forall {F} -> Applicative F ->
                forall {A B} -> (A -> F B) -> T A -> F (T B)
    -- LAWS ----------------------------------------------------
    -- maybe later

record Monad (T : Set -> Set) : Set1 where
  field
    -- OPERATIONS ----------------------------------------------
    return       : forall {X} -> X -> T X
    _>>=_        : forall {X Y} -> T X -> (X -> T Y) -> T Y
    -- LAWS ----------------------------------------------------
    law1 : forall {X Y}(x : X)(f : X -> T Y) -> return x >>= f == f x
    law2 : forall {X}(t : T X) -> t >>= return == t
    law3 : forall {X Y Z}(f : X -> T Y)(g : Y -> T Z)(t : T X) ->
           (t >>= f) >>= g == t >>= (\ x -> f x >>= g)
  -- DERIVED OPERATIONS
  _<=<_ : {X Y Z : Set} -> (Y -> T Z) -> (X -> T Y) -> (X -> T Z)
  (f <=< g) x = g x >>= f

  infixr 5 _>>=_

record Monad-Alg {T : Set -> Set}(M : Monad T) : Set1 where
  field
    -- OPERATIONS ----------------------------------------------
    A : Set
    A-map : forall {X} -> (X -> A) -> T X -> A
  open Monad M
     -- LAWS ----------------------------------------------------
  field
    A-law1 : forall {X}(f : X -> A)(x : X) -> A-map f (return x) == f x
    A-law2 : forall {X Y}(g : X -> T Y)(f : Y -> A)(t : T X) ->
             A-map (A-map f o g) t == A-map f (t >>= g)


record Additive {ℓ} (A : Set ℓ) : Set ℓ where
  field
    zero : A
    _+_ : A → A → A

open Additive {{...}} public

record Subtractive {ℓ} (A : Set ℓ) {{ADD : Additive A}} : Set ℓ where
  field
    _-_ : A → A → A

  neg : A → A
  neg x = zero - x

open Subtractive {{...}} public

check : ∀ ℓ (A : Set ℓ) (ADD : Additive A) (SUB : Subtractive A {{ADD}}) → A → A
check ℓ A ADD SUB x = Subtractive.neg {ℓ} {A} {{ADD}} SUB x


------------------------------------------------------------------------
-- Injections
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

open import Equality

module Injection
  {reflexive} (eq : ∀ {a p} → Equality-with-J a p reflexive) where

open Derived-definitions-and-properties eq
open import Prelude as P hiding (id) renaming (_∘_ to _⊚_)

------------------------------------------------------------------------
-- Injections

-- The property of being injective.

Injective : ∀ {a b} {A : Type a} {B : Type b} → (A → B) → Type (a ⊔ b)
Injective f = ∀ {x y} → f x ≡ f y → x ≡ y

infix 0 _↣_

-- Injections.

record _↣_ {f t} (From : Type f) (To : Type t) : Type (f ⊔ t) where
  field
    to        : From → To
    injective : Injective to

------------------------------------------------------------------------
-- Preorder

-- _↣_ is a preorder.

id : ∀ {a} {A : Type a} → A ↣ A
id = record
  { to        = P.id
  ; injective = P.id
  }

infixr 9 _∘_

_∘_ : ∀ {a b c} {A : Type a} {B : Type b} {C : Type c} →
      B ↣ C → A ↣ B → A ↣ C
f ∘ g = record
  { to        = to′
  ; injective = injective′
  }
  where
  open _↣_

  to′ = to f ⊚ to g

  injective′ : Injective to′
  injective′ = injective g ⊚ injective f

-- "Equational" reasoning combinators.

infix  -1 finally-↣
infixr -2 step-↣

-- For an explanation of why step-↣ is defined in this way, see
-- Equality.step-≡.

step-↣ : ∀ {a b c} (A : Type a) {B : Type b} {C : Type c} →
         B ↣ C → A ↣ B → A ↣ C
step-↣ _ = _∘_

syntax step-↣ A B↣C A↣B = A ↣⟨ A↣B ⟩ B↣C

finally-↣ : ∀ {a b} (A : Type a) (B : Type b) → A ↣ B → A ↣ B
finally-↣ _ _ A↣B = A↣B

syntax finally-↣ A B A↣B = A ↣⟨ A↣B ⟩□ B □