module Prelude where

------------------------------------------------------------------------
-- Universe levels
------------------------------------------------------------------------
open import Agda.Primitive public

ℓ₀ : Level
ℓ₀ = lzero

ℓ₁ : Level
ℓ₁ = lsuc ℓ₀

ℓ₂ : Level
ℓ₂ = lsuc ℓ₁

----------------------------------------------------------------------
-- Instance
----------------------------------------------------------------------
it : {l : Level} {A : Set l}  {{A}}  A
it {{x}} = x

----------------------------------------------------------------------
-- Case expressions
----------------------------------------------------------------------
case :
  {l m : Level}
  {A : Set l}
  {B : A  Set m}
  (x : A)
  (f : (x : A)  B x)
   -----------------
  B x
case x f  = f x

---------------------------------------------------------------------
-- Identity function
----------------------------------------------------------------------
id :
  {l : Level}
  {A : Set l}
   ---------
  A  A
id x = x

----------------------------------------------------------------------
-- Composition
----------------------------------------------------------------------
infixr 5 _∘_
_∘_ :
  {l m n : Level}
  {A : Set l}
  {B : A  Set m}
  {C : (x : A)  B x  Set n}
  (g : {x : A}(y : B x)  C x y)
  (f : (x : A)  B x)
   ----------------------------
  (x : A)  C x (f x)
(g  f) x = g (f x)

----------------------------------------------------------------------
-- Empty type
----------------------------------------------------------------------
data 𝟘 {l : Level} : Set l where

𝟘e :
  {l m : Level}
  {A : 𝟘 {l}  Set m}
   -----------------
   x  A x
𝟘e ()

infix 1 ¬_
¬_ : {l : Level}  Set l  Set l
¬_ {l} p = p  𝟘{l}

----------------------------------------------------------------------
-- Unit type
----------------------------------------------------------------------
record 𝟙 { : Level} : Set  where
  instance constructor tt

