------------------------------------------------------------------------
-- Morphisms between algebraic structures
------------------------------------------------------------------------

module Algebra.Morphism where

open import Relation.Binary
open import Algebra
open import Algebra.FunctionProperties
open import Data.Function

------------------------------------------------------------------------
-- Basic definitions

module Definitions (From To : Set) (_≈_ : Rel To) where
  Morphism : Set
  Morphism = From → To

  Homomorphic₀ : Morphism → From → To → Set
  Homomorphic₀ ⟦_⟧ ∙ ∘ = ⟦ ∙ ⟧ ≈ ∘

  Homomorphic₁ : Morphism → Fun₁ From → Op₁ To → Set
  Homomorphic₁ ⟦_⟧ ∙_ ∘_ = ∀ x → ⟦ ∙ x ⟧ ≈ ∘ ⟦ x ⟧

  Homomorphic₂ : Morphism → Fun₂ From → Op₂ To → Set
  Homomorphic₂ ⟦_⟧ _∙_ _∘_ =
    ∀ x y → ⟦ x ∙ y ⟧ ≈ (⟦ x ⟧ ∘ ⟦ y ⟧)

------------------------------------------------------------------------
-- Some specific morphisms

-- Other morphisms could of course be defined.

record _-RawRing⟶_ (From To : RawRing) : Set where
  open RawRing
  open Definitions (carrier From) (carrier To) (_≈_ To)
  field
    ⟦_⟧    : Morphism
    +-homo : Homomorphic₂ ⟦_⟧ (_+_ From) (_+_ To)
    *-homo : Homomorphic₂ ⟦_⟧ (_*_ From) (_*_ To)
    -‿homo : Homomorphic₁ ⟦_⟧ (-_  From) (-_  To)
    0-homo : Homomorphic₀ ⟦_⟧ (0#  From) (0#  To)
    1-homo : Homomorphic₀ ⟦_⟧ (1#  From) (1#  To)

_-Ring⟶_ : Ring → Ring → Set
From -Ring⟶ To = rawRing From -RawRing⟶ rawRing To
  where open Ring


{-# OPTIONS --without-K #-}
module equality.core where

open import sum
open import level using ()
open import function.core

infix 4 _≡_

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

sym : ∀ {i} {A : Set i} {x y : A}
    → x ≡ y → y ≡ x
sym refl = refl

_·_ : ∀ {i}{X : Set i}{x y z : X}
    → x ≡ y → y ≡ z → x ≡ z
refl · p = p
infixl 9 _·_

ap : ∀ {i j}{A : Set i}{B : Set j}{x y : A}
     → (f : A → B) → x ≡ y → f x ≡ f y
ap f refl = refl

ap₂ : ∀ {i j k}{A : Set i}{B : Set j}{C : Set k}
        {x x' : A}{y y' : B}
      → (f : A → B → C)
      → x ≡ x' → y ≡ y' → f x y ≡ f x' y'
ap₂ f refl refl = refl

subst : ∀ {i j} {A : Set i}{x y : A}
      → (B : A → Set j) → x ≡ y
      → B x → B y
subst B refl = id

subst₂ : ∀ {i j k} {A : Set i}{x x' : A}
         {B : Set j}{y y' : B}
       → (C : A → B → Set k)
       → x ≡ x' → y ≡ y'
       → C x y → C x' y'
subst₂ C refl refl = id

singleton : ∀ {i}{A : Set i} → A → Set i
singleton {A = A} a = Σ A λ a' → a ≡ a'

singleton' : ∀ {i}{A : Set i} → A → Set i
singleton' {A = A} a = Σ A λ a' → a' ≡ a

J' : ∀ {i j}{X : Set i}{x : X}
   → (P : (y : X) → x ≡ y → Set j)
   → P x refl
   → (y : X)
   → (p : x ≡ y)
   → P y p
J' P u y refl = u

J : ∀ {i j}{X : Set i}
  → (P : (x y : X) → x ≡ y → Set j)
  → ((x : X) → P x x refl)
  → (x y : X)
  → (p : x ≡ y)
  → P x y p
J P u x y p = J' (P x) (u x) y p


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

module Categories.Functor.Groupoid where

open import Level

open import Categories.Category
open import Categories.Category.Groupoid using (Groupoid; IsGroupoid)
open import Categories.Functor
import Categories.Morphism.Reasoning as MR

private
  variable
    o ℓ e : Level
    C D : Category o ℓ e

-- functor respects groupoid inverse
module _ (GC : IsGroupoid C) (GD : IsGroupoid D) (F : Functor C D) where
  private
    module C = IsGroupoid GC
    module D = IsGroupoid GD
    open Functor F
    open D
    open HomReasoning
    open MR D

  F-resp-inv : ∀ {A B} (f : A C.⇒ B) → F₁ (f C.⁻¹) ≈ (F₁ f) ⁻¹
  F-resp-inv f = begin
    F₁ (f C.⁻¹)                      ≈⟨ introˡ D.iso.isoˡ ⟩
    ((F₁ f) ⁻¹ ∘ F₁ f) ∘ F₁ (f C.⁻¹) ≈˘⟨ pushʳ homomorphism ⟩
    (F₁ f) ⁻¹ ∘ F₁ (f C.∘ f C.⁻¹)    ≈⟨ elimʳ (F-resp-≈ C.iso.isoʳ ○ identity) ⟩
    (F₁ f) ⁻¹                        ∎

-- Nevertheless, create a |GrFunctor| that is typed over Groupoid instead of Category
GrFunctor : (A B : Groupoid o ℓ e) → Set _
GrFunctor A B = Functor (category A) (category B)
  where open Groupoid


------------------------------------------------------------------------
-- Data and codata can sometimes be "unified"
------------------------------------------------------------------------

-- In Haskell one can define the partial list type once, and define
-- map once and for all for this type. In Agda one typically defines
-- the (finite) list type + map and separately the (potentially
-- infinite) colist type + map. This is not strictly necessary,
-- though: the two types can be unified. The gain may be small,
-- though.

module DataAndCodata where

open import Codata.Musical.Notation
open import Function
open import Relation.Binary.PropositionalEquality

------------------------------------------------------------------------
-- Conditional coinduction

data Rec : Set where
  μ : Rec
  ν : Rec

∞? : Rec → Set → Set
∞? μ = id
∞? ν = ∞

♯? : ∀ (r : Rec) {A} → A → ∞? r A
♯? μ x = x
♯? ν x = ♯ x

♭? : ∀ (r : Rec) {A} → ∞? r A → A
♭? μ = id
♭? ν = ♭

------------------------------------------------------------------------
-- A type for definitely finite or potentially infinite lists

-- If the Rec parameter is μ, then the type contains finite lists, and
-- otherwise it contains potentially infinite lists.

infixr 5 _∷_

data List∞? (r : Rec) (A : Set) : Set where
  []  : List∞? r A
  _∷_ : A → ∞? r (List∞? r A) → List∞? r A

-- List equality.

infix 4 _≈_

data _≈_ {r A} : List∞? r A → List∞? r A → Set where
  []  : [] ≈ []
  _∷_ : ∀ {x y xs ys} →
        x ≡ y → ∞? r (♭? r xs ≈ ♭? r ys) → x ∷ xs ≈ y ∷ ys

-- μ-lists can be seen as ν-lists.

lift : ∀ {A} → List∞? μ A → List∞? ν A
lift []       = []
lift (x ∷ xs) = x ∷ ♯ lift xs

------------------------------------------------------------------------
-- The map function

-- Maps over any list. The definition contains separate cases for _∷_
-- depending on whether the Rec index is μ or ν, though.

map : ∀ {r A B} → (A → B) → List∞? r A → List∞? r B
map     f []       = []
map {μ} f (x ∷ xs) = f x ∷ map f xs        -- Structural recursion
                                           -- (guarded).
map {ν} f (x ∷ xs) = f x ∷ ♯ map f (♭ xs)  -- Guarded corecursion.

-- In Haskell the map function is automatically (in effect) parametric
-- in the Rec parameter. Here this property is not automatic, so I
-- have proved it manually:

map-parametric : ∀ {A B} (f : A → B) (xs : List∞? μ A) →
                 map f (lift xs) ≈ lift (map f xs)
map-parametric f []       = []
map-parametric f (x ∷ xs) = refl ∷ ♯ map-parametric f xs


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

open import Categories.Category using (Category)

-- Defines the following properties of a Category:
-- Cartesian -- a Cartesian category is a category with all products

--  (for the induced Monoidal structure, see Cartesian.Monoidal)

module Categories.Category.Cartesian {o ℓ e} (𝒞 : Category o ℓ e) where

open import Level using (levelOfTerm)
open import Data.Nat using (ℕ; zero; suc)

open Category 𝒞
open HomReasoning

open import Categories.Category.BinaryProducts 𝒞 using (BinaryProducts; module BinaryProducts)
open import Categories.Object.Terminal 𝒞 using (Terminal)

private
  variable
    A B C D W X Y Z : Obj
    f f′ g g′ h i : A ⇒ B

-- Cartesian monoidal category
record Cartesian : Set (levelOfTerm 𝒞) where
  field
    terminal : Terminal
    products : BinaryProducts
  open BinaryProducts products using (_×_)

  power : Obj → ℕ → Obj
  power A 0 = Terminal.⊤ terminal
  power A 1 = A
  power A (suc (suc n)) = A × power A (suc n)


{-# OPTIONS -WUnknownFixityInMixfixDecl #-}

data Nat : Set where
  zero : Nat
  suc : Nat → Nat

_+_ : Nat → Nat → Nat
zero + n = n
(suc m) + n = suc (m + n)

private
  _*_ : Nat → Nat → Nat
  zero    * n = zero
  (suc m) * n = n + (m * n)

data List (A : Set) : Set where
  [] : List A
  _∷_ : A → List A → List A

foldr : {A B : Set} → (A → B → B) → B → List A → B
foldr _<>_ n []       = n
foldr _<>_ n (x ∷ xs) = x <> (foldr _<>_ n xs)

sumOfPowers : Nat → List Nat → Nat
sumOfPowers x = foldr (λ p → (x ^ p) +_) zero where

  _^_ : Nat → Nat → Nat
  m ^ zero  = suc zero
  m ^ suc n = m * (m ^ n)


------------------------------------------------------------------------------
-- A Peano arithmetic proof without using a where clause
------------------------------------------------------------------------------

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

module LogicalFramework.CommAddition where

open import Common.FOL.Relation.Binary.EqReasoning

open import PA.Axiomatic.Standard.Base

------------------------------------------------------------------------------

postulate
  +-rightIdentity : ∀ n → n + zero ≡ n
  x+Sy≡S[x+y]     : ∀ m n → m + succ n ≡ succ (m + n)
  succCong        : ∀ {m n} → m ≡ n → succ m ≡ succ n

+-leftIdentity : ∀ n → zero + n ≡ n
+-leftIdentity = PA₃

A : ℕ → Set
A m = ∀ n → m + n ≡ n + m

A0 : A zero
A0 n = zero + n   ≡⟨ +-leftIdentity n ⟩
       n          ≡⟨ sym (+-rightIdentity n) ⟩
       n + zero   ∎

is : ∀ m → A m → A (succ m)
is m ih n = succ m + n   ≡⟨ PA₄ m n ⟩
            succ (m + n) ≡⟨ succCong (ih n) ⟩
            succ (n + m) ≡⟨ sym (x+Sy≡S[x+y] n m) ⟩
            n + succ m   ∎

+-comm : ∀ m n → m + n ≡ n + m
+-comm = ℕ-ind A A0 is


module Issue361 where

data _==_ {A : Set}(a : A) : A -> Set where
  refl : a == a

postulate
  A : Set
  a b : A
  F : A -> Set

record R (a : A) : Set where
  constructor c
  field
    p : A

beta : (x : A) -> R.p {b} (c {b} x) == x
beta x = refl

lemma : (r : R a) -> R.p {b} (c {b} (R.p {a} r)) == R.p {a} r
lemma r = beta (R.p {a} r)


module PLRTree.Heap {A : Set}(_≤_ : A → A → Set) where

open import PLRTree {A}

data _≤*_ : A → PLRTree → Set where
  lf≤* : (x : A)
                   → x ≤* leaf
  nd≤* : {t : Tag}{x y : A}{l r : PLRTree}
                   → x ≤ y
                   → x ≤* l
                   → x ≤* r
                   → x ≤* node t y l r

data Heap : PLRTree → Set where
  leaf : Heap leaf
  node : {t : Tag}{x : A}{l r : PLRTree}
                   → x ≤* l
                   → x ≤* r
                   → Heap l
                   → Heap r
                   → Heap (node t x l r)


open import prelude

-- Copied pretty much verbatim

data Term : Set where
  true : Term
  false : Term
  if_then_else_end : Term → Term → Term → Term

data Value : Term → Set where
  true : Value true
  false :  Value false

data _⟶_ : Term → Term → Set where

  E─IfTrue : ∀ {t₂ t₃} →

    -----------------------------------
    if true then t₂ else t₃ end ⟶ t₂

  E─IfFalse : ∀ {t₂ t₃} →

    -----------------------------------
    if false then t₂ else t₃ end ⟶ t₃

  E─IfCong : ∀ {t₁ t₁′ t₂ t₃} →

    (t₁ ⟶ t₁′) →
    ----------------------------------------------------------
    (if t₁ then t₂ else t₃ end ⟶ if t₁′ then t₂ else t₃ end)

data Redex  : Term → Set where

  redex : ∀ {t t′} →

    t ⟶ t′ →
    --------
    Redex(t)

-- Proving that every term is a value or a redex

data ValueOrRedex : Term → Set where

  value : ∀ {t} →

    (Value(t)) →
    ---------------
    ValueOrRedex(t)

  redex : ∀ {t t′} →

    t ⟶ t′ →
    ---------------
    ValueOrRedex(t)

valueOrRedex : (t : Term) → ValueOrRedex(t)
valueOrRedex true = value true
valueOrRedex false = value false
valueOrRedex if t₀ then t₁ else t₂ end = helper (valueOrRedex t₀) where

  helper : ∀ {t₀ t₁ t₂} → ValueOrRedex(t₀) → ValueOrRedex(if t₀ then t₁ else t₂ end)
  helper (value true) = redex E─IfTrue
  helper (value false) = redex E─IfFalse
  helper (redex r) = redex (E─IfCong r)

-- From which we get some of the theorems in the book

NormalForm : Term → Set
NormalForm(t) = Redex(t) → FALSE

thm357 : ∀ {t} → Value(t) → NormalForm(t)
thm357 true (redex ())
thm357 false (redex ())

thm358 : ∀ {t} → NormalForm(t) → Value(t)
thm358 {t} nf = helper (valueOrRedex t) nf where

  helper : ∀ {t} → ValueOrRedex(t) → NormalForm(t) → Value(t)
  helper (value v) nf = v
  helper (redex r) nf = CONTRADICTION (nf (redex r))

-- But also we can buid an interpreter.

data _⟶*_ : Term → Term → Set where

  done : ∀ {t} →

    --------
    t ⟶* t

  redex : ∀ {t t′ t″} →

    t ⟶ t′ →
    t′ ⟶* t″ →
    ----------
    t ⟶* t″

-- An interpreter result

data Result  : Term → Set where

  result : ∀ {t t′} →

    t ⟶* t′ →
    Value(t′) →
    ---------
    Result(t)

-- The interpreter just calls `valueOrRedex` until it is a value.
-- This might bot terminate!

{-# NON_TERMINATING #-}
interp : (t : Term) → Result(t)
interp t = helper₂ (valueOrRedex t) where

  helper₁ : ∀ {t t′} → (t ⟶ t′) → Result(t′) → Result(t)
  helper₁ r (result s v) = result (redex r s) v

  helper₂ : ∀ {t} → ValueOrRedex(t) → Result(t)
  helper₂ (value v)          = result done v
  helper₂ (redex {t} {t′} r) = helper₁ r (interp t′)

-- Examples

not : Term → Term
not(t) = if t then false else true end

_and_ : Term → Term → Term
s and t = if s then t else false end

_or_ : Term → Term → Term
s or t = if s then true else t end

ex : Term
ex = (true and false) or (not true)

-- Try normalizing (CTRL-C CTRL-N) `interp ex`
-- you get told the result but also the derivation tree for every step!
-- ```
-- result
-- (redex (E─IfCong E─IfTrue)
--  (redex E─IfFalse
--   (redex E─IfTrue
--    done)))
-- false
-- ```


open import Relation.Binary.Core

module BSTree.Properties  {A : Set}
               (_≤_ : A → A → Set)
               (trans≤ : Transitive _≤_) where

open import BTree {A}
open import BSTree _≤_
open import List.Order.Simple _≤_
open import List.Order.Simple.Properties _≤_ trans≤
open import List.Sorted _≤_

lemma-*⊴-*≤ : {x : A}{t : BTree} → BSTree t → t *⊴ x → flatten t *≤ x
lemma-*⊴-*≤ slf lelf = lenx
lemma-*⊴-*≤ (snd sl sr l≤y y≤r) (lend y≤x r≤x) = lemma-++-*≤ y≤x (lemma-*⊴-*≤ sl l≤y) (lemma-*⊴-*≤ sr r≤x)

lemma-⊴*-≤* : {x : A}{t : BTree} → BSTree t → x ⊴* t → x ≤* flatten t
lemma-⊴*-≤* slf gelf = genx
lemma-⊴*-≤* (snd sl sr l≤y y≤r) (gend x≤y x≤l) = lemma-≤*-++ x≤y (lemma-⊴*-≤* sl x≤l) (lemma-⊴*-≤* sr y≤r)

lemma-bst-sorted : {t : BTree} → BSTree t → Sorted (flatten t)
lemma-bst-sorted slf = nils
lemma-bst-sorted (snd sl sr l≤x x≤r) = lemma-sorted++ (lemma-*⊴-*≤ sl l≤x) (lemma-⊴*-≤* sr x≤r) (lemma-bst-sorted sl) (lemma-bst-sorted sr)


module Type.Properties.Empty{ℓ} where

import      Lvl
open import Type

-- A type is empty when "empty functions" exists for it, which essentially means that there are no objects with this type.
-- This is an useful definition because the empty type is not unique (There are an infinite number of "empty types").
-- An explanation for why there are an infinite number of them:
-- · Types are not equal to each other extensionally (unlike sets, type equality is not based on their inhabitants (set equality is based on which elements that the set contains)).
-- An alternative explanation:
-- · Type equality is nominal (loosely: based on its name (assuming no other type could be named the same)), and not representional.
-- Or more simply by an example:
-- · `data Empty : Type where` defines an empty type.
--   `data Empty2 : Type where` also defines an empty type.
--   Now, `Empty` is not type equal to `Empty2` because the terms does not normalize further (by the rules of the language).
-- So by proving IsEmpty(T), it means that the type T is empty, because empty types are the only types that has the property of having empty functions.
record IsEmpty (T : Type{ℓ}) : Type{Lvl.𝐒(ℓ)} where
  constructor intro
  field
    -- Empty functions for an empty type
    -- For any type U, it is always possible to construct a function from T to U if T is empty
    empty : ∀{U : Type{ℓ}} → T → U


module Issue1691.Nat where

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

{-# BUILTIN NATURAL ℕ #-}

_∸_ : ℕ → ℕ → ℕ
m     ∸ zero  = m
zero  ∸ suc n = zero
suc m ∸ suc n = m ∸ n

pred : ℕ → ℕ
pred zero    = zero
pred (suc n) = n


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

module Categories.Functor.Monoidal where

open import Level
open import Data.Product using (Σ; _,_)

open import Categories.Category
open import Categories.Category.Product
open import Categories.Category.Monoidal

open import Categories.Functor hiding (id)
open import Categories.NaturalTransformation hiding (id)

private
  variable
    o ℓ e : Level
    C D : Category o ℓ e

module _  (MC : Monoidal C) (MD : Monoidal D) where
  private
    module C  = Category C
    module D  = Category D
    module MC = Monoidal MC
    module MD = Monoidal MD

  record MonoidalFunctor : Set (levelOfTerm MC ⊔ levelOfTerm MD) where
    field
      F : Functor C D

    open Functor F public

    field
      ε      : D [ MD.unit , F₀ MC.unit ]
      ⊗-homo : NaturalTransformation (MD.⊗ ∘F (F ⁂ F)) (F ∘F MC.⊗)

    module ⊗-homo = NaturalTransformation ⊗-homo

    -- coherence condition
    open D
    open MD
    open Commutation

    field
      associativity : ∀ {X Y Z} →
                      [ (F₀ X ⊗₀ F₀ Y) ⊗₀ F₀ Z ⇒ F₀ (X MC.⊗₀ Y MC.⊗₀ Z) ]⟨
                        ⊗-homo.η (X , Y) ⊗₁ id                          ⇒⟨ F₀ (X MC.⊗₀ Y) ⊗₀ F₀ Z ⟩
                        ⊗-homo.η (X MC.⊗₀ Y , Z)                        ⇒⟨ F₀ ((X MC.⊗₀ Y) MC.⊗₀ Z) ⟩
                        F₁ MC.associator.from
                      ≈ associator.from                                 ⇒⟨ F₀ X ⊗₀ F₀ Y ⊗₀ F₀ Z ⟩
                        id ⊗₁ ⊗-homo.η (Y , Z)                          ⇒⟨ F₀ X ⊗₀ F₀ (Y MC.⊗₀ Z) ⟩
                        ⊗-homo.η (X , Y MC.⊗₀ Z)
                      ⟩
      unitaryˡ      : ∀ {X} →
                      [ unit ⊗₀ F₀ X ⇒ F₀ X    ]⟨
                        ε ⊗₁ id                ⇒⟨ F₀ MC.unit ⊗₀ F₀ X ⟩
                        ⊗-homo.η (MC.unit , X) ⇒⟨ F₀ (MC.unit MC.⊗₀ X) ⟩
                        F₁ MC.unitorˡ.from
                      ≈ unitorˡ.from
                      ⟩
      unitaryʳ      : ∀ {X} →
                      [ F₀ X ⊗₀ unit ⇒ F₀ X    ]⟨
                        id ⊗₁ ε                ⇒⟨ F₀ X ⊗₀ F₀ MC.unit ⟩
                        ⊗-homo.η (X , MC.unit) ⇒⟨ F₀ (X MC.⊗₀ MC.unit) ⟩
                        F₁ MC.unitorʳ.from
                      ≈ unitorʳ.from
                      ⟩


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

open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Functions.Definition
open import Numbers.Naturals.Definition
open import Sets.FinSet.Definition
open import Setoids.Setoids

module Setoids.Cardinality.Finite.Definition where

record FiniteSetoid {a b : _} {A : Set a} (S : Setoid {a} {b} A) : Set (a ⊔ b) where
  field
    size : ℕ
    mapping : FinSet size → A
    bij : SetoidBijection (reflSetoid (FinSet size)) S mapping


open import Agda.Primitive using (_⊔_)

-- Set being type of all types (which is infinitely nested as Set₀ Set₁ etc
postulate
  String : Set

{-# BUILTIN STRING String #-}

data bool : Set where
  tt : bool
  ff : bool

ex₀ : bool → String
ex₀ tt = "true"
ex₀ ff = "false"

-- parameterization over all "Sets"
-- otherwise we are limited to types that ∈ Set
if_then_else_ : ∀ { ℓ } { A : Set ℓ } → bool → A → A → A
if tt then x else y = x
if ff then x else y = y

data ℕ : Set where
  zero : ℕ
  succ : ℕ → ℕ

{-# BUILTIN NATURAL ℕ #-}

_plus_ : ℕ → ℕ → ℕ
zero   plus n = n
succ m plus n = succ (m plus n)

ex₁ : ℕ
ex₁ = 5

data [_] (A : Set) : Set where
  ♢   : [ A ]
  _,_ : A → [ A ] → [ A ]

infixr 6 _,_

_++_ : ∀{ α } → [ α ] → [ α ] → [ α ]
♢ ++ ys        = ys
(x , xs) ++ ys = x , xs ++ ys

ex₂ : [ ℕ ]
ex₂ = 5 , 6 , ♢

-- why is this equivalent to
--data _≡_ { α : Set } (x : α) : α → Set where
--  refl : x ≡ x

-- syntactical identity
data _≡_ { ℓ } { α : Set ℓ} : α → α → Set ℓ where
  refl : ∀ { x : α } → x ≡ x

{-# BUILTIN EQUALITY _≡_  #-}
{-# BUILTIN REFL     refl #-}

data ⊥ : Set where

ex₃ : (2 plus 3) ≡ 5
ex₃ = refl

-- logical negation in intutionistic logic
ex₄ : 0 ≡ 1 → ⊥
ex₄ ()

cong : ∀ { ℓ } { A B : Set ℓ } → { a b : A } { f : A → B } → a ≡ b → f a ≡ f b
cong refl = refl

ex₅ : ∀ { n } → (n plus 0) ≡ n
ex₅ {zero}    = refl
ex₅ {succ n1} = cong { f = succ } ex₅

-- rewrites and dot patterns ??

data _+_ (α : Set) (β : Set) : Set where
  left  : α → α + β
  right : β → α + β

ex₆ : String + ℕ
ex₆ = left "foo"

ex₇ : String + ℕ
ex₇ = right 5

record _∨_ (α β : Set) : Set where
  constructor _,_
  field
    fst : bool
    snd : if fst then β else α

tosum : ∀ { α β } → α + β → α ∨ β
tosum (left a)  = ff , a
tosum (right b) = tt  , b

unsum : ∀ { α β } → α ∨ β → α + β
unsum (ff , a) = left a
unsum (tt , b) = right b

tosum∘unsum : ∀ { α β } → (p : α ∨ β) → (tosum (unsum p)) ≡ p
tosum∘unsum (tt , b) = refl
tosum∘unsum (ff , b) = refl

unsum∘tosum : ∀ { α β } → (p : α + β) → (unsum (tosum p)) ≡ p
unsum∘tosum (left a)  = refl
unsum∘tosum (right b) = refl

--- Thus α + β is same as dependently typed α ∨ β. Further generalizing

record Σ (I : Set) (V : I -> Set) : Set where
  constructor _,_
  field
    fst : I
    snd : V fst

--- now α ∨ β can be written as
-- this is on the types, not on values
or : Set → Set → Set
or x y = Σ bool (λ b → if b then x else y)

-- assume V does not depend on I, we get products
twice : Set → Set
twice x = Σ bool (λ b → x)


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

open import Level using (Level)
open import FLA.Algebra.Structures
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

module FLA.Algebra.Properties.Field {ℓ : Level } {A : Set ℓ} ⦃ F : Field A ⦄ where

open Field F

0ᶠ+0ᶠ≡0ᶠ : 0ᶠ + 0ᶠ ≡ 0ᶠ
0ᶠ+0ᶠ≡0ᶠ = +0ᶠ 0ᶠ

0ᶠ+ : (a : A) → 0ᶠ + a ≡ a
0ᶠ+ a rewrite +-comm 0ᶠ a = +0ᶠ a

a*0ᶠ≡0ᶠ : (a : A) → a * 0ᶠ ≡ 0ᶠ
a*0ᶠ≡0ᶠ a = begin
  a * 0ᶠ                  ≡˘⟨ 0ᶠ+ (a * 0ᶠ) ⟩
  0ᶠ + a * 0ᶠ             ≡⟨ cong (_+ a * 0ᶠ) (sym (+-inv a)) ⟩
  - a + a + a * 0ᶠ        ≡⟨ cong (λ x → - a + x + a * 0ᶠ) (sym (*1ᶠ a)) ⟩
  - a + a * 1ᶠ + a * 0ᶠ   ≡˘⟨ +-assoc (- a) (a * 1ᶠ) (a * 0ᶠ) ⟩
  - a + (a * 1ᶠ + a * 0ᶠ) ≡⟨ cong (- a +_) (sym (*-distr-+ a 1ᶠ 0ᶠ)) ⟩
  - a + (a * (1ᶠ + 0ᶠ))   ≡⟨ cong (λ x → - a + (a * x)) (+0ᶠ 1ᶠ) ⟩
  - a + (a * 1ᶠ)          ≡⟨ cong (- a +_) (*1ᶠ a) ⟩
  - a + a                 ≡⟨ +-inv a ⟩
  0ᶠ                      ∎

0ᶠ*a≡0ᶠ : (a : A) → 0ᶠ * a ≡ 0ᶠ
0ᶠ*a≡0ᶠ a = trans (*-comm 0ᶠ a) (a*0ᶠ≡0ᶠ a)

-a≡-1ᶠ*a : (a : A) → - a ≡ - 1ᶠ * a
-a≡-1ᶠ*a a = begin
  - a                        ≡˘⟨ +0ᶠ (- a) ⟩
  - a + 0ᶠ                   ≡⟨ cong (- a +_) (sym (a*0ᶠ≡0ᶠ a)) ⟩
  - a + (a * 0ᶠ)             ≡⟨ cong (λ x → - a + (a * x)) (sym (+-inv 1ᶠ)) ⟩
  - a + (a * (- 1ᶠ + 1ᶠ))    ≡⟨ cong (- a +_) (*-distr-+ a (- 1ᶠ) 1ᶠ) ⟩
  - a + (a * - 1ᶠ + a * 1ᶠ)  ≡⟨ cong (- a +_) (+-comm (a * - 1ᶠ) (a * 1ᶠ)) ⟩
  - a + (a * 1ᶠ + a * - 1ᶠ ) ≡⟨ +-assoc (- a) (a * 1ᶠ) (a * - 1ᶠ) ⟩
  - a + a * 1ᶠ + a * - 1ᶠ    ≡⟨ cong (λ x → - a + x + a * - 1ᶠ) (*1ᶠ a) ⟩
  - a + a + a * - 1ᶠ         ≡⟨ cong (_+ a * - 1ᶠ) (+-inv a) ⟩
  0ᶠ + a * - 1ᶠ              ≡⟨ 0ᶠ+ (a * - 1ᶠ) ⟩
  a * - 1ᶠ                   ≡⟨ *-comm a (- 1ᶠ) ⟩
  - 1ᶠ * a                   ∎

-a*b≡-[a*b] : (a b : A) → - a * b ≡ - (a * b)
-a*b≡-[a*b] a b = begin
  - a * b        ≡⟨ cong (_* b) (-a≡-1ᶠ*a a) ⟩
  (- 1ᶠ * a) * b ≡˘⟨ *-assoc (- 1ᶠ) a b ⟩
  - 1ᶠ * (a * b) ≡˘⟨ -a≡-1ᶠ*a ((a * b)) ⟩
  - (a * b)      ∎

a*-b≡-[a*b] : (a b : A) → a * - b ≡ - (a * b)
a*-b≡-[a*b] a b = begin
  a * - b   ≡⟨ *-comm a (- b) ⟩
  - b * a   ≡⟨ -a*b≡-[a*b] b a ⟩
  - (b * a) ≡⟨ cong -_ (*-comm b a) ⟩
  - (a * b) ∎


module Vec where

import Nat
import Fin

open Nat hiding (_==_; _<_)
open Fin

data Nil : Set where
  vnil : Nil

data Cons (A As : Set) : Set where
  vcons : A -> As -> Cons A As

mutual
  Vec' : Nat -> Set -> Set
  Vec' zero    A = Nil
  Vec' (suc n) A = Cons A (Vec n A)

  data Vec (n : Nat)(A : Set) : Set where
    vec : Vec' n A -> Vec n A

ε : {A : Set} -> Vec zero A
ε = vec vnil

_∷_ : {A : Set}{n : Nat} -> A -> Vec n A -> Vec (suc n) A
x ∷ xs = vec (vcons x xs)

_!_ : {n : Nat}{A : Set} -> Vec n A -> Fin n -> A
_!_ {zero}   _                 (fin ())
_!_ {suc n} (vec (vcons x xs)) (fin fz)     = x
_!_ {suc n} (vec (vcons x xs)) (fin (fs i)) = xs ! i

map : {n : Nat}{A B : Set} -> (A -> B) -> Vec n A -> Vec n B
map {zero}  f (vec vnil)         = ε
map {suc n} f (vec (vcons x xs)) = f x ∷ map f xs

fzeroToN-1 : (n : Nat) -> Vec n (Fin n)
fzeroToN-1 zero    = ε
fzeroToN-1 (suc n) = fzero ∷ map fsuc (fzeroToN-1 n)


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

module #1 where

open import Relation.Binary.PropositionalEquality

{-
Exercise 2.1. Show that the three obvious proofs of Lemma 2.1.2 are pairwise equal.
-}

ind₌ : ∀{a b}{A : Set a} → (C : (x y : A) → (x ≡ y) → Set b) → ((x : A) → C x x refl) → {x y : A} → (p : x ≡ y) → C x y p
ind₌ C c {x}{y} p rewrite p = c y

composite : ∀ {i} {A : Set i}{x y z : A} → (x ≡ y) → (y ≡ z) → (x ≡ z)
composite {i} {A} {_}{_}{z} p = ind₌ D d p where
  D : (x y : A) → (p : x ≡ y) → Set i
  D x y _ = y ≡ z → x ≡ z

  d : (x₁ : A) → D x₁ x₁ refl
  d _ = λ x → x

composite' : ∀ {i} {A : Set i}{x y z : A} → (x ≡ y) → (y ≡ z) → (x ≡ z)
composite' {i} {A} {_}{_}{z} = ind₌ D d where
  D : (x y : A) → (p : x ≡ y) → Set i
  D x y _ = y ≡ z → x ≡ z

  d : (x : A) → D x x refl
  d x = ind₌ E e where
    E : (x z : A) → (q : x ≡ z) → Set i
    E x z _ = x ≡ z

    e : (x : A) → E x x refl
    e x = refl

composite'' : ∀ {i} {A : Set i}{x y z : A} → (x ≡ y) → (y ≡ z) → (x ≡ z)
composite'' refl refl = refl

composite=composite' : ∀ {i} {A : Set i}{x y z : A} → (p : x ≡ y)(q : y ≡ z) → composite p q ≡ composite' p q
composite=composite' refl refl = refl

composite=composite'' : ∀ {i} {A : Set i}{x y z : A} → (p : x ≡ y)(q : y ≡ z) → composite p q ≡ composite'' p q
composite=composite'' refl refl = refl

composite'=composite'' : ∀ {i} {A : Set i}{x y z : A} → (p : x ≡ y)(q : y ≡ z) → composite' p q ≡ composite'' p q
composite'=composite'' refl refl = refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Some derivable properties
------------------------------------------------------------------------

open import Algebra

module Algebra.Properties.Group {g₁ g₂} (G : Group g₁ g₂) where

open Group G
import Algebra.FunctionProperties as P; open P _≈_
import Relation.Binary.EqReasoning as EqR; open EqR setoid
open import Function
open import Data.Product

⁻¹-involutive : ∀ x → x ⁻¹ ⁻¹ ≈ x
⁻¹-involutive x = begin
  x ⁻¹ ⁻¹               ≈⟨ sym $ proj₂ identity _ ⟩
  x ⁻¹ ⁻¹ ∙ ε           ≈⟨ refl ⟨ ∙-cong ⟩ sym (proj₁ inverse _) ⟩
  x ⁻¹ ⁻¹ ∙ (x ⁻¹ ∙ x)  ≈⟨ sym $ assoc _ _ _ ⟩
  x ⁻¹ ⁻¹ ∙ x ⁻¹ ∙ x    ≈⟨ proj₁ inverse _ ⟨ ∙-cong ⟩ refl ⟩
  ε ∙ x                 ≈⟨ proj₁ identity _ ⟩
  x                     ∎

private

  left-helper : ∀ x y → x ≈ (x ∙ y) ∙ y ⁻¹
  left-helper x y = begin
    x              ≈⟨ sym (proj₂ identity x) ⟩
    x ∙ ε          ≈⟨ refl ⟨ ∙-cong ⟩ sym (proj₂ inverse y) ⟩
    x ∙ (y ∙ y ⁻¹) ≈⟨ sym (assoc x y (y ⁻¹)) ⟩
    (x ∙ y) ∙ y ⁻¹ ∎

  right-helper : ∀ x y → y ≈ x ⁻¹ ∙ (x ∙ y)
  right-helper x y = begin
    y              ≈⟨ sym (proj₁ identity y) ⟩
    ε          ∙ y ≈⟨ sym (proj₁ inverse x) ⟨ ∙-cong ⟩ refl ⟩
    (x ⁻¹ ∙ x) ∙ y ≈⟨ assoc (x ⁻¹) x y ⟩
    x ⁻¹ ∙ (x ∙ y) ∎

left-identity-unique : ∀ x y → x ∙ y ≈ y → x ≈ ε
left-identity-unique x y eq = begin
  x              ≈⟨ left-helper x y ⟩
  (x ∙ y) ∙ y ⁻¹ ≈⟨ eq ⟨ ∙-cong ⟩ refl ⟩
       y  ∙ y ⁻¹ ≈⟨ proj₂ inverse y ⟩
  ε              ∎

right-identity-unique : ∀ x y → x ∙ y ≈ x → y ≈ ε
right-identity-unique x y eq = begin
  y              ≈⟨ right-helper x y ⟩
  x ⁻¹ ∙ (x ∙ y) ≈⟨ refl ⟨ ∙-cong ⟩ eq ⟩
  x ⁻¹ ∙  x      ≈⟨ proj₁ inverse x ⟩
  ε              ∎

identity-unique : ∀ {x} → Identity x _∙_ → x ≈ ε
identity-unique {x} id = left-identity-unique x x (proj₂ id x)

left-inverse-unique : ∀ x y → x ∙ y ≈ ε → x ≈ y ⁻¹
left-inverse-unique x y eq = begin
  x              ≈⟨ left-helper x y ⟩
  (x ∙ y) ∙ y ⁻¹ ≈⟨ eq ⟨ ∙-cong ⟩ refl ⟩
       ε  ∙ y ⁻¹ ≈⟨ proj₁ identity (y ⁻¹) ⟩
            y ⁻¹ ∎

right-inverse-unique : ∀ x y → x ∙ y ≈ ε → y ≈ x ⁻¹
right-inverse-unique x y eq = begin
  y       ≈⟨ sym (⁻¹-involutive y) ⟩
  y ⁻¹ ⁻¹ ≈⟨ ⁻¹-cong (sym (left-inverse-unique x y eq)) ⟩
  x ⁻¹    ∎


module Data.Vec.Any.Membership.Properties where

open import Relation.Binary
open import Data.Vec

module SingleSetoid {a ℓ} (S : Setoid a ℓ) where
    open Setoid S renaming (Carrier to A)
    open import Data.Vec.Any
    open import Data.Vec.Any.Membership S
    open import Function using (flip)
    open import Data.Vec.Equality using (module Equality)
    open Equality S renaming (_≈_ to _≋_; trans to ≋-trans)
    ⊆-reflexive : ∀ {n m} {xs : Vec A n} {ys : Vec A m} →
      xs ≋ ys → xs ⊆ ys
    ⊆-reflexive []-cong ()
    ⊆-reflexive (x₁≈x₂ ∷-cong eq) (here x≈x₁) = here (trans x≈x₁ x₁≈x₂)
    ⊆-reflexive (_ ∷-cong eq) (there p) = there (⊆-reflexive eq p)

    ∈′-resp-≈ : ∀ {x} → (x ≈_) Respects _≈_
    ∈′-resp-≈ = flip trans

    ∈′-resp-≋ : ∀ {n₁ n₂ x}{xs₁ : Vec A n₁}{xs₂ : Vec A n₂} →
      xs₁ ≋ xs₂ → x ∈′ xs₁ → x ∈′ xs₂
    ∈′-resp-≋ {xs₁ = .[]} {.[]} []-cong ()
    ∈′-resp-≋ {xs₁ = .(_ ∷ _)} {.(_ ∷ _)} (x¹≈x² ∷-cong eq) (here x≈x₁) = here (trans x≈x₁ x¹≈x²)
    ∈′-resp-≋ {xs₁ = .(_ ∷ _)} {.(_ ∷ _)} (x¹≈x² ∷-cong eq) (there p) =
       there (∈′-resp-≋ eq p)

open SingleSetoid public

module DoubleSetoid {a₁ a₂ ℓ₁ ℓ₂}
  (S₁ : Setoid a₁ ℓ₁) (S₂ : Setoid a₂ ℓ₂) where
      open import Data.Vec.Any.Properties
      import Data.Vec.Any as Any
      open import Data.Product hiding (map)
      open Setoid S₁ renaming (Carrier to A₁; _≈_ to _≈₁_; refl to refl₁)
      open Setoid S₂ renaming (Carrier to A₂; _≈_ to _≈₂_)

      open import Data.Vec.Any.Membership S₁ renaming (_∈′_ to _∈′₁_) using (find′)
      open import Data.Vec.Any.Membership S₂ renaming (_∈′_ to _∈′₂_) using ()

      ∈′-map⁺  : ∀ {n x}{xs : Vec A₁ n} {f} →
        f Preserves _≈₁_ ⟶ _≈₂_ →
          x ∈′₁ xs → f x ∈′₂ map f xs
      ∈′-map⁺ pres x∈′xs = map⁺ (Any.map pres x∈′xs)

      ∈′-map⁻  : ∀ {n y}{xs : Vec A₁ n} {f} → y ∈′₂ map f xs →
        ∃ λ x → x ∈′₁ xs × y ≈₂ f x
      ∈′-map⁻ y∈′map with find′ (map⁻ y∈′map)
      ... | _ , x∈xs , px = , x∈xs , px
open DoubleSetoid public


{-# OPTIONS --safe #-}

module Data.Nat.AbsoluteDifference where

open import Data.Nat.Base
open import Path
open import Prelude
open import Algebra

∣_-_∣ : ℕ → ℕ → ℕ
∣ 0         - m     ∣ = m
∣ n@(suc _) - 0     ∣ = n
∣ suc n     - suc m ∣ = ∣ n - m ∣

_ : ∣ 5 - 3 ∣ ≡ 2
_ = refl

_ : ∣ 3 - 5 ∣ ≡ 2
_ = refl

∣-∣‿comm : Commutative ∣_-_∣
∣-∣‿comm zero    zero    = refl
∣-∣‿comm zero    (suc y) = refl
∣-∣‿comm (suc x) zero    = refl
∣-∣‿comm (suc x) (suc y) = ∣-∣‿comm x y


------------------------------------------------------------------------
-- Coinductive "natural" numbers
------------------------------------------------------------------------

module Data.Conat where

open import Coinduction
open import Data.Nat using (ℕ; zero; suc)

------------------------------------------------------------------------
-- The type

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

------------------------------------------------------------------------
-- Some operations

fromℕ : ℕ → Coℕ
fromℕ zero    = zero
fromℕ (suc n) = suc (♯ fromℕ n)

∞ℕ : Coℕ
∞ℕ = suc (♯ ∞ℕ)

infixl 6 _+_

_+_ : Coℕ → Coℕ → Coℕ
zero  + n = n
suc m + n = suc (♯ (♭ m + n))


{-# OPTIONS --without-K --safe #-}
open import Categories.Category.Core
open import Categories.Category.Monoidal.Core

module Categories.Object.Monoid {o ℓ e} {𝒞 : Category o ℓ e} (C : Monoidal 𝒞) where

open import Level

-- a monoid object is a generalization of the idea from algebra of a monoid,
-- extended into any monoidal category

open Category 𝒞
open Monoidal C

record IsMonoid (M : Obj) : Set (ℓ ⊔ e) where
  field
    μ : M ⊗₀ M ⇒ M
    η : unit ⇒ M

  field
    assoc : μ ∘ μ ⊗₁ id ≈ μ ∘ id ⊗₁ μ ∘ associator.from
    identityˡ : unitorˡ.from ≈ μ ∘ η ⊗₁ id
    identityʳ : unitorʳ.from ≈ μ ∘ id ⊗₁ η

record Monoid : Set (o ⊔ ℓ ⊔ e) where
  field
    Carrier : Obj
    isMonoid : IsMonoid Carrier

  open IsMonoid isMonoid public

open Monoid

record Monoid⇒ (M M′ : Monoid) : Set (ℓ ⊔ e) where
  field
    arr : Carrier M ⇒ Carrier M′
    preserves-μ : arr ∘ μ M ≈ μ M′ ∘ arr ⊗₁ arr
    preserves-η : arr ∘ η M ≈ η M′


module foldr-monoid-foldl where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning

open import lists using (List; []; _∷_; [_]; [_,_]; [_,_,_]; foldr; IsMonoid)
open IsMonoid
open import foldl using (foldl)

postulate
  -- 外延性の公理
  extensionality : ∀ {A B : Set} {f g : A → B}
    → (∀ (x : A) → f x ≡ g x)
      -----------------------
    → f ≡ g

-- foldr-monoidのfoldl版
-- _⊗_ と e がモノイドをなすとき、任意の値でfoldを再表現できる
foldl-monoid : ∀ {A : Set} → (_⊗_ : A → A → A) (e : A) → IsMonoid _⊗_ e
  → ∀ (xs : List A) (y : A) → foldl _⊗_ y xs ≡ y ⊗ (foldl _⊗_ e xs)
foldl-monoid _⊗_ e ⊗-monoid [] y =
  begin
    foldl _⊗_ y []
  ≡⟨⟩
    y
  ≡⟨ sym (identityʳ ⊗-monoid y) ⟩
    y ⊗ e
  ≡⟨⟩
    y ⊗ (foldl _⊗_ e [])
  ∎
foldl-monoid _⊗_ e ⊗-monoid (x ∷ xs) y =
  begin
    foldl _⊗_ y (x ∷ xs)
  ≡⟨⟩
    foldl _⊗_ (y ⊗ x) xs
  ≡⟨ foldl-monoid _⊗_ e ⊗-monoid xs (y ⊗ x) ⟩
    (y ⊗ x) ⊗ (foldl _⊗_ e xs)
  ≡⟨ assoc ⊗-monoid y x (foldl _⊗_ e xs) ⟩
    y ⊗ (x ⊗ (foldl _⊗_ e xs))
  ≡⟨ cong (y ⊗_) (sym (foldl-monoid _⊗_ e ⊗-monoid xs x)) ⟩
    y ⊗ (foldl _⊗_ x xs)
  ≡⟨ cong (λ e⊗x → y ⊗ (foldl _⊗_ e⊗x xs)) (sym (identityˡ ⊗-monoid x)) ⟩
    y ⊗ (foldl _⊗_ (e ⊗ x) xs)
  ≡⟨⟩
    y ⊗ (foldl _⊗_ e (x ∷ xs))
  ∎

-- 外延性の公理を用いた証明のための補題
lemma : ∀ {A : Set} → (_⊗_ : A → A → A) (e : A) → IsMonoid _⊗_ e
  → ∀ (xs : List A) → foldr _⊗_ e xs ≡ foldl _⊗_ e xs
lemma _⊗_ e ⊗-monoid [] =
  begin
    foldr _⊗_ e []
  ≡⟨⟩
    e
  ≡⟨⟩
    foldl _⊗_ e []
  ∎
lemma _⊗_ e ⊗-monoid (x ∷ xs) =
  begin
    foldr _⊗_ e (x ∷ xs)
  ≡⟨⟩
    x ⊗ (foldr _⊗_ e xs)
  ≡⟨ cong (x ⊗_) (lemma _⊗_ e ⊗-monoid xs) ⟩
    x ⊗ (foldl _⊗_ e xs)
  ≡⟨ sym (foldl-monoid _⊗_ e ⊗-monoid xs x) ⟩
    foldl _⊗_ x xs
  ≡⟨ cong (λ e⊗x → foldl _⊗_ e⊗x xs) (sym (identityˡ ⊗-monoid x)) ⟩
    foldl _⊗_ (e ⊗ x) xs
  ≡⟨⟩
    foldl _⊗_ e (x ∷ xs)
  ∎

-- _⊗_ と e がモノイドをなすとき、foldrとfoldlが等しくなることの証明
foldr-monoid-foldl : ∀ {A : Set} → (_⊗_ : A → A → A) (e : A) → IsMonoid _⊗_ e
  → foldr _⊗_ e ≡ foldl _⊗_ e
foldr-monoid-foldl _⊗_ e ⊗-monoid = extensionality (lemma _⊗_ e ⊗-monoid)


open import bool
open import bool-thms2
open import eq
open import product
open import product-thms
open import bool-relations

module minmax {A : Set} (_≤A_ : A → A → 𝔹)
              (≤A-trans : transitive _≤A_)
              (≤A-total : total _≤A_) where

≤A-refl : reflexive _≤A_
≤A-refl = total-reflexive _≤A_ ≤A-total

min : A → A → A
min = λ x y → if x ≤A y then x else y

max : A → A → A
max = λ x y → if x ≤A y then y else x

min-≤1 : ∀{x y : A} → min x y ≤A x ≡ tt
min-≤1{x}{y} with keep (x ≤A y)
min-≤1{x}{y} | tt , p rewrite p = ≤A-refl
min-≤1{x}{y} | ff , p rewrite p = ≤A-total p

min-≤2 : ∀{x y : A} → min x y ≤A y ≡ tt
min-≤2{x}{y} with keep (x ≤A y)
min-≤2{x}{y} | tt , p rewrite p = p
min-≤2{x}{y} | ff , p rewrite p = ≤A-refl

max-≤1 : ∀{x y : A} → x ≤A max x y ≡ tt
max-≤1{x}{y} with keep (x ≤A y)
max-≤1{x}{y} | tt , p rewrite p = p
max-≤1{x}{y} | ff , p rewrite p = ≤A-refl

max-≤2 : ∀{x y : A} → y ≤A max x y ≡ tt
max-≤2{x}{y} with keep (x ≤A y)
max-≤2{x}{y} | tt , p rewrite p = ≤A-refl
max-≤2{x}{y} | ff , p rewrite p = ≤A-total p

min1-mono : ∀{x x' y : A} → x ≤A x' ≡ tt → min x y ≤A min x' y ≡ tt
min1-mono{x}{x'}{y} p with keep (x ≤A y) | keep (x' ≤A y)
min1-mono p | tt , q | tt , q' rewrite q | q' = p
min1-mono p | tt , q | ff , q' rewrite q | q' = q
min1-mono p | ff , q | tt , q' rewrite q | q' | ≤A-trans p q' with q
min1-mono p | ff , q | tt , q' | ()
min1-mono p | ff , q | ff , q' rewrite q | q' = ≤A-refl

min2-mono : ∀{x y y' : A} → y ≤A y' ≡ tt → min x y ≤A min x y' ≡ tt
min2-mono{x}{y}{y'} p with keep (x ≤A y) | keep (x ≤A y')
min2-mono p | tt , q | tt , q' rewrite q | q' = ≤A-refl
min2-mono p | tt , q | ff , q' rewrite q | q' | ≤A-trans q p with q'
min2-mono p | tt , q | ff , q' | ()
min2-mono p | ff , q | tt , q' rewrite q | q' = ≤A-total q
min2-mono p | ff , q | ff , q' rewrite q | q' = p

max2-mono : ∀{x y y' : A} → y ≤A y' ≡ tt → max x y ≤A max x y' ≡ tt
max2-mono{x}{y}{y'} p with keep (x ≤A y) | keep (x ≤A y')
max2-mono p | tt , q | tt , q' rewrite q | q' = p
max2-mono p | tt , q | ff , q' rewrite q | q' = ≤A-trans p (≤A-total q')
max2-mono p | ff , q | tt , q' rewrite q | q' = q'
max2-mono p | ff , q | ff , q' rewrite q | q' = ≤A-refl


module Data.Vec.Membership.Propositional.Disjoint where
open import Data.Vec
open import Data.Vec.Membership.Propositional
open import Relation.Binary.PropositionalEquality as P using (_≡_; _≢_)
open import Data.Empty using (⊥; ⊥-elim)
open import Function using (flip)

Disjoint : ∀ {a} {A : Set a} {n m} → Vec A n → Vec A m → Set a
Disjoint xs ys = ∀ {x} → x ∈ xs → x ∈ ys → ⊥

disjoint-sim : ∀ {a} {A : Set a} {n m} {xs : Vec A n}{ys :  Vec A m} → Disjoint xs ys → Disjoint ys xs
disjoint-sim dis = flip dis

disjoint-[]ˡ : ∀ {a} {A : Set a} {n} {xs : Vec A n} → Disjoint [] xs
disjoint-[]ˡ ()

disjoint-[]ʳ : ∀ {a} {A : Set a} {n} {xs : Vec A n} → Disjoint xs []
disjoint-[]ʳ = disjoint-sim disjoint-[]ˡ

disjointness :  ∀ {a} {A : Set a} {n m} {xs : Vec A n}{ys :  Vec A m} → Disjoint xs ys →
             ∀ {x y} → x ∈ xs → y ∈ ys → x ≢ y
disjointness dis x∈xs y∈ys x≡y rewrite x≡y = dis x∈xs y∈ys


module *-comm where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; sym)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_; step-≡; _∎)
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)

open import Induction′ using (+-assoc; +-comm; +-suc)
open import +-swap using (+-swap)

*-comm : ∀ (m n : ℕ) → m * n ≡ n * m
*-comm zero zero = refl
*-comm zero (suc n) =
  begin
    zero * (suc n)
  ≡⟨⟩
    zero
  ≡⟨⟩
    zero + (zero * n)
  ≡⟨ *-comm zero n ⟩
    zero + (n * zero)
  ≡⟨⟩
    (suc n) * zero
  ∎
*-comm (suc m) zero =
  begin
    (suc m) * zero
  ≡⟨⟩
    zero + (m * zero)
  ≡⟨ *-comm m zero ⟩
    (zero * m)
  ≡⟨⟩
    zero
  ≡⟨⟩
    zero * (suc m)
  ∎
*-comm (suc m) (suc n) =
  begin
    (suc m) * (suc n)
  ≡⟨⟩
    (suc n) + (m * (suc n))
  ≡⟨ cong ((suc n) +_) (*-comm m (suc n)) ⟩
    (suc n) + ((suc n) * m)
  ≡⟨⟩
    (suc n) + (m + (n * m))
  ≡⟨ +-swap (suc n) m (n * m) ⟩
    m + ((suc n) + (n * m))
  ≡⟨ sym (+-assoc m (suc n) (n * m)) ⟩
    (m + (suc n)) + (n * m)
  ≡⟨ cong (_+ (n * m)) (+-suc m n) ⟩
    suc (m + n) + (n * m)
  ≡⟨ cong suc (+-assoc m n (n * m)) ⟩
    (suc m) + (n + (n * m))
  ≡⟨ cong (λ m*n → (suc m) + (n + m*n)) (*-comm n m) ⟩
    (suc m) + (n + (m * n))
  ≡⟨⟩
    (suc m) + ((suc m) * n)
  ≡⟨ cong ((suc m) +_) (*-comm ((suc m)) n) ⟩
    (suc m) + (n * (suc m))
  ≡⟨⟩
    (suc n) * (suc m)
  ∎


-- from http://wiki.portal.chalmers.se/agda/pmwiki.php?n=ReferenceManual.LocalDefinition

module Local where

  data Nat : Set where
    zero : Nat
    succ : Nat -> Nat

  infixl 5 _+_
  _+_ : Nat -> Nat -> Nat
  zero + n = n
  (succ m) + n = succ (m + n)

  infixl 6 _*_
  _*_ : Nat -> Nat -> Nat
  zero * _ = zero
  (succ m) * n = n + m * n

  f : Nat
  f =  let h : Nat -> Nat
           h m = succ (succ m)
        in h zero + h (succ zero)

  t1 : Nat
  t1 = f

  h : Nat -> Nat
  h n = let add2 : Nat
            add2 = succ (succ n)

            twice : Nat -> Nat
            twice m = m * m

        in twice add2

  g : Nat -> Nat
  g n = fib n + fact n
   where fib : Nat -> Nat
         fib zero = succ zero
         fib (succ zero) = succ zero
         fib (succ (succ n)) = fib (succ n) + fib n

         fact : Nat -> Nat
         fact zero = succ zero
         fact (succ n) = succ n * fact n

  k : Nat -> Nat
  k n = let aux : Nat -> Nat
            aux m = pred (g m) + h m
        in aux (pred n)
    where pred : Nat -> Nat
          pred zero = zero
          pred (succ m) = m


{-# OPTIONS --without-K --safe #-}
open import Categories.Category

-- Properties relating Initial and Terminal Objects,
-- and Product / Coproduct via op

module Categories.Object.Duality {o ℓ e} (C : Category o ℓ e) where

open Category C

open import Level
open import Relation.Binary.PropositionalEquality as ≡ using (_≡_)

open import Categories.Morphism C
open import Categories.Object.Terminal op
open import Categories.Object.Initial C
open import Categories.Object.Product op
open import Categories.Object.Coproduct C

IsInitial⇒coIsTerminal : ∀ {X} → IsInitial X → IsTerminal X
IsInitial⇒coIsTerminal is⊥ = record
  { !        = !
  ; !-unique = !-unique
  }
  where open IsInitial is⊥

⊥⇒op⊤ : Initial → Terminal
⊥⇒op⊤ i = record
  { ⊤             = ⊥
  ; ⊤-is-terminal = IsInitial⇒coIsTerminal ⊥-is-initial
  }
  where open Initial i

coIsTerminal⇒IsInitial : ∀ {X} → IsTerminal X → IsInitial X
coIsTerminal⇒IsInitial is⊤ = record
  { !        = !
  ; !-unique = !-unique
  }
  where open IsTerminal is⊤

op⊤⇒⊥ : Terminal → Initial
op⊤⇒⊥ t = record
  { ⊥            = ⊤
  ; ⊥-is-initial = coIsTerminal⇒IsInitial ⊤-is-terminal
  }
  where open Terminal t

Coproduct⇒coProduct : ∀ {A B} → Coproduct A B → Product A B
Coproduct⇒coProduct A+B = record
  { A×B      = A+B.A+B
  ; π₁       = A+B.i₁
  ; π₂       = A+B.i₂
  ; ⟨_,_⟩    = A+B.[_,_]
  ; project₁ = A+B.inject₁
  ; project₂ = A+B.inject₂
  ; unique   = A+B.unique
  }
  where
  module A+B = Coproduct A+B

coProduct⇒Coproduct : ∀ {A B} → Product A B → Coproduct A B
coProduct⇒Coproduct A×B = record
  { A+B     = A×B.A×B
  ; i₁      = A×B.π₁
  ; i₂      = A×B.π₂
  ; [_,_]   = A×B.⟨_,_⟩
  ; inject₁ = A×B.project₁
  ; inject₂ = A×B.project₂
  ; unique  = A×B.unique
  }
  where
  module A×B = Product A×B

private
  coIsTerminal⟺IsInitial : ∀ {X} (⊥ : IsInitial X) →
    coIsTerminal⇒IsInitial (IsInitial⇒coIsTerminal ⊥) ≡ ⊥
  coIsTerminal⟺IsInitial _ = ≡.refl

  IsInitial⟺coIsTerminal : ∀ {X} (⊤ : IsTerminal X) →
    IsInitial⇒coIsTerminal (coIsTerminal⇒IsInitial ⊤) ≡ ⊤
  IsInitial⟺coIsTerminal _ = ≡.refl

  ⊥⟺op⊤ : (⊤ : Terminal) → ⊥⇒op⊤ (op⊤⇒⊥ ⊤) ≡ ⊤
  ⊥⟺op⊤ _ = ≡.refl

  op⊤⟺⊥ : (⊥ : Initial) → op⊤⇒⊥ (⊥⇒op⊤ ⊥) ≡ ⊥
  op⊤⟺⊥ _ = ≡.refl

  Coproduct⟺coProduct : ∀ {A B} (p : Product A B) → Coproduct⇒coProduct (coProduct⇒Coproduct p) ≡ p
  Coproduct⟺coProduct _ = ≡.refl

  coProduct⟺Coproduct : ∀ {A B} (p : Coproduct A B) → coProduct⇒Coproduct (Coproduct⇒coProduct p) ≡ p
  coProduct⟺Coproduct _ = ≡.refl


-- {-# OPTIONS -v tc.cover.cover:10 -v tc.cover.splittree:100 -v tc.cover.strategy:100 -v tc.cc:100 #-}
module Issue365 where

{- Basic data types -}

data Nat : Set where
 zero : Nat
 succ : Nat -> Nat

data Fin : Nat -> Set where
 fzero : {n : Nat} -> Fin (succ n)
 fsucc : {n : Nat} -> Fin n -> Fin (succ n)

data Vec (A : Set) : Nat -> Set where
 []   : Vec A zero
 _::_ : {n : Nat} -> A -> Vec A n -> Vec A (succ n)

data _==_ {A : Set} (x : A) : A -> Set where
 refl : x == x

{- Function composition -}

_◦_ : {A : Set} {B : A -> Set} {C : (x : A) -> B x -> Set}
     (f : {x : A} (y : B x) -> C x y) (g : (x : A) -> B x)
     (x : A) -> C x (g x)
(f ◦ g) x = f (g x)

{- Indexing and tabulating -}

_!_ : {n : Nat} {A : Set} -> Vec A n -> Fin n -> A
[]        ! ()
(x :: xs) ! fzero     = x
(x :: xs) ! (fsucc i) = xs ! i

tabulate : {n : Nat} {A : Set} -> (Fin n -> A) -> Vec A n
tabulate {zero}   f = []
tabulate {succ n} f = f fzero :: tabulate (f ◦ fsucc)

lem-tab-! : forall {A n} (xs : Vec A n) -> tabulate (_!_ xs) == xs
lem-tab-! {A} {zero}   [] = refl
lem-tab-! {A} {succ n} (x :: xs) with tabulate (_!_ xs) | lem-tab-! xs
lem-tab-! {A} {succ _} (x :: xs) | .xs | refl = refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Example use case for a fresh list: sorted list
------------------------------------------------------------------------

module README.Data.List.Fresh where

open import Data.Nat
open import Data.List.Base
open import Data.List.Fresh
open import Data.List.Relation.Unary.AllPairs as AllPairs using (AllPairs)
open import Data.Product
open import Relation.Nary using (⌊_⌋; fromWitness)

-- A sorted list of natural numbers can be seen as a fresh list
-- where the notion of freshness is being smaller than all the
-- existing entries

SortedList : Set
SortedList = List# ℕ _<_

_ : SortedList
_ = cons 0 (cons 1 (cons 3 (cons 10 [] _)
      (s≤s (s≤s (s≤s (s≤s z≤n))) , _))
      (s≤s (s≤s z≤n) , s≤s (s≤s z≤n) , _))
      (s≤s z≤n , s≤s z≤n , s≤s z≤n , _)

-- Clearly, writing these by hand can pretty quickly become quite cumbersome
-- Luckily, if the notion of freshness we are using is decidable, we can
-- make most of the proofs inferrable by using the erasure of the relation
-- rather than the relation itself!

-- We call this new type *I*SortedList because all the proofs will be implicit.

ISortedList : Set
ISortedList = List# ℕ ⌊ _<?_ ⌋

-- The same example is now much shorter. It looks pretty much like a normal list
-- except that we know for sure that it is well ordered.

ins : ISortedList
ins = 0 ∷# 1 ∷# 3 ∷# 10 ∷# []

-- Indeed we can extract the support list together with a proof that it
-- is ordered thanks to the combined action of toList converting a fresh
-- list to a pair of a list and a proof and fromWitness which "unerases"
-- a proof.

ns : List ℕ
ns = proj₁ (toList ins)

sorted : AllPairs _<_ ns
sorted = AllPairs.map (fromWitness _<_ _<?_) (proj₂ (toList ins))

-- See the following module for an applied use-case of fresh lists
open import README.Data.Trie.NonDependent


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.Group.Morphism where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Structure
open import Cubical.Algebra.Group.Base
open import Cubical.Data.Sigma

private
  variable
    ℓ ℓ' ℓ'' ℓ''' : Level

-- The following definition of GroupHom and GroupEquiv are level-wise heterogeneous.
-- This allows for example to deduce that G ≡ F from a chain of isomorphisms
-- G ≃ H ≃ F, even if H does not lie in the same level as G and F.

isGroupHom : (G : Group {ℓ}) (H : Group {ℓ'}) (f : ⟨ G ⟩ → ⟨ H ⟩) → Type _
isGroupHom G H f = (x y : ⟨ G ⟩) → f (x G.+ y) ≡ (f x H.+ f y) where
  module G = GroupStr (snd G)
  module H = GroupStr (snd H)

record GroupHom (G : Group {ℓ}) (H : Group {ℓ'}) : Type (ℓ-max ℓ ℓ') where
  constructor grouphom

  field
    fun : ⟨ G ⟩ → ⟨ H ⟩
    isHom : isGroupHom G H fun

record GroupEquiv (G : Group {ℓ}) (H : Group {ℓ'}) : Type (ℓ-max ℓ ℓ') where
  constructor groupequiv

  field
    eq : ⟨ G ⟩ ≃ ⟨ H ⟩
    isHom : isGroupHom G H (equivFun eq)

  hom : GroupHom G H
  hom = grouphom (equivFun eq) isHom

open GroupHom
open GroupStr

×hom : {A : Group {ℓ}} {B : Group {ℓ'}} {C : Group {ℓ''}} {D : Group {ℓ'''}}
    → GroupHom A C → GroupHom B D → GroupHom (dirProd A B) (dirProd C D)
fun (×hom mf1 mf2) = map-× (fun mf1) (fun mf2)
isHom (×hom mf1 mf2) a b = ≡-× (isHom mf1 _ _) (isHom mf2 _ _)

isInIm : (G : Group {ℓ}) (H : Group {ℓ'}) → GroupHom G H → ⟨ H ⟩ → Type (ℓ-max ℓ ℓ')
isInIm G H ϕ h = ∃[ g ∈ ⟨ G ⟩ ] ϕ .fun g ≡ h

isInKer : (G : Group {ℓ}) (H : Group {ℓ'}) → GroupHom G H → ⟨ G ⟩ → Type ℓ'
isInKer G H ϕ g = ϕ .fun g ≡ 0g (snd H)

isSurjective : (G : Group {ℓ}) (H : Group {ℓ'}) → GroupHom G H → Type (ℓ-max ℓ ℓ')
isSurjective G H ϕ = (x : ⟨ H ⟩) → isInIm G H ϕ x

isInjective : (G : Group {ℓ}) (H : Group {ℓ'}) → GroupHom G H → Type (ℓ-max ℓ ℓ')
isInjective G H ϕ = (x : ⟨ G ⟩) → isInKer G H ϕ x → x ≡ 0g (snd G)


-- 2012-02-13 Andreas: testing correct polarity of data types
-- sized types are the only source of subtyping, I think...
-- {-# OPTIONS -v tc.polarity.set:10 #-}
-- {-# OPTIONS -v tc.size.solve:20 #-}

{-# OPTIONS --show-implicit #-}
{-# OPTIONS --sized-types #-}
module DataPolarity where

open import Common.Size

data Nat : {size : Size} -> Set where
  zero : {size : Size} -> Nat {↑ size}
  suc  : {size : Size} -> Nat {size} -> Nat {↑ size}

data Pair (A : Set) : Set where
  _,_ : A -> A -> Pair A

split : {i : Size} → Nat {i} → Pair (Nat {i})
split zero = zero , zero
split (suc n) with split n
... | (l , r) = suc r , l
-- this should work, due to the monotonicity of Pair
-- without subtyping, Agda would complain about i != ↑ i

MyPair : Nat → Set → Set
MyPair zero A = Pair A
MyPair (suc n) A = MyPair n A
-- polarity should be preserved by functions

mysplit : {i : Size} → (n : Nat {i}) → MyPair (suc zero) (Nat {i})
mysplit zero = zero , zero
mysplit (suc n) with mysplit n
... | (l , r) = suc r , l

-- it should also work in modules

module M (s : Set1) where

  data P (A : Set) : Set where
    _,_ : A -> A -> P A

  sp : {i : Size} → (n : Nat {i}) → P (Nat {i})
  sp zero = zero , zero
  sp (suc n) with sp n
  ... | (l , r) = suc r , l

-- open import Common.Prelude

postulate A : Set

data Color : Set where
  red   : Color
  black : Color

data Bounds : Set where
  leftOf : Bounds → Bounds
  rightOf : Bounds → Bounds

-- works not:
data Tree' (β : Bounds) : {i : Size} -> Color → (Nat {∞}) → Set where
  lf : ∀ {i} → Tree' β {↑ i} black zero
  nr : ∀ {i n}(a : A) -- →  .(a is β)
     → Tree' (leftOf  β) {i} black n
     → Tree' (rightOf β) {i} black n
     → Tree' β {↑ i} red n
  nb : ∀ {i c n}(a : A) -- → .(a is β)
     → Tree' (leftOf β) {i} c n
     → Tree' (rightOf β) {i} black n
     → Tree' β {↑ i} black (suc n)

-- works:
data Tr (A : Set) : {i : Size} -> Color → Set where
  lf : ∀ {i} → Tr A {↑ i} black
  nr : ∀ {i}(a : A)
     → Tr A {i} black → Tr A {i} black
     → Tr A {↑ i} red
  nb : ∀ {i c}(a : A)
     → Tr A {i} c → Tr A {i} black
     → Tr A {↑ i} black


module z-06 where

open import Data.Nat                              using (ℕ; zero; suc; _+_; _*_; _<?_; _<_; ≤-pred)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
import      Relation.Binary.PropositionalEquality.Core as PE

{-
------------------------------------------------------------------------------
-- 267 p 6.2.2 Shortcuts.

C-c C-l       typecheck and highlight the current file
C-c C-,       get information about the hole under the cursor
C-c C-.       show inferred type for proposed term for a hole
C-c C-space   give a solution
C-c C-c       case analysis on a variable
C-c C-r       refine the hole
C-c C-a       automatic fill
C-c C-n       which normalizes a term (useful to test computations)
middle click  definition of the term

SYMBOLS

∧ \and
⊤ \top
→ \to
∀ \all
Π \Pi
λ \Gl
∨ \or
⊥ \bot
¬ \neg
∃ \ex
Σ \Sigma
≡ \equiv
ℕ \bN
× \times
≤ \le
∈ \in
⊎ \uplus
∷ \::
∎ \qed
x₁ \_1
x¹ \^1

------------------------------------------------------------------------------
-- p 268 6.2.3 The standard library.

default path /usr/share/agda-stdlib

Data.Empty    empty type (⊥)
Data.Unit     unit type (⊤)
Data.Bool     booleans
Data.Nat      natural numbers (ℕ)
Data.List     lists
Data.Vec      vectors (lists of given length)
Data.Fin      types with finite number of elements
Data.Integer  integers
Data.Float    floating point numbers
Data.Bin      binary natural numbers
Data.Rational rational numbers
Data.String   strings
Data.Maybe    option types
Data.AVL      balanced binary search trees

Data.Sum                               sum types (⊎, ∨)
Data.Product                           product types (×, ∧, ∃, Σ)
Relation.Nullary                       negation (¬)
Relation.Binary.PropositionalEquality  equality (≡)

------------------------------------------------------------------------------
-- p 277 6.3.4 Postulates.

for axioms (no proof)
avoide as much as possible
e.g, to work in classical logic, assume law of excluded middle with

postulate
  lem : (A : Set) → ¬ A ⊎ A

postulates do not compute:
- applying 'lem' to type A, will not reduce to ¬ A or A (as expected for a coproduct)
see section 6.5.6

------------------------------------------------------------------------------
-- p 277 6.3.5 Records.
-}

-- implementation of pairs using records
record Pair (A B : Set) : Set where
  constructor mkPair
  field
    fst : A
    snd : B

make-pair : {A B : Set} → A → B → Pair A B
make-pair a b = record { fst = a ; snd = b }

make-pair' : {A B : Set} → A → B → Pair A B
make-pair' a b = mkPair a b

proj1 : {A B : Set} → Pair A B → A
proj1 p = Pair.fst p

------------------------------------------------------------------------------
-- p 278 6.4 Inductive types: data
-- p 278 6.4.1 Natural numbers

{-
data ℕ : Set where
  zero :     ℕ -- base case
  suc  : ℕ → ℕ -- inductive case
-}

pred : ℕ → ℕ
pred  zero   = zero
pred (suc n) = n

_+'_ : ℕ → ℕ → ℕ
zero    +' n =          n
(suc m) +' n = suc (m +' n)
infixl 6  _+'_

_∸'_ : ℕ → ℕ → ℕ
zero  ∸'     n = zero
suc m ∸' zero  = suc m
suc m ∸' suc n = m ∸' n

_*'_ : ℕ → ℕ → ℕ
zero  *' n = zero
suc m *' n = (m *' n) + n

{-
_mod'_ :  ℕ → ℕ → ℕ
m mod' n with m <? n
m mod' n | yes _ = m
m mod' n | no  _ = (m ∸' n) mod' n
-}
-- TODO : what is going on here?
-- mod' :  ℕ → ℕ → ℕ
-- mod' m n with m <? n
-- ... | x = {!!}
{-
------------------------------------------------------------------------------
-- p 280 Empty pattern matching.

there is no case to pattern match on elements of this type
use on types with no elements, e.g.,
-}
data ⊥'  : Set where

-- given an element of type ⊥ then "produce" anything
-- uses pattern : () -- means that no such pattern can happen
⊥'-elim : {A : Set} → ⊥' → A
⊥'-elim ()

{-
since A is arbitrary, no way, in proof, to exhibit one.
Do not have to.
'()'  states no cases to handle, so done

Useful in negation and other less obvious ways of constructing empty inductive types.
E.g., the type zero ≡ suc zero of equalities between 0 and 1 is also an empty inductive type.
-}

{-
------------------------------------------------------------------------------
-- p 281 Anonymous pattern matching.
-}
-- curly brackets before args, cases separated by semicolons:
-- e.g.,

pred' : ℕ → ℕ
pred' = λ { zero → zero ; (suc n) → n }

{-
------------------------------------------------------------------------------
-- p 281  6.4.3 The induction principle.

pattern matching corresponds to the presence of a recurrence or induction principle

e.g.,
f : → A
f  zero   = t
f (suc n) = u' -- u' might be 'n' or result of recursive call f n

recurrence principle expresses this as
-}

rec : {A : Set} → A → (ℕ → A → A) → ℕ → A
rec t u  zero   = t
rec t u (suc n) = u n (rec t u n)

-- same with differenct var names
recℕ : {A : Set} → A → (ℕ → A → A) → ℕ → A
recℕ a n→a→a   zero  = a
recℕ a n→a→a (suc n) = n→a→a n (recℕ a n→a→a n)

{-
Same as "recursor" for including nats to simply typed λ-calculus in section 4.3.6.

Any function of type ℕ → A defined using pattern matching can be redefined using this function.
This recurrence function encapsulates the expressive power of pattern matching.
e.g.,
-}

pred'' : ℕ → ℕ
pred'' = rec zero (λ n _ → n)

_ : pred'' 2 ≡ rec zero (λ n _ → n) 2
_ = refl
_ :            rec zero (λ n _ → n) 2 ≡ 1
_ = refl
_ : pred'' 2                          ≡ 1
_ = refl

{-
logical : recurrence principle corresponds to elimination rule, so aka "eliminator"

Pattern matching in Agda is more powerful
- can be used to define functions whose return type depends on argument

means must consider functions of the form

f : (n : ℕ) -> P n    -- P : ℕ → Set
f  zero   = t         --   : P zero
f (suc n) = u n (f n) --   : P (suc n)

corresponding dependent variant of the recurrence principle is called the induction principle:
-}

rec' : (P : ℕ → Set)
     → P zero
     → ((n : ℕ) → P n → P (suc n))
     → (n : ℕ)
     → P n
rec' P Pz Ps  zero   = Pz
rec' P Pz Ps (suc n) = Ps n (rec' P Pz Ps n)

{-
reading type as a logical formula, it says the recurrence principle over natural numbers:

    P (0) ⇒ (∀n ∈ ℕ.P (n) ⇒ P (n + 1)) ⇒ ∀n ∈ ℕ.P (n)
-}

-- proof using recursion
+-zero' :    (n : ℕ) → n + zero ≡ n
+-zero'  zero   = refl
+-zero' (suc n) =                                  PE.cong suc (+-zero' n)

-- proof using dependent induction principle
+-zero'' :   (n : ℕ) → n + zero ≡ n
+-zero'' = rec' (λ n → n + zero ≡ n) refl (λ n p → PE.cong suc p)

_ : +-zero'' 2 ≡ refl
_ = refl
_ : rec' (λ n →             n + zero ≡ n) refl (λ n p → PE.cong suc p) ≡
          λ n → rec' (λ z → z + zero ≡ z) refl (λ n   → PE.cong (λ z → suc z)) n
_ = refl

------------------------------------------------------------------------------
-- p 282 Booleans

data Bool : Set where
  false : Bool
  true  : Bool

-- induction principle for booleans
Bool-rec : (P : Bool → Set) → P false → P true → (b : Bool) → P b
Bool-rec P Pf Pt false = Pf
Bool-rec P Pf Pt true  = Pt

------------------------------------------------------------------------------
-- p 283 Lists Data.List

data List (A : Set) : Set where
  []  :              List A
  _∷_ : A → List A → List A

length : {A : Set} → List A → ℕ
length      []  = 0
length (_ ∷ xs) = 1 + length xs

_++_ : {A : Set} → List A → List A → List A
[]       ++ l =            l
(x ∷ xs) ++ l = x ∷ (xs ++ l)

List-rec
  : {A : Set}
  → (P : List A → Set)
  → P []
  → ((x : A) → (xs : List A) → P xs → P (x ∷ xs))
  → (xs : List A)
  → P xs
List-rec P Pe Pc      []  = Pe
List-rec P Pe Pc (x ∷ xs) = Pc x xs (List-rec P Pe Pc xs)

------------------------------------------------------------------------------
-- p 284 6.4.7 Vectors.

data Vec (A : Set) : ℕ → Set where
  []  :                         Vec A  zero
  _∷_ : {n : ℕ} → A → Vec A n → Vec A (suc n)

{-
------------------------------------------------------------------------------
-- p 284 Dependent types.

type Vec A n depends on term n : a defining feature of dependent types.
-}

-- also, functions whose result type depends on argument, e.g.,
replicate : {A : Set} → A → (n : ℕ) → Vec A n
replicate x  zero   = []
replicate x (suc n) = x ∷ replicate x n

------------------------------------------------------------------------------
-- p 285 Dependent pattern matching.

-- since input is type Vec A (suc n), infers never applied to empty
head : {n : ℕ} {A : Set} → Vec A (suc n) → A
head (x ∷ xs) = x

------------------------------------------------------------------------------
-- p 285 Convertibility.

-- Agda is able to compare types up to β-reduction on terms (zero + n reduces to n):
-- - never distinguishes between two β-convertible terms

_++'_ : {m n : ℕ} {A : Set}
      → Vec A m → Vec A n → Vec A (m + n)
[]       ++' l = l                        -- Vec A (zero + n) ≡ Vec A n
(x ∷ xs) ++' l = x ∷ (xs ++' l)

------------------------------------------------------------------------------
-- p 285 Induction principle for Vec-rec

-- induction principle for vectors
Vec-rec : {A : Set}
        → (P : {n : ℕ} → Vec A n → Set)
        → P []
        → ({n : ℕ} → (x : A) → (xs : Vec A n) → P xs → P (x ∷ xs))
        → {n : ℕ}
        → (xs : Vec A n)
        → P xs
Vec-rec P Pe Pc      []  = Pe
Vec-rec P Pe Pc (x ∷ xs) = Pc x xs (Vec-rec P Pe Pc xs)

------------------------------------------------------------------------------
-- p 285 Indices instead of parameters.

-- general : can always encode a parameter as an index
-- recommended using parameters whenever possible (Agda handles them more efficiently)

-- use an index for type A (instead of a parameter)
data VecI : Set → ℕ → Set where
  []  : {A : Set} → VecI A zero
  _∷_ : {A : Set} {n : ℕ} (x : A) (xs : VecI A n) → VecI A (suc n)

-- induction principle for index VecI
VecI-rec : (P : {A : Set} {n : ℕ} → VecI A n → Set)
         → ({A : Set} → P {A} [])
         → ({A : Set} {n : ℕ} (x : A) (xs : VecI A n) → P xs → P (x ∷ xs))
         → {A : Set}
         → {n : ℕ}
         → (xs : VecI A n)
         → P xs
VecI-rec P Pe Pc      []  = Pe
VecI-rec P Pe Pc (x ∷ xs) = Pc x xs (VecI-rec P Pe Pc xs)

------------------------------------------------------------------------------
-- p 286 6.4.8 Finite sets.

-- has n elements
data Fin' : ℕ → Set where
  fzero' : {n : ℕ} →          Fin' (suc n)
  fsuc'  : {n : ℕ} → Fin' n → Fin' (suc n)

{-
Fin n is collection of ℕ restricted to Fin n = {0,...,n − 1}

above type corresponds to inductive set-theoretic definition:

    Fin      0  = ∅
    Fin (n + 1) = {0} ∪ {i + 1 | i ∈ Fin n}
-}

finToℕ : {n : ℕ} → Fin' n → ℕ
finToℕ  fzero'   = zero
finToℕ (fsuc' i) = suc (finToℕ i)

------------------------------------------------------------------------------
-- p 286 Vector lookup using Fin

-- Fin n typically used to index

-- type ensures index in bounds
lookup : {n : ℕ} {A : Set} → Fin' n → Vec A n → A
lookup  fzero'   (x ∷ xs) = x
lookup (fsuc' i) (x ∷ xs) = lookup i xs

-- where index can be out of bounds
open import Data.Maybe
lookup' : ℕ → {A : Set} {n : ℕ} → Vec A n → Maybe A
lookup'  zero       []  = nothing
lookup'  zero   (x ∷ l) = just x
lookup' (suc i)     []  = nothing
lookup' (suc i) (x ∷ l) = lookup' i l

-- another option : add proof of i < n
lookupP : {i n : ℕ} {A : Set}
        → i < n
        → Vec A n
        → A
lookupP     {i}       {.0}  ()     []
lookupP  {zero} {.(suc _)} i<n (x ∷ l) = x
lookupP {suc i} {.(suc _)} i<n (x ∷ l) = lookupP (≤-pred i<n) l

{-
------------------------------------------------------------------------------
-- p 287 6.5 Inductive types: logic

Use inductive types to implement types used as logical formulas,
though the Curry-Howard correspondence.

What follows is a dictionary between the two.

------------------------------------------------------------------------------
-- 6.5.1 Implication : corresponds to arrow (→) in types
-}

-- constant function
-- classical formula   A ⇒ B ⇒ A  proved by
K : {A B : Set} → A → B → A
K x y = x

-- composition
-- classical formula     (A ⇒ B ⇒ C) ⇒ (A ⇒ B) ⇒ A ⇒ C  proved by
S : {A B C : Set} → (A → B → C) → (A → B) → A → C
S g f x = g x (f x)

{-
------------------------------------------------------------------------------
-- 6.5.2 Product : corresponds to conjunction
defined in Data.Product
-}

data _×_ (A B : Set) : Set where
  _,_ : A → B → A × B

-- aka fst
proj₁ : {A B : Set} → A × B → A
proj₁ (a , b) = a

-- aka snd
proj₂ : {A B : Set} → A × B → B
proj₂ (a , b) = b

-- proof of A ∧ B ⇒ B ∧ A (commutativity of conjunction)
×-comm : {A B : Set} → A × B → B × A
×-comm (a , b) = (b , a)

-- proof of curryfication
×-→ : {A B C : Set} → (A × B → C) → (A → B → C)
×-→ f x y = f (x , y)
-- and
→-× : {A B C : Set} → (A → B → C) → (A × B → C)
→-× f (x , y) = f x y

{-
introduction rule for conjunction:
    Γ ⊢ A    Γ ⊢ B
    -------------- (∧I)
    Γ ⊢ A      ∧ B

general : when logical connectives are defined with inductive types,
- CONSTRUCTORS CORRESPOND TO INTRODUCTION RULES

------------------------------------------------------------------------------
Induction principle : ELIMINATION RULE CORRESPONDS TO THE ASSOCIATED INDUCTION PRINCIPLE
-}

-- for case where P does not depend on its arg
×-rec : {A B : Set}
  → (P : Set)
  → (A → B → P)
  → A × B → P
×-rec P Pp (x , y) = Pp x y
{-
corresponds to elimination rule for conjunction:
    Γ, A,B ⊢ P      Γ ⊢ A ∧ B
    ------------------------- (∧E)
               Γ ⊢ P
if the premises are true then the conclusion is also true
-}
-- dependent induction principle
-- corresponds to the elimination rule in dependent types
-- see 8.3.3
×-ind : {A B : Set}
  → (P : A × B → Set)
  → ((x : A) → (y : B) → P (x , y))
  → (p : A × B) → P p
×-ind P Pp (x , y) = Pp x y

{-
------------------------------------------------------------------------------
-- p 289 6.5.3 Unit type : corresponds to truth
Data.Unit
-}

data ⊤ : Set where
  tt : ⊤ -- constructor is introduction rule

{-
    ----- (⊤I)
    Γ ⊢ ⊤
-}

-- induction principle
⊤-rec
  : (P : ⊤ → Set)
  → P tt
  → (t : ⊤)
  → P t
⊤-rec P Ptt tt = Ptt

{-
know from logic there is no elimination rule associated with truth

but can write rule that corresponds to induction principle:

    Γ ⊢ P    Γ ⊢ ⊤
    --------------- (⊤E)
         Γ ⊢ P

not interesting from a logical point of view:
if P holds and ⊤ holds
then can deduce that P holds, which was already known

------------------------------------------------------------------------------
-- 6.5.4 Empty type : corresponds to falsity
Data.Empty
-}

data ⊥ : Set where
  -- no constructor, so no introduction rule

-- dependent induction principle
⊥-d-elim : (P : ⊥ → Set) → (x : ⊥) → P x
⊥-d-elim P ()

-- non-dependent variant of this principle
⊥-elim : (P : Set) → ⊥ → P
⊥-elim P () -- () is the empty pattern in Agda
            -- indicates there are no cases to handle when matching on a value of type

{-
corresponds to explosion principle, which is the associated elimination rule

    Γ ⊢ ⊥
    ---- (⊥E)
    Γ ⊢ P

------------------------------------------------------------------------------
6.5.5 Negation
Relation.Nullary
-}

¬ : Set → Set
¬ A = A → ⊥

-- e.g., A ⇒ ¬¬A  proved:
nni : {A : Set} → A → ¬ (¬ A)
nni A ¬A = ¬A A

{-
------------------------------------------------------------------------------
p 290 6.5.6 Coproduct : corresponds to disjunction
Data.Sum
-}
data _⊎_ (A : Set) (B : Set) : Set where
  inj₁ : A → A ⊎ B -- called injection of A into A ⊎ B
  inj₂ : B → A ⊎ B -- ditto               B

{-
The two constructors correspond to the two introduction rules
    Γ ⊢ A
    --------- (∨ᴸI)
    Γ ⊢ A ∨ B

    Γ ⊢     B
    --------- (∨ᴿI)
    Γ ⊢ A ∨ B
-}

-- commutativity of disjunction
⊎-comm : (A B : Set) → A ⊎ B → B ⊎ A
⊎-comm A B (inj₁ x) = inj₂ x
⊎-comm A B (inj₂ y) = inj₁ y
{-
-- proof of (A ∨ ¬A) ⇒ ¬¬A ⇒ A
lem-raa : {A : Set}
  → A ⊎ ¬ A
  → ¬ (¬ A)
  → A
lem-raa (inj₁  a) _ = a
lem-raa (inj₂ ¬a) k = ⊥-elim (k ¬a) -- ⊥ !=< Set
-}
-- induction principle
⊎-rec : {A B : Set}
  → (P : A ⊎ B → Set)
  → ((x : A) → P (inj₁ x))
  → ((y : B) → P (inj₂ y))
  → (u : A ⊎ B)
  → P u
⊎-rec P P₁ P₂ (inj₁ x) = P₁ x
⊎-rec P P₁ P₂ (inj₂ y) = P₂ y
{-
non-dependent induction principle corresponds to the elimination rule
    Γ, A ⊢ P    Γ, B ⊢ P    Γ ⊢ A ∨ B
    ----------------------------- (∨E)
                   Γ ⊢ P

------------------------------------------------------------------------------
Decidable types : A type A is decidable when it is known whether it is inhabited or not
i.e. a proof of A ∨ ¬A

could define predicate: Dec A is a proof that A is decidable
-}
Dec' : Set → Set
Dec' A = A ⊎ ¬ A -- by definition of the disjunction
{-
Agda convention
  write yes/no instead of inj₁/inj₂
because it answers the question: is A provable?

defined in Relation.Nullary as

-- p 291
A type A is decidable when
-}
data Dec (A : Set) : Set where
  yes :   A → Dec A
  no  : ¬ A → Dec A

{-
logic of Agda is intuitionistic
therefore A ∨ ¬A not provable for any type A, and not every type is decidable

it can be proved that no type is not decidable (see 2.3.5 and 6.6.8)
-}

nndec : (A : Set) → ¬ (¬ (Dec A))
nndec A n = n (no (λ a → n (yes a)))

{-
------------------------------------------------------------------------------
-- p 291 6.5.7 Π-types : corresponds to universal quantification

dependent types : types that depend on terms

some connectives support dependent generalizations

e.g., generalization of function types
  A → B
to dependent function types
  (x : A) → B
where x might occur in B.
the type B of the returned value depends on arg x

e.g.,

replicate : {A : Set} → A → (n : ℕ) → Vec A n

Dependent function types are also called Π-types

often written

    Π(x : A).B

can be define as (note: there is builtin notation in Agda)
-}
data Π {A : Set} (A : Set) (B : A → Set) : Set where
  Λ : ((a : A) → B a) → Π A B

{-
an element of Π A B is a dependent function

    (x : A) → B x

bound universal quantification bounded (the type A over which the variable ranges)

   corresponds to

    ∀x ∈ A.B(x)

proof of that formula corresponds to a function which
- to every x in A
- associates a proof of B(x)

why Agda allows the notation
    ∀ x → B x
for the above type (leaves A implicit)

Exercise 6.5.7.1.
Show that the type
     Π Bool (λ { false → A ; true → B })
is isomorphic to
     A × B

------------------------------------------------------------------------------
-- p 292 6.5.8 Σ-types : corresponds to bounded existential quantification
Data.Product
-}

-- dependent variant of product types : a : A , b : B a
data Σ (A : Set) (B : A → Set) : Set where
  _,_ : (a : A) → B a → Σ A B

-- actual Agda def is done using a record

dproj₁ : {A : Set} {B : A → Set} → Σ A B → A
dproj₁ (a , b) = a

dproj₂ : {A : Set} {B : A → Set} → (s : Σ A B) → B (dproj₁ s)
dproj₂ (a , b) = b

{-
Logical interpretation

type

    Σ A B

is bounded existential quantification

    ∃x ∈ A.B(x)

set theoretic interpretation corresponds to constructing sets by comprehension

    {x ∈ A | B(x)}

the set of elements x of A such that B(x) is satisfied

e.g., in set theory
- given a function f : A → B
- its image Im(f) is the subset of B consisting of elements in the image of f.

formally defined

     Im(f) = {y ∈ B | ∃x ∈ A.f (x) = y}

translated to with two Σ types
- one for the comprehension
- one for the universal quantification
-}
Im : {A B : Set} (f : A → B) → Set
Im {A} {B} f = Σ B (λ y → Σ A (λ x → f x ≡ y))

-- e.g., can show that every function f : A → B has a right inverse (or section)
-- g : Im(f) → A
sec : {A B : Set} (f : A → B) → Im f → A
sec f (y , (x , p)) = x

{-
------------------------------------------------------------------------------
-- p 293 : the axiom of choice

for every relation R ⊆ A × B satisfying ∀x ∈ A.∃y ∈ B.(x, y) ∈ R
there is a function f : A → B such that ∀x ∈ A.(x, f (x)) ∈ R

section 6.5.9 defined type Rel A B
corresponding to relations between types A and B

using Rel, can prov axiom of choice
-}
-- AC : {A B : Set} (R : Rel A B) -- TODO
--   → ((x : A) → Σ B (λ y → R x y))
--   → Σ (A → B) (λ f → ∀ x → R x (f x))
-- AC R f = (λ x → proj₁ (f x)) , (λ x → proj₂ (f x))
{-
the arg that corresponds to the proof of (6.1), is constructive
a function which to every element x of type A
associates a pair of an element y of B
and a proof that (x, y) belongs to the relation.

By projecting it on the first component,
necessary function f is obtained (associates an element of B to each element of A)

use the second component to prove that it satisfies the required property

the "classical" variant of the axiom of choice
does not have access to the proof of (6.1) -- it only knows its existence.

another description is thus
where the double negation has killed the contents of the proof, see section 2.5.9

postulate CAC : {A B : Set} (R : Rel A B)
  → ¬ ¬ ((x : A) → Σ B (λ y → R x y))
  → ¬ ¬ Σ (A → B) (λ f → ∀ x → R x (f x))
see 9.3.4.

------------------------------------------------------------------------------
-- p 293 : 6.5.9 Predicates

In classical logic, the set Bool of booleans is the set of truth values:
- a predicate on a set A can either be false or true
- modeled as a function A → Bool

In Agda/intuitionistic logic
- not so much interested in truth value of predicate
- but rather in its proofs
- so the role of truth values is now played by Set

predicate P on a type A is term of type

  A → Set

which to every element x of A associates the type of proofs of P x

------------------------------------------------------------------------------
-- p 294 Relations
Relation.Binary

In classical mathematics, a relation R on a set A is a subset of A × A (see A.1)

x of A is in relation with an element y when (x, y) ∈ R

relation on A can also be encoded as a function : A × A → 𝔹
or, curryfication,                              : A → A → 𝔹

in this representation, x is in relation with y when R(x, y) = 1

In Agda/intuitionistic
- relations between types A and B as type Rel A
- obtained by replacing the set 𝔹 of truth values with Set in the above description:
-}
Rel : Set → Set₁
Rel A = A → A → Set

-- e.g.
-- _≤_ : type Rel ℕ
-- _≡_ : type Rel A

{-
------------------------------------------------------------------------------
Inductive predicates (predicates defined by induction)
-}

data isEven : ℕ → Set where
  even-z : isEven zero                               --    0 is even
  even-s : {n : ℕ} → isEven n → isEven (suc (suc n)) -- if n is even then n + 2 is even
{-
corresponds to def of set E ⊆ N of even numbers
as the smallest set of numbers such that
    0 ∈ E
and
    n ∈ E ⇒ n+2 ∈ E
-}
data _≤_ : ℕ → ℕ → Set where
  z≤n : {n : ℕ}                 →  zero ≤     n
  s≤s : {m n : ℕ} (m≤n : m ≤ n) → suc m ≤ suc n
{-
smallest relation on ℕ such that
     0 ≤ 0
and
     m ≤ n implies m+1 ≤ n+1

inductive predicate definitions enable reasoning by induction over those predicates/relations
-}

≤-refl : {n : ℕ} → (n ≤ n)
≤-refl  {zero} = z≤n
≤-refl {suc n} = s≤s ≤-refl

-- p 295

≤-trans : {m n p : ℕ} → (m ≤ n) → (n ≤ p) → (m ≤ p)
≤-trans      z≤n       n≤p  = z≤n
≤-trans (s≤s m≤n) (s≤s n≤p) = s≤s (≤-trans m≤n n≤p)

{-
inductive defs good because of Agda's support for
reasoning by induction (and dependent pattern matching)
leading to simpler proofs

other defs possible

-- base on classical equivalence, for m, n ∈ N, m ≤ n ⇔ ∃m' ∈ N.m + m' = n
_≤'_ : ℕ → ℕ → Set
m ≤' n = Σ (λ m' → m + m' ≡eq n)

another:
-}
le : ℕ → ℕ → Bool
le   zero       n  = true
le (suc m)   zero  = false
le (suc m) (suc n) = le m n

_≤'_ : ℕ → ℕ → Set
m ≤' n = le m n ≡ true

{-
EXERCISE : show reflexivity and transitivity with the alternate formalizations

involved example
implicational fragment of intuitionistic natural deduction is formalized in section 7.2
the relation Γ ⊢ A
between a context Γ and a type A
which is true when the sequent is provable
is defined inductively

------------------------------------------------------------------------------
-- p 295 6.6 Equality
Relation.Binary.PropositionalEquality

-- typed equality : compare elements of same type
data _≡_ {A : Set} (x : A) : A → Set where
  refl : x ≡ x -- only way to be equal is to be the same

------------------------------------------------------------------------------
6.6.1 Equality and pattern matching

example proof with equality : successor function on natural numbers is injective
- for every natural numbers m and n
- m + 1 = n + 1 ⇒ m = n
-}

-- p 296

suc-injective : {m n : ℕ} → suc m ≡ suc n → m ≡ n
-- suc-injective {m} {n} p  -- Goal: m ≡ n;   p : suc m ≡ suc n
                            -- case split on p : it can ONLY be refl
                            -- therefore m is equal to n
                            -- so agda provide .m - not really an arg - something equal to m
suc-injective {m} {.m} refl --       m ≡ m
  = refl

{-
------------------------------------------------------------------------------
-- p 296 6.6.2 Main properties of equality: reflexive, congruence, symmetric, transitive
-}

sym : {A : Set} {x y : A}
  → x ≡ y
  → y ≡ x
sym refl = refl

trans : {A : Set} {x y z : A}
  → x ≡ y
  → y ≡ z
  → x ≡ z
trans refl refl = refl

cong : ∀ {A B : Set} (f : A → B) {x y : A}
  →   x ≡   y
  → f x ≡ f y
cong f refl = refl

-- substitutivity : enables transporting the elements of a type along an equality
{-
subst : {A : Set} (P : A → Set) → {x y : A}
  →   x ≡ y
  → P x
  → P     y
subst P refl p = p
-}
-- https://stackoverflow.com/a/27789403
subst : ∀ {a p} {A : Set a} (P : A → Set p) {x y : A}
      → x ≡ y → P x → P y
subst P refl p = p

-- coercion : enables converting an element of type to another equal type
coe : {A B : Set}
  → A ≡ B
  → A
  → B
coe p x = subst (λ A → A) p x

-- see 9.1

{-
------------------------------------------------------------------------------
-- p 296 6.6.3 Half of even numbers : example every even number has a half
using proof strategy from 2.3

traditional notation : show  ∀n ∈ N. isEven(n) ⇒ ∃m ∈ ℕ.m + m = n
-}

+-suc : ∀ (m n : ℕ)
      →      m + suc n
      ≡ suc (m +     n)
+-suc  zero   n = refl
+-suc (suc m) n = cong suc (+-suc m n)

-- even-half : {n : ℕ}
--   → isEven n
--   → Σ (λ m → m + m ≡ n) -- TODO (m : ℕ) → Set !=< Set
-- even-half  even-z = zero , refl
-- even-half (even-s e) with even-half e
-- even-half (even-s e) | m , p =
--   suc m , cong suc (trans (+-suc m m) (cong suc p))

{-
second case : by induction have m such that m + m = n
need to construct a half for n + 2: m + 1
show that it is a half via

    (m + 1) + (m + 1) =  (m + (m  + 1)) + 1   by definition of addition
                      = ((m +  m) + 1)  + 1   by +-suc
                      =       (n  + 1)  + 1   since m + m = n

implemented using transitivity of equality and
fact that it is a congruence (m + 1 = n + 1 from m = n)
also use auxiliary lemma m + (n + 1) = (m + n) + 1
-}

{-
------------------------------------------------------------------------------
-- p 297 6.6.4 Reasoning
-}

--import      Relation.Binary.PropositionalEquality as Eq
--open        Eq.≡-Reasoning using (begin_; _≡⟨⟩_; step-≡; _∎)

infix  3 _∎
infixr 2 _≡⟨⟩_ _≡⟨_⟩_
infix  1 begin_

begin_ : ∀ {ℓ} {A : Set ℓ} {x y : A} → x ≡ y → x ≡ y
begin_ x≡y = x≡y

_≡⟨⟩_ : ∀ {ℓ} {A : Set ℓ} (x {y} : A) → x ≡ y → x ≡ y
_ ≡⟨⟩ x≡y = x≡y

_≡⟨_⟩_ : {A : Set} (x {y z} : A) → x ≡ y → y ≡ z → x ≡ z
_ ≡⟨ x≡y ⟩ y≡z = trans x≡y y≡z

_∎ : ∀ {ℓ} {A : Set ℓ} (x : A) → x ≡ x
_∎ _ = refl

+-zero : ∀ (n : ℕ) → n + zero ≡ n
+-zero   zero  = refl
+-zero (suc n) rewrite +-zero n = refl

+-comm : (m n : ℕ) → m + n ≡ n + m
+-comm m zero    = +-zero m
+-comm m (suc n) =
  begin
    (m + suc n) ≡⟨ +-suc m n ⟩             -- m + (n + 1) = (m + n) + 1 -- by +-suc
    suc (m + n) ≡⟨ cong suc (+-comm m n) ⟩ -- = (n + m) + 1 -- by induction hypothesis
    suc (n + m)
  ∎

-- p 297
-- another proof using properties of equality
+-comm' : (m n : ℕ) → m + n ≡ n + m
+-comm' m   zero  = +-zero m
+-comm' m (suc n) = trans (+-suc m n) (cong suc (+-comm m n))

{-
------------------------------------------------------------------------------
-- p 298 6.6.5 Definitional equality

two terms which are convertible (i.e. re duce to a common term) are considered to be EQUAL.

not ≡, but equality internal to Agda, referred to as definitional equality
- cannot distinguish between two definitionally equal terms
- e.g., zero + n is definitionally equal to n (because addition defined that way)
- definitional equality implies equality by refl:
-}

+-zero''' : (n : ℕ) → zero + n ≡ n
+-zero''' n = refl

-- n + zero and n are not definitionally equal (because def of addition)
-- but can be proved
+-0 : (n : ℕ) → n + zero ≡ n
+-0  zero   = refl
+-0 (suc n) = cong suc (+-zero n)

-- implies structure of definitions is important (and an art form)

------------------------------------------------------------------------------
-- p 298 6.6.6 More properties with equality

-- zero is NOT the successor of any NAT
zero-suc : {n : ℕ} → zero ≡ suc n → ⊥
zero-suc ()

+-assoc : (m n o : ℕ) → (m + n) + o ≡ m + (n + o)
+-assoc  zero   n o = refl
+-assoc (suc m) n o = cong suc (+-assoc m n o)

-- p 299
*-+-dist-r : (m n o : ℕ)
           → (m + n) * o ≡ m * o + n * o
*-+-dist-r  zero   n o = refl
*-+-dist-r (suc m) n o
  rewrite
    +-comm n o
  | *-+-dist-r m n o
  | +-assoc o (m * o) (n * o)
  = refl

*-assoc : (m n o : ℕ) → (m * n) * o ≡ m * (n * o)
*-assoc  zero   n o = refl
*-assoc (suc m) n o
  rewrite
    *-+-dist-r n (m * n) o
  | *-assoc m n o
  = refl

------------------------------------------------------------------------------
-- p 299 Lists

++-empty' : {A : Set}
          → (l : List A)
          → [] ++ l ≡ l
++-empty' l = refl

empty-++ : {A : Set}
          → (l : List A)
          → l ++ [] ≡ l
empty-++     []  = refl
empty-++ (x ∷ l) = cong (x ∷_) (empty-++ l)

++-assoc : {A : Set}
         → (l1 l2 l3 : List A)
         → ((l1 ++ l2) ++ l3) ≡ (l1 ++ (l2 ++ l3))
++-assoc      []  l2 l3 = refl
++-assoc (x ∷ l1) l2 l3 = cong (x ∷_) (++-assoc l1 l2 l3)

-- TODO DOES NOT COMPILE: Set₁ != Set
-- ++-not-comm : ¬ ({A : Set} → (l1 l2 : List A)
--                  → (l1 ++ l2) ≡ (l2 ++ l1))
-- ++-not-comm f with f (1 ∷ []) (2 ∷ [])
-- ... | ()

++-length : {A : Set}
          → (l1 l2 : List A)
          → length (l1 ++ l2) ≡ length l1 + length l2
++-length      []  l2 = refl
++-length (x ∷ l1) l2 = cong (1 +_) (++-length l1 l2)

-- p 300

-- adds element to end of list
snoc : {A : Set} → List A → A → List A
snoc     []  x = x ∷ []
snoc (y ∷ l) x = y ∷ (snoc l x)

-- reverse a list
rev : {A : Set} → List A → List A
rev     []  = []
rev (x ∷ l) = snoc (rev l) x

-- reversing a list with x as the last element will prodice a list with x as the first element
rev-snoc : {A : Set}
         → (l : List A) → (x : A)
         → rev (snoc l x) ≡ x ∷ (rev l)
rev-snoc     []  x = refl
rev-snoc (y ∷ l) x = cong (λ l → snoc l y) (rev-snoc l x)

-- reverse twice
rev-rev : {A : Set}
        → (l : List A)
        → rev (rev l) ≡ l
rev-rev     []  = refl
rev-rev (x ∷ l) = trans (rev-snoc (rev l) x)
                        (cong (x ∷_) (rev-rev l))

--------------------------------------------------
-- p 300 6.6.7 The J rule.

-- equality
data _≡'_ {A : Set} : A → A → Set where
  refl' : {x : A} → x ≡' x

-- has associated induction principle :  J rule:
-- to prove P depending on equality proof p,
-- - prove it when this proof is refl
J : {A : Set} {x y : A}
    (p : x ≡' y)
    (P : (x y : A) → x ≡' y → Set)
    (r : (x : A)   → P x x refl')
  → P x y p
J {A} {x} {.x} refl' P r = r x

{-
section 6.6 shows that definition usually taken in Agda is different
(it uses a parameter instead of an index for the first argument of type A),
so that the resulting induction principle is a variant:
-}

J' : {A : Set}
     (x : A)
     (P : (y : A) → x ≡' y → Set)
     (r : P x refl')
     (y : A)
     (p : x ≡' y)
   → P y p
J' x P r .x refl' = r

{-
--------------------------------------------------
p 301 6.6.8 Decidable equality.

A type A is decidable when either A or ¬A is provable.

Write Dec A for the type of proofs of decidability of A
- yes p, where p is a proof of  A, or
- no  q, where q is a proof of ¬A

A relation on a type A is decidable when
- the type R x y is decidable
- for every elements x and y of type A.
-}

-- in Relation.Binary
-- term of type Decidable R is proof that relation R is decidable
Decidable : {A : Set} (R : A → A → Set) → Set
Decidable {A} R = (x y : A) → Dec (R x y)

{-
A type A has decidable equality when equality relation _≡_ on A is decidable.
- means there is a function/algorithm able to determine,
  given two elements of A,
  whether they are equal or not
- return a PROOF (not a boolean)
-}

_≟_ : Decidable {A = Bool} _≡_
false ≟ false = yes refl
true  ≟ true  = yes refl
false ≟ true  = no (λ ())
true  ≟ false = no (λ ())

_≟ℕ_ : Decidable {A = ℕ} _≡_
zero  ≟ℕ zero  = yes refl
zero  ≟ℕ suc n = no(λ())
suc m ≟ℕ zero  = no(λ())
suc m ≟ℕ suc n with m ≟ℕ n
... | yes refl = yes refl
... | no  ¬p   = no (λ p → ¬p (suc-injective p))

{-
--------------------------------------------------
p 301 6.6.9 Heterogeneous equality : enables comparing (seemingly) distinct types

due to McBride [McB00]

p 302

e.g., show concatenation of vectors is associative

    (l1 ++ l2) ++ l3 ≡ l1 ++ (l2 ++ l3) , where lengths are m, n and o

equality ≡ only used on terms of same type
- but types above are
- left   Vec A ((m + n) + o)
- right  Vec A (m + (n + o))

the two types are propositionally equal, can prove

   Vec A ((m + n) + o) ≡ Vec A (m + (n + o))

by

  cong (Vec A) (+-assoc m n o)

but the two types are not definitionally equal (required to compare terms with ≡)

PROOF WITH STANDARD EQUALITY.

To compare vecs, use above propositional equality
and'coe' to cast one of the members to the same type as other.
   term
      coe (cong (Vec A) (+-assoc m n o))
has type
      Vec A ((m + n) + o) → Vec A (m + (n + o))
-}

-- lemma : if l and l’ are propositional equal vectors,
-- up to propositional equality of their types as above,
-- then x : l and x : l’ are also propositionally equal:
∷-cong : {A : Set} → {m n : ℕ} {l1 : Vec A m} {l2 : Vec A n}
       → (x : A)
       → (p : m ≡ n)
       → coe (PE.cong (Vec A) p) l1 ≡ l2
       → coe (PE.cong (Vec A) (PE.cong suc p)) (x ∷ l1) ≡ x ∷ l2
∷-cong x refl refl = refl

-- TODO this needs Vec ++ (only List ++ in scope)
-- ++-assoc' : {A : Set} {m n o : ℕ}
--           → (l1 : Vec A m)
--           → (l2 : Vec A n)
--           → (l3 : Vec A o)
--           → coe (PE.cong (Vec A) (+-assoc m n o))
--                 ((l1 ++ l2) ++ l3) ≡ l1 ++ (l2 ++ l3)
-- ++-assoc'                          []  l2 l3 = refl
-- ++-assoc' {_} {suc m} {n} {o} (x ∷ l1) l2 l3 = ∷-cong x (+-assoc m n o) (++-assoc' l1 l2 l3)

{-
p 303 Proof with heterogeneous equality - TODO

------------------------------------------------------------------------------
p 303 6.7 Proving programs in practice

correctness means it agrees with a specification

correctness properties
- absence of errors : uses funs with args in correct domain (e.g., no divide by zero)
- invariants : properties always satisfied during execution
- functional properties : computes expected output on any given input

p 304 6.7.1 Extrinsic vs intrinsic proofs

extrinsic : first write program then prove properties about it (from "outside") e.g., sort : List ℕ →     List ℕ
intrinsic : incorporate properties in types                                     e.g., sort : List ℕ → SortList ℕ

example: length of concat of two lists is sum of their lengths
-}
-- extrinsic proof
++-length' : {A : Set}
           → (l1 l2 : List A)
           → length (l1 ++ l2) ≡ length l1 + length l2
++-length'      []  l2 = refl
++-length' (x ∷ l1) l2 = PE.cong suc (++-length' l1 l2)

-- intrinsic
_V++_ : {m n : ℕ} {A : Set} → Vec A m → Vec A n → Vec A (m + n)
[]      V++ l  = l
(x ∷ l) V++ l' = x ∷ (l V++ l')

------------------------------------------------------------------------------
-- p 305 6.7.2 Insertion sort


module PLRTree.Equality.Properties {A : Set} where

open import PLRTree {A}
open import PLRTree.Equality {A}
open import Relation.Binary.Core

sym≃ : Symmetric _≃_
sym≃ ≃lf = ≃lf
sym≃ (≃nd x x' l≃r l'≃r' l≃l') = ≃nd x' x l'≃r' l≃r (sym≃ l≃l')

trans≃ : Transitive _≃_
trans≃ ≃lf t≃t'' = t≃t''
trans≃ (≃nd x x' l≃r l'≃r' l≃l') (≃nd .x' x'' _ l''≃r'' l'≃r'') = ≃nd x x'' l≃r l''≃r'' (trans≃ l≃l' l'≃r'')

lemma-≃-≃ : {t t' : PLRTree} → t ≃ t' → t ≃ t
lemma-≃-≃ ≃lf = ≃lf
lemma-≃-≃ (≃nd x x' l≃r l≃r' l≃l') = ≃nd x x l≃r l≃r (lemma-≃-≃ l≃l')


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

module Data.Binary.Multiplication.Properties where

open import Prelude
open import Data.Binary.Definition
open import Data.Binary.Addition
open import Data.Binary.Addition.Properties using (+-cong)
open import Data.Binary.Multiplication
open import Data.Binary.Conversion
import Data.Nat as ℕ
import Data.Nat.Properties as ℕ
open import Path.Reasoning
open import Data.Binary.Isomorphism

double-cong : ∀ xs → ⟦ double xs ⇓⟧ ≡ ⟦ xs ⇓⟧ ℕ.* 2
double-cong 0ᵇ i = zero
double-cong (1ᵇ xs) i = 2 ℕ.+ double-cong xs i ℕ.* 2
double-cong (2ᵇ xs) i = ⟦ 2ᵇ 1ᵇ xs ⇓⟧

double-plus : ∀ x → x ℕ.+ x ≡ x ℕ.* 2
double-plus x = cong (x ℕ.+_) (sym (ℕ.+-idʳ x)) ; ℕ.*-comm 2 x

lemma₁ : ∀ x y → x ℕ.* y ℕ.* 2 ≡ y ℕ.* 2 ℕ.* x
lemma₁ x y =
  x ℕ.* y ℕ.* 2 ≡⟨ ℕ.*-assoc x y 2 ⟩
  x ℕ.* (y ℕ.* 2) ≡⟨ ℕ.*-comm x (y ℕ.* 2) ⟩
  y ℕ.* 2 ℕ.* x ∎

lemma₂ : ∀ x y → (x ℕ.+ x ℕ.* y) ℕ.* 2 ≡ x ℕ.+ (x ℕ.+ y ℕ.* 2 ℕ.* x)
lemma₂ x y =
  (x ℕ.+ x ℕ.* y) ℕ.* 2 ≡⟨ ℕ.+-*-distrib x (x ℕ.* y) 2 ⟩
  x ℕ.* 2 ℕ.+ x ℕ.* y ℕ.* 2 ≡⟨ cong₂ ℕ._+_ (sym (double-plus x)) (lemma₁ x y) ⟩
  x ℕ.+ x ℕ.+ y ℕ.* 2 ℕ.* x ≡⟨ ℕ.+-assoc x x (y ℕ.* 2 ℕ.* x) ⟩
  x ℕ.+ (x ℕ.+ y ℕ.* 2 ℕ.* x) ∎

*-cong : ∀ xs ys → ⟦ xs * ys ⇓⟧ ≡ ⟦ xs ⇓⟧ ℕ.* ⟦ ys ⇓⟧
*-cong 0ᵇ ys = refl
*-cong (1ᵇ xs) ys =
  ⟦ ys + double (ys * xs) ⇓⟧ ≡⟨ +-cong ys (double (ys * xs)) ⟩
  ⟦ ys ⇓⟧  ℕ.+ ⟦ double (ys * xs) ⇓⟧ ≡⟨ cong (⟦ ys ⇓⟧ ℕ.+_)  (double-cong (ys * xs)) ⟩
  ⟦ ys ⇓⟧  ℕ.+ ⟦ ys * xs ⇓⟧ ℕ.* 2 ≡⟨ cong (⟦ ys ⇓⟧ ℕ.+_)  (cong (ℕ._* 2) (*-cong ys xs)) ⟩
  ⟦ ys ⇓⟧  ℕ.+ ⟦ ys ⇓⟧ ℕ.* ⟦ xs ⇓⟧ ℕ.* 2 ≡⟨ cong (⟦ ys ⇓⟧ ℕ.+_) (lemma₁ ⟦ ys ⇓⟧ ⟦ xs ⇓⟧) ⟩
  ⟦ ys ⇓⟧ ℕ.+ ⟦ xs ⇓⟧ ℕ.* 2 ℕ.* ⟦ ys ⇓⟧ ∎
*-cong (2ᵇ xs) ys =
  ⟦ double (ys + ys * xs) ⇓⟧ ≡⟨ double-cong (ys + ys * xs) ⟩
  ⟦ ys + ys * xs ⇓⟧ ℕ.* 2 ≡⟨ cong (ℕ._* 2) (+-cong ys (ys * xs)) ⟩
  (⟦ ys ⇓⟧ ℕ.+ ⟦ ys * xs ⇓⟧) ℕ.* 2 ≡⟨ cong (ℕ._* 2) (cong (⟦ ys ⇓⟧ ℕ.+_) (*-cong ys xs)) ⟩
  (⟦ ys ⇓⟧ ℕ.+ ⟦ ys ⇓⟧ ℕ.* ⟦ xs ⇓⟧) ℕ.* 2 ≡⟨ lemma₂ ⟦ ys ⇓⟧ ⟦ xs ⇓⟧  ⟩
  ⟦ ys ⇓⟧ ℕ.+ (⟦ ys ⇓⟧ ℕ.+ ⟦ xs ⇓⟧ ℕ.* 2 ℕ.* ⟦ ys ⇓⟧) ∎


module Acme.Data.Fin where

open import Acme.Type
open import Acme.Data.Nat as ℕ using (ℕ)

Fin : Elt ℕ → Type
Fin = ℕ.induction (λ _ → Type) base (λ _ → step)

  where

  base : Type
  base _ = false

  step : Type → Type
  step ih [] = false
  step ih (c ∷ cs) = c == 'Z' && isNil cs
                  || c == 'S' && ih cs

zero : ∀ {n} → Elt (Fin (ℕ.suc n))
zero {n} = Fin (ℕ.suc n) ∋ "Z"

suc : ∀ {n} → Elt (Fin n) → Elt (Fin (ℕ.suc n))
suc [ k ] = [ 'S' ∷ k ]

sub : ∀ n str → str ∈ Fin n → str ∈ ℕ
sub = ℕ.induction
        (λ n → ∀ str → str ∈ Fin n → str ∈ ℕ)
        (λ _ ())
         step

  where

  step : ∀ n → (∀ str → str ∈ Fin n → str ∈ ℕ) →
               (∀ str → str ∈ Fin (ℕ.suc n) → str ∈ ℕ)
  step n ih (c ∷ cs) isFin = checkZ (c ≟ 'Z') cs {{isFin}} where

    checkS : ∀ {b} → Reflects c 'S' b → ∀ cs →
             {{IsTrue (b && Fin n cs)}} →
             (c ∷ cs) ∈ ℕ
    checkS true cs {{isFin}} = ih cs isFin

    checkZ : ∀ {b} → Reflects c 'Z' b → ∀ cs →
             {{IsTrue (b && isNil cs || c == 'S' && Fin n cs)}} →
             (c ∷ cs) ∈ ℕ
    checkZ true  [] = _
    checkZ false cs = checkS (c ≟ 'S') cs

cast : ∀ {n} → Elt (Fin n) → Elt ℕ
cast {n} p .value = p .value
cast {n} p .check = sub n (p .value) (p .check)


module Lec1Start where

-- the -- mark introduces a "comment to end of line"

------------------------------------------------------------------------------
-- some basic "logical" types
------------------------------------------------------------------------------

data Zero : Set where
  -- to give a value in a data, choose one constructor
  -- there are no constructors
  -- so that's impossible

record One : Set where
  -- to give a value in a record type, fill all its fields
  -- there are no fields
  -- so that's trivial
  --   (can we have a constructor, for convenience?)

data _+_ (S : Set)(T : Set) : Set where -- "where" wants an indented block
  -- to offer a choice of constructors, list them with their types
  inl : S -> S + T     -- constructors can pack up stuff
  inr : T -> S + T
  -- in Haskell, this was called "Either S T"

record _*_ (S : Set)(T : Set) : Set where
  field -- introduces a bunch of fields, listed with their types
    fst : S
    snd : T
  -- in Haskell, this was called "(S, T)"

------------------------------------------------------------------------------
-- some simple proofs
------------------------------------------------------------------------------

{-+}
comm-* : {A : Set}{B : Set} -> A * B -> B * A
comm-* x = ?
{+-}

{-+}
assocLR-+ : {A B C : Set} -> (A + B) + C -> A + (B + C)
assocLR-+ x = ?
{+-}

{-+}
_$*_ : {A A' B B' : Set} -> (A -> A') -> (B -> B') -> A * B -> A' * B'
(f $* g) x = r?
{+-}

-- record syntax is rather ugly for small stuff; can we have constructors?

{-+}
_$+_ : {A A' B B' : Set} -> (A -> A') -> (B -> B') -> A + B -> A' + B'
(f $+ g) x = ?
{+-}

{-+}
combinatorK : {A E : Set} -> A -> E -> A
combinatorK = ?

combinatorS : {S T E : Set} -> (E -> S -> T) -> (E -> S) -> E -> T
combinatorS = ?
{+-}

{-+}
id : {X : Set} -> X -> X
-- id x = x -- is the easy way; let's do it a funny way to make a point
id = ?
{+-}

{-+}
naughtE : {X : Set} -> Zero -> X
naughtE x = ?
{+-}

------------------------------------------------------------------------------
-- from logic to data
------------------------------------------------------------------------------

data Nat : Set where
  zero : Nat
  suc  : Nat -> Nat     -- recursive data type

{-# BUILTIN NATURAL Nat #-}
--  ^^^^^^^^^^^^^^^^^^^       this pragma lets us use decimal notation

{-+}
_+N_ : Nat -> Nat -> Nat
x +N y = ?

four : Nat
four = 2 +N 2
{+-}

------------------------------------------------------------------------------
-- and back to logic
------------------------------------------------------------------------------

{-+}
data _==_ {X : Set} : X -> X -> Set where
  refl : (x : X) -> x == x           -- the relation that's "only reflexive"

{-# BUILTIN EQUALITY _==_ #-}  -- we'll see what that's for, later

_=$=_ : {X Y : Set}{f f' : X -> Y}{x x' : X} ->
        f == f' -> x == x' -> f x == f' x'
fq =$= xq = ?
{+-}

{-+}
zero-+N : (n : Nat) -> (zero +N n) == n
zero-+N n = ?

+N-zero : (n : Nat) -> (n +N zero) == n
+N-zero n = ?

assocLR-+N : (x y z : Nat) -> ((x +N y) +N z) == (x +N (y +N z))
assocLR-+N x y z = ?
{+-}

------------------------------------------------------------------------------
-- computing types
------------------------------------------------------------------------------

{-+}
_>=_ : Nat -> Nat -> Set
x     >= zero   = One
zero  >= suc y  = Zero
suc x >= suc y  = x >= y

refl->= : (n : Nat) -> n >= n
refl->= n = {!!}

trans->= : (x y z : Nat) -> x >= y -> y >= z -> x >= z
trans->= x y z x>=y y>=z = {!!}
{+-}

------------------------------------------------------------------------------
-- construction by proof
------------------------------------------------------------------------------

{-+}
record Sg (S : Set)(T : S -> Set) : Set where  -- Sg is short for "Sigma"
  constructor _,_
  field -- introduces a bunch of fields, listed with their types
    fst : S
    snd : T fst
-- make _*_ from Sg ?

difference : (m n : Nat) -> m >= n -> Sg Nat \ d -> m == (n +N d)
                                   --       (                    )
difference m       zero    m>=n = m , refl m
difference zero    (suc n) ()
difference (suc m) (suc n) m>=n with difference m n m>=n
difference (suc m) (suc n) m>=n | d , q = d , (refl suc =$= q)

tryMe      = difference 42 37 _
don'tTryMe = difference 37 42 {!!}
{+-}

------------------------------------------------------------------------------
-- things to remember to say
------------------------------------------------------------------------------

-- why the single colon?

-- what's with all the spaces?

-- what's with identifiers mixing letters and symbols?

-- what's with all the braces?

-- what is Set?

-- are there any lowercase/uppercase conventions?

-- what's with all the underscores?
--   (i)   placeholders in mixfix operators
--   (ii)  don't care (on the left)
--   (iii) go figure (on the right)

-- why use arithmetic operators for types?

-- what's the difference between = and == ?

-- can't we leave out cases?

-- can't we loop?

-- the function type is both implication and universal quantification,
-- but why is it called Pi?

-- why is Sigma called Sigma?

-- B or nor B?


import      Lvl
open import Type

module Type.Functions.Inverse.Proofs {ℓₗ : Lvl.Level}{ℓₒ₁}{ℓₒ₂} {X : Type{ℓₒ₁}} {Y : Type{ℓₒ₂}} where

open import Function.Domains
open import Relator.Equals
open import Type.Functions {ℓₗ}
open import Type.Functions.Inverse {ℓₗ}
open import Type.Properties.Empty
open import Type.Properties.Singleton {ℓₒ₁}{ℓₒ₂}

postulate inv-bijective : ∀{f : X → Y} → ⦃ proof : Bijective(f) ⦄ → Bijective(inv f)
-- inv-bijective {f} ⦃ Bijective.intro(proof) ⦄

private
  _≡₁_ = _≡_ {ℓₗ Lvl.⊔ ℓₒ₁}

invᵣ-is-inverseᵣ : (f : X → Y) → ⦃ _ : Surjective(f) ⦄ → ∀{y} → (f(invᵣ f(y)) ≡ y)
invᵣ-is-inverseᵣ f ⦃ Surjective.intro(proof) ⦄ {y} with proof{y}
... | ◊.intro ⦃ Unapply.intro _ ⦃ out ⦄ ⦄ = out

inv-is-inverseᵣ : (f : X → Y) → ⦃ _ : Bijective(f) ⦄ → ∀{y} → (f(inv f(y)) ≡ y)
inv-is-inverseᵣ f ⦃ Bijective.intro(proof) ⦄ {y} with proof{y}
... | IsUnit.intro (Unapply.intro _ ⦃ out ⦄) _ = out

inv-is-inverseₗ : (f : X → Y) → ⦃ _ : Bijective(f) ⦄ → ∀{x} → (inv f(f(x)) ≡₁ x)
inv-is-inverseₗ f ⦃ Bijective.intro(proof) ⦄ {x} with proof{f(x)}
... | IsUnit.intro _ uniqueness with uniqueness {Unapply.intro x ⦃ [≡]-intro ⦄}
...   | [≡]-intro = [≡]-intro


module Limit where
  -- Statement that the limit of the function f at point l exists (and its value is L)
  -- This is expressed by converting the standard (ε,δ)-limit definition to Skolem normal form (TODO: ...I think? Is this correct?
  record Lim (f : ℝ → ℝ) (p : ℝ) (L : ℝ) : Stmt where
    field
      δ : ℝ₊ → ℝ₊ -- The delta function that is able to depend on epsilon
      satisfaction : ∀{ε : ℝ} → ⦃ ε > 𝟎 ⦄ → ∀{x : ℝ} → (𝟎 < ‖ x − p ‖ < δ(ε)) → (‖ f(x) − L ‖ < ε)

  -- Limit value function f (if the limit exists)
  lim : (f : ℝ → ℝ) → (p : ℝ) → ⦃ _ : ∃(Lim f(p)) ⦄ → ℝ
  lim _ _ ⦃ l ⦄ = Lim.L(l)

module Proofs where
  postulate [+]-limit : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → Lim(x ↦ f(x) + g(x))(p)
  postulate [−]-limit : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → Lim(x ↦ f(x) − g(x))(p)
  postulate [⋅]-limit : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → Lim(x ↦ f(x) ⋅ g(x))(p)
  postulate [/]-limit : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → Lim(x ↦ f(x) / g(x))(p)

  postulate [+]-lim : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → (lim(x ↦ f(x) + g(x))(p) ≡ lim f(p) + lim g(p))
  postulate [−]-lim : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → (lim(x ↦ f(x) − g(x))(p) ≡ lim f(p) − lim g(p))
  postulate [⋅]-lim : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → (lim(x ↦ f(x) ⋅ g(x))(p) ≡ lim f(p) ⋅ lim g(p))
  postulate [/]-lim : ∀{f g p} → ⦃ _ : ∃(Lim f(p)) ⦄ → ⦃ _ : ∃(Lim g(p)) ⦄ → (lim(x ↦ f(x) / g(x))(p) ≡ lim f(p) / lim g(p))


module Properties.Equality where

open import Agda.Builtin.Equality using (_≡_; refl)
open import Properties.Contradiction using (¬)

sym : ∀ {A : Set} {a b : A} → (a ≡ b) → (b ≡ a)
sym refl = refl

trans : ∀ {A : Set} {a b c : A} → (a ≡ b) → (b ≡ c) → (a ≡ c)
trans refl refl = refl

cong : ∀ {A B : Set} {a b : A} (f : A → B) → (a ≡ b) → (f a ≡ f b)
cong f refl = refl

subst₁ : ∀ {A : Set} {a b : A} (F : A → Set) → (a ≡ b) → (F a) → (F b)
subst₁ F refl x = x

subst₂ : ∀ {A B : Set} {a b : A} {c d : B} (F : A → B → Set) → (a ≡ b) → (c ≡ d) → (F a c) → (F b d)
subst₂ F refl refl x = x

_≢_ : ∀ {A : Set} → A → A → Set
(a ≢ b) = ¬(a ≡ b)