{-# BUILTIN UNIT 𝟙 #-}

----------------------------------------------------------------------
-- Booleans
----------------------------------------------------------------------
data 𝔹 : Set where
  true false : 𝔹

{-# BUILTIN BOOL  𝔹  #-}
{-# BUILTIN TRUE  true  #-}
{-# BUILTIN FALSE false #-}

--Boolean conditional
infix 0 if_then_else_
if_then_else_ :
  {l : Level}
  {A : 𝔹  Set l}
  (b : 𝔹)
   --------------------
  A true  A false  A b
if true  then t else f = t
if false then t else f = f

-- Boolean conjunction
infixr 6 _and_
_and_ : 𝔹  𝔹  𝔹
true  and true  = true
false and _     = false
_     and false = false

-- Boolean negation
not : 𝔹  𝔹
not true = false
not false = true

----------------------------------------------------------------------
-- Homogeneous propositional equality
----------------------------------------------------------------------
infix 4 _≡_
data _≡_ {l : Level}{A : Set l}(x : A) : A  Set l where
  instance refl : x  x

{-# BUILTIN EQUALITY _≡_ #-}
{-# BUILTIN REWRITE _≡_ #-}

----------------------------------------------------------------------
-- Heterogeneous equality
----------------------------------------------------------------------
infix 4 _≡≡_
data _≡≡_
  {l : Level}
  {A : Set l}
  : -------------------------------
  {B : Set l}(x : A)(y : B)  Set l
  where
  instance refl : {x : A}  x ≡≡ x

----------------------------------------------------------------------
-- Properties of equality
----------------------------------------------------------------------
ap :
  {l m : Level}
  {A : Set l}
  {B : Set m}
  (f : A  B)
  {x y : A}
  (_ : x  y)
   -----------
  f x  f y
ap _ refl = refl

ap₂ :
  {l m n : Level}
  {A : Set l}
  {B : Set m}
  {C : Set n}
  (f : A  B  C)
  {x x' : A}
  (_ : x  x')
  {y y' : B}
  (_ : y  y')
   -------------
  f x y  f x' y'
ap₂ f refl refl = refl

infixl 5 _;_
_;_ :
  {l : Level}
  {A : Set l}
  {x y  z : A}
  (p : x  y)
  (q : y  z)
   ----------
  x  z
p  refl = p

symm :
  {l : Level}
  {A : Set l}
  {x y : A}
  (p : x  y)
   ---------
  y  x
symm refl = refl

symm¬≡ :
  {l : Level}
  {A : Set l}
  {x y : A}
  (p : ¬ x  y)
   -----------
  ¬ y  x
symm¬≡ p refl = p refl

infix  1 proof_
proof_ :
  {l : Level}
  {A : Set l}
  {x y : A}
   -----------
  x  y  x  y
proof p = p

infixr 2 _≡[_]_
_≡[_]_ :
  {l : Level}
  {A : Set l}
  (x : A)
  {y z : A}
   -------------------
  x  y  y  z  x  z
_ ≡[ refl ] q = q

infixr 2 _[_]≡_
_[_]≡_ :
  {l : Level}
  {A : Set l}
  (x : A)
  {y z : A}
   -------------------
  y  x  y  z  x  z
_ [ refl ]≡ q = q

infixr 2 _≡[]_
_≡[]_ :
  {l : Level}
  {A : Set l}
  (x : A)
  {y : A}
   -----------
  x  y  x  y
_ ≡[] q = q

infix  3 _qed
_qed :
  {l : Level}
  {A : Set l}
  (x : A)
   ---------
  x  x
_ qed = refl

coe : {l : Level}{P Q : Set l}  P  Q  P  Q
coe refl x = x

subst :
  {l m : Level}
  {A : Set l}
  (B : A  Set m)
  {x x' : A}
  (_ : x  x')
   -------------
  B x  B x'
subst B refl x = x

uip :
  {l : Level}
  {A : Set l}
  {x x' : A}
  {p : x  x'}
  {p' : x  x'}
   -----------
  p  p'
uip {p = refl} {refl} = refl

----------------------------------------------------------------------
-- Injective functions
----------------------------------------------------------------------
injection :
  {l m : Level}
  {A : Set l}
  {B : Set m}
  (f : A  B)
   -----------
  Set (l  m)
injection f = ∀{x x'}  f x  f x'  x  x'

----------------------------------------------------------------------
-- Disjoint union
----------------------------------------------------------------------
infixr 6 _⊎_
data _⊎_ {l m : Level}(A : Set l)(B : Set m) : Set (l  m) where
  ι₁ : (x : A)  A  B
  ι₂ : (y : B)  A  B

injectionι₁ :
  {l m : Level}
  {A : Set l}
  {B : Set m}
   -----------------------
  injection (ι₁ {A = A}{B})
injectionι₁ refl = refl

injectionι₂ :
  {l m : Level}
  {A : Set l}
  {B : Set m}
   -----------------------
  injection (ι₂ {A = A}{B})
injectionι₂ refl = refl

----------------------------------------------------------------------
-- Recursion over well-founded relations
----------------------------------------------------------------------
module wf {l m : Level}{A : Set l}(R : A  A  Set m) where
  -- Accessibility predicate
  data Acc (x : A) : Set (l  m) where
    acc : (∀ y  R y x  Acc y)  Acc x

  -- Well-founded relation
  iswf : Set (l  m)
  iswf =  x  Acc x

  -- Well-founded recursion
  module _
    (w : iswf)
    {n : Level}
    (B : A  Set n)
    (b :  x  (∀ y  R y x  B y)  B x)
    where
    private
      Acc→B :  x  Acc x  B x
      Acc→B x (acc a) = b x  y r  Acc→B  y (a y r))

    rec :  x  B x
    rec x = Acc→B x (w x)

  -- Irreflexivity
  irrefl :
    (_ : iswf)
     ------------------
     x  R x x  𝟘 {l}
  irrefl w x p = ¬Accx (w x)
    where
    ¬Accx : Acc x  𝟘
    ¬Accx (acc f) = ¬Accx (f x p)

----------------------------------------------------------------------
-- Decidable properties
----------------------------------------------------------------------

{- See agda-stdlib/src/Relation/Nullary.aga -}

-- `Reflects` idiom
-- (The truth value of P is reflected by a boolean value)
data Reflects {l : Level}(P : Set l) : 𝔹  Set l where
  of-y : ( p : P  )  Reflects P true
  of-n : (¬p : ¬ P)  Reflects P false

invert :
 {l : Level}
 {P : Set l}
 {b : 𝔹}
  ---------------------------------
 Reflects P b  if b then P else ¬ P
invert (of-y  p) = p
invert (of-n ¬p) = ¬p

-- Decidability.
record Dec {l : Level}(P : Set l) : Set l where
  constructor _because_
  field
    does : 𝔹
    bcos : Reflects P does

open Dec public

pattern yes p = true  because of-y  p
pattern no ¬p = false because of-n ¬p

dec-true :
  {l : Level}
  {P : Set l}
  (p? : Dec P)
   ----------------
  P  does p?  true
dec-true (true  because   _ ) p = refl
dec-true (false because [¬p]) p with ()invert [¬p] p

dec-false :
  {l : Level}
  {P : Set l}
  (p? : Dec P)
   -------------------
  ¬ P  does p?  false
dec-false (false because  _ ) ¬p = refl
dec-false (true  because [p]) ¬p with ()¬p (invert [p])

map′ :
  {l : Level}
  {P Q : Set l}
   -------------------------------
  (P  Q)  (Q  P)  Dec P  Dec Q
does (map′ P→Q Q→P p?)                   = does p?
bcos (map′ P→Q Q→P (true  because [p] )) = of-y (P→Q (invert [p]))
bcos (map′ P→Q Q→P (false because [¬p])) = of-n (invert [¬p]  Q→P)

----------------------------------------------------------------------
-- Decidable homogeneous equality
----------------------------------------------------------------------
record hasDecEq {l : Level}(A : Set l) : Set l where
  constructor mkDecEq
  infix 4 _≐_
  field _≐_ : (x y : A)  Dec (x  y)

open hasDecEq {{...}} public

{-# DISPLAY hasDecEq._≐_ _ x y = x  y #-}

pattern equ    = yes refl
pattern neq ¬p = no ¬p

dec-equ :
  { : Level}
  {A : Set }
  {{_ : hasDecEq A}}
  (x : A)
   ----------------
  does (x  x)  true
dec-equ x = dec-true (x  x) refl

dec-neq :
  { : Level}
  {A : Set }
  {{_ : hasDecEq A}}
  (x y : A)
  (_ : ¬ x  y)
   ------------------
  does (x  y)  false
dec-neq x y = dec-false (x  y)

infix 4 _≠_
_≠_ : {l : Level}{A : Set l}{{_ : hasDecEq A}}(x x' : A)  Set
x  x' = does (x  x')  false

symm≠ :
  {l : Level}
  {A : Set l}
  {{_ : hasDecEq A}}
  (x x' : A)
   ----------------
  x  x'  x'  x
symm≠ x x' _ with  x  x'
symm≠  _ _ p    | equ with ()p
symm≠  _ _ refl | neq q = dec-neq _ _ (q  symm)

¬≡→≠  :
  { : Level}
  {A : Set }
  {{_ : hasDecEq A}}
  {x y : A}
   ----------------
  ¬ x  y  x  y
¬≡→≠ {x = x} {y} = dec-neq x y

­ :
  {l : Level}
  {A : Set l}
  {{_ : hasDecEq A}}
  (x : A)
   ----------------
  ¬ x  x
¬≠ x ¬p rewrite dec-equ x with ()¬p

≠→¬≡ :
  { : Level}
  {A : Set }
  {{_ : hasDecEq A}}
  {x y : A}
   ----------------
  x  y  ¬ x  y
≠→¬≡ p refl with ()¬≠ _ p

inj≠ :
  { : Level}
  {A B : Set }
  {{_ : hasDecEq A}}
  {{_ : hasDecEq B}}
  {f : A  B}
  (injf : injection f)
  {x x' : A}
   -----------------
  x  x'  f x  f x'
inj≠ injf p = ¬≡→≠ λ q  ≠→¬≡ p (injf q)

ap≠ :
  { : Level}
  {A B : Set }
  {{_ : hasDecEq A}}
  {{_ : hasDecEq B}}
  {f : A  B}
  {x x' : A}
   -----------------
  f x  f x'  x  x'
ap≠ p = ¬≡→≠ λ{refl  ≠→¬≡ p refl}

instance
  hasDecEq⊎ :
    {l : Level}
    {A B : Set l}
    {{_ : hasDecEq A}}
    {{_ : hasDecEq B}}
     ----------------
    hasDecEq (A  B)
  _≐_ {{hasDecEq⊎}} (ι₁ x) (ι₁ x') with  x  x'
  ... | equ   = yes refl
  ... | neq f = no λ{refl  f refl}
  _≐_ {{hasDecEq⊎}} (ι₁ _) (ι₂ _) = no λ()
  _≐_ {{hasDecEq⊎}} (ι₂ _) (ι₁ _) = no λ()
  _≐_ {{hasDecEq⊎}} (ι₂ y) (ι₂ y') with y  y'
  ... | equ   = yes refl
  ... | neq f = no λ{refl  f refl}

----------------------------------------------------------------------
-- Natural number type
----------------------------------------------------------------------
infix 8 _+1
data  : Set where
  zero : 
  _+1  : (n : )  

{-# BUILTIN NATURAL  #-}

pattern _+2 x = (x +1) +1

infix 4 _≡ᴮ_
_≡ᴮ_ :     𝔹
0     ≡ᴮ 0    = true
x +1  ≡ᴮ y +1 = x ≡ᴮ y
_     ≡ᴮ _    = false

{-# BUILTIN NATEQUALS _≡ᴮ_ #-}

-- Decidable equality
instance
  hasDecEqℕ : hasDecEq 
  _≐_ {{hasDecEqℕ}} zero zero = yes refl
  _≐_ {{hasDecEqℕ}} zero (y +1) = no λ()
  _≐_ {{hasDecEqℕ}} (x +1) zero = no λ()
  _≐_ {{hasDecEqℕ}} (x +1) (y +1) with  x  y
  ... | equ   = yes refl
  ... | neq f = no λ{refl  f refl}

-- Addition
infixl 6 _+_
_+_ :     
x + 0      = x
x + (y +1) = (x + y) +1

{-# BUILTIN NATPLUS _+_ #-}

0+ : ∀{x}  0 + x  x
0+ {0   }                = refl
0+ {x +1} rewrite 0+ {x} = refl

+1+ : ∀{x y}  (x +1) + y  (x + y) +1
+1+ {x} {0   }                    = refl
+1+ {x} {y +1} rewrite +1+ {x}{y} = refl

+comm : ∀{x y}  x + y  y + x
+comm {x} {0   }                   = symm 0+
+comm {x} {y +1}
  rewrite +1+ {y}{x} | +comm{x}{y} = refl


+1≠ : ∀{x y}  x  y  x +1  y +1
+1≠ {x} {y} p = dec-neq (x +1) (y +1) λ{refl  ¬≠ x p}

+≠ :  {x y} z  x  y  x + z  y + z
+≠         0       p = p
+≠ {x} {y} (z +1)  p = +1≠ {x + z} {y + z} (+≠ z p)

≠+1 :  x  x  x +1
≠+1 0      = dec-neq 0 1 λ ()
≠+1 (x +1) = +1≠ {x} (≠+1 x)

-- Predecessor
pred :   
pred 0      = 0
pred (x +1) = x

-- Monus
infixl 6 _∸_
_∸_ :     
x  0   = x
x  (y +1) = (pred x)  y

∸refl :  x  x  x  0
∸refl 0      = refl
∸refl (x +1) = ∸refl x

0∸ :  x  0  x  0
0∸ zero   = refl
0∸ (x +1) = 0∸ x

-- Order
infix 4 _<_ _≤_ _>_ _≥_
data _≤_ :     Set where
  ≤refl : {x : }    x  x
  ≤+1   : {x y : }  x  y  x  y +1

data _<_ :     Set where
  <+1 : {x y : }  x  y  x < y +1

1≤+1 : ∀{x}  1  x +1
1≤+1 {zero} = ≤refl
1≤+1 {x +1} = ≤+1 (1≤+1 {x})

≤+ : ∀{x y} z  x  y  x  y + z
≤+ 0      p = p
≤+ (z +1) p = ≤+1 (≤+ z p)

≤+' : ∀{x y z}  x  y  x  z + y
≤+' {y = y} {z} p rewrite +comm {z}{y} = ≤+ z p

_>_ :     Set
x > y = y < x

_≥_ :     Set
x  y = y  x

0≤ : ∀{x}  0  x
0≤ {0}    = ≤refl
0≤ {x +1} = ≤+1 0≤

+1≤ : ∀{x y}  x  y  x +1  y +1
+1≤ ≤refl      = ≤refl
+1≤ (≤+1 x≤y)  = ≤+1 (+1≤ x≤y)

+≤ : ∀{x y} z  x  y  x + z  y + z
+≤ 0 p      = p
+≤ (z +1) p = +1≤ (+≤ z p)

+1< : ∀{x y}  x < y  x +1 < y +1
+1< (<+1 p) = <+1 (+1≤ p)

≤trans :
  {x y z : }
  (_ : x  y)
  (_ : y  z)
   ---------
  x  z
≤trans x≤y ≤refl = x≤y
≤trans x≤y (≤+1 y≤z) = ≤+1 (≤trans x≤y y≤z)

≤< :
  {x y z : }
  (_ : x  y)
  (_ : y < z)
   ---------
  x < z
≤< p (<+1 q) = <+1 (≤trans p q)

<≤ :
  {x y z : }
  (_ : x < y)
  (_ : y  z)
   ---------
  x < z
<≤ (<+1 p) ≤refl   = <+1 p
<≤ (<+1 p) (≤+1 q) = <+1 (≤trans (≤+1 p) q)

<< :
  {x y z : }
  (_ : x < y)
  (_ : y < z)
   ---------
  x < z
<< (<+1 p) (q) = ≤< (≤+1 p) q

¬x+1≤x : ∀{x}  ¬ x +1  x
¬x+1≤x (≤+1 p) = ¬x+1≤x (≤trans (≤+1 ≤refl) p)

¬<> : ∀{x y}  x < y  ¬ y < x
¬<> (<+1 p) (<+1 q) = ¬x+1≤x (≤trans (≤+1 ≤refl) (≤trans (+1≤ p) q))

trich : ∀{x y}  x  y  ¬(y  x)  x < y
trich ≤refl q with ()q refl
trich (≤+1 p) _ = <+1 p

≤≠ : ∀{x y}  x  y  x  y  x +1  y
≤≠ {x} ≤refl q with ()¬≠ x q
≤≠ (≤+1 p) _ = +1≤ p

≤∨≥ :  x y  (x  y)  (y  x)
≤∨≥ 0      _             = ι₁ 0≤
≤∨≥ (x +1) 0             = ι₂ 0≤
≤∨≥ (x +1) (y +1) with ≤∨≥ x y
...               | ι₁ p = ι₁ (+1≤ p)
...               | ι₂ p = ι₂ (+1≤ p)

trich' : ∀{x y}  ¬(y  x)  x < y
trich' {x} {y} _ with ≤∨≥ x y
trich' {x} {y} _  | ι₁ _ with  x  y
trich'         _  | ι₁ q | neq f = trich q λ{refl  f refl}
trich'         p  | ι₁ q | equ with ()p q
trich'         p  | ι₂ q with ()p q

≤-1 : ∀{x y}  x +1  y +1  x  y
≤-1 ≤refl   = ≤refl
≤-1 (≤+1 p) = ≤trans (≤+1 ≤refl) p

+1≤→< :  x y  x +1  y  x < y
+1≤→< _ _ p = <≤ (<+1 ≤refl) p

<→+1≤ :  x y  x < y  x +1  y
<→+1≤ _ _ (<+1 p) = +1≤ p

+1≤→≠ :  x y  x +1  y  y  x
+1≤→≠ x y p = dec-neq y x λ{refl  ¬x+1≤x p}

<→≠ :  x y  x < y  y  x
<→≠ x (y +1) (<+1 p) = dec-neq (y +1) x λ{refl  ¬x+1≤x p}

pred+1≤ :  x  x  (pred x) +1
pred+1≤ 0      = 0≤
pred+1≤ (_ +1) = ≤refl

∸≤ : ∀{x} y  x  (x  y) + y
∸≤     0      = ≤refl
∸≤ {x} (y +1) = ≤trans (pred+1≤ x) (+1≤ (∸≤ {pred x} y))

predadj : ∀{x y}  x +1  y  x  pred y
predadj {y = y +1} = ≤-1

∸adj : ∀{x y z}  x + y  z  x  z  y
∸adj {y = 0   } p = p
∸adj {y = y +1} p = ∸adj {y = y} (predadj p)

pred+1 : ∀{x}  1  x  (pred x) +1  x
pred+1 {x +1} p = refl

∸≤' : ∀{x y}  y  x  (x  y) + y  x
∸≤' {x} {zero} p = refl
∸≤' {x} {y +1} p =
  proof
    ((pred x  y + y) +1)
  ≡[ ap _+1 (∸≤' (predadj p)) ]
     (pred x) +1
  ≡[ pred+1 (≤trans 1≤+1 p) ]
    x
  qed

¬x<x :  x  ¬(x < x)
¬x<x _ (<+1 p) = ¬x+1≤x p

-- Maximum of two numbers
max :     
max 0      y      = y
max (x +1) 0      = x +1
max (x +1) (y +1) = (max x y) +1

≤max₁ : ∀{x y}  x  max x y
≤max₁ {0   } {0   } = ≤refl
≤max₁ {x +1} {0   } = ≤refl
≤max₁ {0   } {y +1} = 0≤
≤max₁ {x +1} {y +1} = +1≤ ≤max₁

≤max₂ : ∀{x y}  y  max x y
≤max₂ {0   } {0   } = ≤refl
≤max₂ {0   } {y +1} = ≤refl
≤max₂ {x +1} {0   } = 0≤
≤max₂ {x +1} {y +1} = +1≤ ≤max₂

max≤ : ∀{x y}  x  y  max x y  y
max≤ {0   } {_   } _                      = refl
max≤ {x +1} {y +1} p rewrite max≤ (≤-1 p) = refl

max≥ : ∀{x y}  x  y  max x y  x
max≥ {0}    {0   } _                      = refl
max≥ {x +1} {0   } p                      = refl
max≥ {x +1} {y +1} p rewrite max≥ (≤-1 p) = refl

≤lub :  x y z  x  z  y  z  max x y  z
≤lub x y z p q with ≤∨≥ x y
... | ι₁ x≤y rewrite max≤ x≤y = q
... | ι₂ x≥y rewrite max≥ x≥y = p

-- < is well founded
wf< : wf.iswf _<_
wf< x = wf.acc (α x)
  where
  α :  x y  y < x  wf.Acc _<_ y
  β :  x y  y  x  wf.Acc _<_ y
  α (x +1) y (<+1 p) = β x y p
  β 0      _ ≤refl   = wf.acc (λ{ _ ()})
  β (x +1) _ ≤refl   = wf.acc (λ{ y (<+1 p)  β _ y p})
  β (x +1) y (≤+1 p) = wf.acc  z q  α x z (<≤ q p))

----------------------------------------------------------------------
-- Finite enumerated sets
----------------------------------------------------------------------
data Fin :   Set where
  zero : ∀{n}  Fin (n +1)
  succ : ∀{n}  Fin n  Fin (n +1)

-- Maximum of finitely many numbers
Max : {n : }  (Fin n  )  
Max {0} f = 0
Max {n +1} f = max (f zero) (Max (f  succ))

≤Max :
  {n : }
  (f : Fin n  )
  (k : Fin n)
   -------------
  f k  Max f
≤Max {n +1} f zero     = ≤max₁
≤Max {n +1} f (succ k) = ≤trans (≤Max (f  succ) k) ≤max₂

----------------------------------------------------------------------
-- Arrays
----------------------------------------------------------------------
record Array {l : Level}(A : Set l) : Set l where
  constructor mkArray
  field
    length : 
    index  : Fin length  A

open Array public

----------------------------------------------------------------------
-- Lists
----------------------------------------------------------------------
infixr 6 _::_
data List {l : Level} (A : Set l) : Set l where
  []  : List A
  _::_ : (x : A) (xs : List A)  List A

{-# BUILTIN LIST List #-}

----------------------------------------------------------------------
--  Finite sets represented by trees
----------------------------------------------------------------------
infix 1 [_]
infixr 6 _∪_
data Fset {l : Level}(A : Set l) : Set l where
  Ø   : Fset A
  [_] : A  Fset A
  _∪_ : Fset A  Fset A  Fset A

∪inj₂ :
  {l : Level}
  {A : Set l}
  {xs xs' ys ys' : Fset A}
   -------------------------------
  (xs  xs'  ys  ys')  xs'  ys'
∪inj₂ refl = refl

-- Functorial action
Fset′ :
  {l : Level}
  {A B : Set l}
  (f : A  B)
   -------------
  Fset A  Fset B
Fset′ f Ø          = Ø
Fset′ f [ x ]      = [ f x ]
Fset′ f (xs  xs') = Fset′ f xs  Fset′ f xs'

-- Membership
infix 4 _∈_
data _∈_
  {l : Level}
  {A : Set l}
  (x : A)
  : ------------
  Fset A  Set l
  where
  ∈[] : x  [ x ]
  ∈∪₁ : ∀{xs xs'}  x  xs   x  xs  xs'
  ∈∪₂ : ∀{xs xs'}  x  xs'  x  xs  xs'

Fset′∈ :
  {l : Level}
  {A B : Set l}
  {f : A  B}
  {x : A}
  {xs : Fset A}
  (_ : x  xs)
   --------------
  f x  Fset′ f xs
Fset′∈ ∈[]     = ∈[]
Fset′∈ (∈∪₁ p) = ∈∪₁ (Fset′∈ p)
Fset′∈ (∈∪₂ p) = ∈∪₂ (Fset′∈ p)

-- Non-membership
module _ {l : Level}{A : Set l}{{α : hasDecEq A}} where
  infix 4 _∉_
  data _∉_ (x : A) : Fset A  Set l
    where
    instance
      ∉Ø  : x  Ø
      ∉[] : ∀{x'}{{p : x  x'}}  x  [ x' ]
      ∉∪  : ∀{xs xs'}{{p : x  xs}}{{q : x  xs'}}  x  xs  xs'

  ∉∪₁ :
    {x : A}
    {xs xs' : Fset A}
     -------------------
    x  xs  xs'  x  xs
  ∉∪₁ ∉∪ = it

  ∉∪₂ :
    {x : A}
    {xs xs' : Fset A}
     --------------------
    x  xs  xs'  x  xs'
  ∉∪₂ ∉∪ = it

  ∉[]₁ :
    {x x' : A}
     -----------------
    x  [ x' ]  x  x'
  ∉[]₁ ∉[] = it

  ¬∈→∉ :
    {x : A}
    {xs : Fset A}
     ----------------
    ¬(x  xs)  x  xs
  ¬∈→∉ {xs = Ø}     _ = ∉Ø
  ¬∈→∉ {xs = [ x' ]} p =
    ∉[] {x' = x'} {{¬≡→≠{{α}} λ{refl  p ∈[]}}}
  ¬∈→∉ {xs = xs  xs'} p =
    ∉∪ {xs = xs} {xs' = xs'}
    {{¬∈→∉ λ q  p (∈∪₁ q)}}
    {{¬∈→∉ λ q  p (∈∪₂ q)}}

  ∉→¬∈ :
    {x : A}
    {xs : Fset A}
    {{p : x  xs}}
     ------------
    ¬ (x  xs)
  ∉→¬∈ {x = x} {{p = ∉[]}} ∈[] with ()¬≠ x it
  ∉→¬∈ {{p = ∉∪}} (∈∪₁ q) = ∉→¬∈ q
  ∉→¬∈ {{p = ∉∪}} (∈∪₂ q) = ∉→¬∈ q

Fset′∉ :
  {l : Level}
  {A B : Set l}
  {{_ : hasDecEq A}}
  {{_ : hasDecEq B}}
  {f : A  B}
  {x : A}
  {xs : Fset A}
  {{p : f x  Fset′ f xs}}
   ----------------------
  x  xs
Fset′∉ = ¬∈→∉ λ q  ∉→¬∈ (Fset′∈ q)

-- Finite union of finite subsets
 : {l : Level}{A : Set l}{n : }  (Fin n  Fset A)  Fset A
 {n = 0} _ = Ø
 {n = n +1} f = f zero   {n = n} (f  succ)

∉⋃ :
  {l : Level}
  {A : Set l}
  {{_ : hasDecEq A}}
  {n : }
  (f : Fin n  Fset A)
  {x : A}
  (k : Fin n)
  {{p : x   f}}
   ------------------
  x  f k
∉⋃ {n = n +1} f zero     {{p}} = ∉∪₁ p
∉⋃ {n = n +1} f (succ k) {{p}} = ∉⋃ {n = n} (f  succ) k {{∉∪₂ p}}

∉⋃′ :
  {l : Level}
  {A : Set l}
  {{_ : hasDecEq A}}
  {n : }
  (f : Fin n  Fset A)
  {x : A}
  (g : (k : Fin n)→ x  f k)
   ------------------------
  x   f
∉⋃′ {n = 0}    _ _ = ∉Ø
∉⋃′ {n = n +1} f g =
  ∉∪{{p = g zero}}{{∉⋃′{n = n} (f  succ) (g  succ)}}

-- Subtract an element
infix 6 _-[_]
_-[_] :
  {l : Level}
  {A : Set l}
  {{α : hasDecEq A}}
  (xs : Fset A)
  (x : A)
   ----------------
  Fset A
Ø         -[ x ] = Ø
[ y ]     -[ x ] = if does(x  y) then Ø else [ y ]
(ys  zs) -[ x ] = (ys -[ x ])  (zs -[ x ])

x∉xs-[x] :
  {l : Level}
  {A : Set l}
  {{α : hasDecEq A}}
  (xs : Fset A)
  {x : A}
   ----------------
  x  xs -[ x ]
x∉xs-[x] Ø = ∉Ø
x∉xs-[x] [ y ] {x} with x  y
... | neq f        = ∉[]{{p = ¬≡→≠ f}}
... | equ          = ∉Ø
x∉xs-[x] (ys  zs) = ∉∪{{p = x∉xs-[x] ys}}{{x∉xs-[x] zs}}

y∉zs→y∉zs-[x] :
  {l : Level}
  {A : Set l}
  {{α : hasDecEq A}}
  {x y : A}
  (zs : Fset A)
   --------------------
  y  zs  y  zs -[ x ]
y∉zs→y∉zs-[x] Ø ∉Ø = ∉Ø
y∉zs→y∉zs-[x] {x = x} {y} [ z ] ∉[] with x  z
... | equ                   = ∉Ø
... | neq f                 = ∉[]
y∉zs→y∉zs-[x] (zs  zs') ∉∪ =
  ∉∪{{p = y∉zs→y∉zs-[x] zs it}}{{y∉zs→y∉zs-[x] zs' it}}

∉-[] :
  {l : Level}
  {A : Set l}
  {{α : hasDecEq A}}
  {xs : Fset A}
  {x y : A}
  (_ : y  xs -[ x ])
  (_ : y  x)
   -----------------
  y  xs
∉-[] {xs = Ø      } ∉Ø _              = ∉Ø
∉-[] {xs = [ z ]  } {x} p   q with x  z
∉-[] {xs = [ _ ]  }     ∉[] _ | neq _ = ∉[]
∉-[] {xs = [ _ ]  }     _   q | equ   = ∉[]{{p = q}}
∉-[] {xs = ys  zs}     ∉∪  q         =
  ∉∪{{p = ∉-[] it q}}{{∉-[] it q}}

-- Intersection
ι₂⁻¹ :
  {l : Level}
  {A B : Set l}
   ------------------
  Fset(A  B)  Fset B
ι₂⁻¹ Ø         = Ø
ι₂⁻¹ [ ι₁ _ ]  = Ø
ι₂⁻¹ [ ι₂ y ]  = [ y ]
ι₂⁻¹ (xs  ys) = ι₂⁻¹ xs  ι₂⁻¹ ys

∉ι₂⁻¹→ι₂∉ :
  {l : Level}
  {A B : Set l}
  {{_ : hasDecEq A}}
  {{_ : hasDecEq B}}
  (zs : Fset(A  B))
  (y : B)
   ---------------------
  y  ι₂⁻¹ zs  ι₂ y  zs
∉ι₂⁻¹→ι₂∉ Ø _ _ = ∉Ø
∉ι₂⁻¹→ι₂∉ [ ι₁ x ] y ∉Ø = ¬∈→∉ λ{()}
∉ι₂⁻¹→ι₂∉ {A = A} {B} [ ι₂ y' ] y (∉[]{{p = p}}) =
  ∉[]{{p = inj≠ {f = ι₂ {A = A}{B}}(injectionι₂) p}}
∉ι₂⁻¹→ι₂∉ (zs  zs') y ∉∪ =
  ∉∪ {{p = ∉ι₂⁻¹→ι₂∉ zs y it}}{{∉ι₂⁻¹→ι₂∉ zs' y it}}

-- Maximum of a finite set of numbers
maxfs : Fset   
maxfs Ø         = 0
maxfs [ x ]     = x
maxfs (xs  ys) = max (maxfs xs) (maxfs ys)

≤maxfs : ∀{xs x}  x  xs  x  maxfs xs
≤maxfs ∈[] = ≤refl
≤maxfs (∈∪₁ p) = ≤trans (≤maxfs p) ≤max₁
≤maxfs (∈∪₂ p) = ≤trans (≤maxfs p) ≤max₂

maxfs+1∉ :  xs  (maxfs xs +1)  xs
maxfs+1∉ xs =
  ¬∈→∉ λ p  wf.irrefl _<_ wf< (maxfs xs +1) (<+1 (≤maxfs p))

-- Finite ordinals
ordinal :   Fset 
ordinal 0      = Ø
ordinal (n +1) = ordinal n  [ n ]

∉ordinal→≥ :  m n  m  ordinal n  m  n
∉ordinal→≥ _ 0 _ = 0≤
∉ordinal→≥ m (n +1) (∉∪{{q = ∉[]}}) =
  <→+1≤ n m (trich (∉ordinal→≥ m n it) (≠→¬≡ it))

----------------------------------------------------------------------
-- Dependent product
----------------------------------------------------------------------
infixr 6 _,_
record  {l m : Level}(A : Set l)(B : A  Set m) : Set(l  m) where
  constructor _,_
  field
    π₁ : A
    π₂ : B π₁

{-# BUILTIN SIGMA  #-}

open  public

infix 2 ∑-syntax
∑-syntax : {l m : Level}(A : Set l)  (A  Set m)  Set (l  m)
∑-syntax = 
syntax ∑-syntax A  x  B) =  x  A , B

pair :
  {l m : Level}
  {A : Set l}
  (B : A  Set m)
  (x : A)
  (_ : B x)
   -------------
   A B
pair _ x y = (x , y)

----------------------------------------------------------------------
-- Cartesian product
----------------------------------------------------------------------
infixr 7 _×_
_×_ : {l m : Level}  Set l  Set m  Set (l  m)
A × B =  A  _  B)

-- Iterated cartesian product
infixr 6 _^_
_^_ : {l : Level}  Set l    Set l
A ^ 0     = 𝟙
A ^(n +1) = A × (A ^ n)