```module Nom where

{-
This file provides a category theoretic treatment to nominal sets and
equivariant functions. It shows that Nom is a topos.
-}

open import Basics
open import Atoms
open import Perms
open import CatDef
open import PermProp

--------------------------------------------------------------------------------------------------
--Definition Nominal Set
--------------------------------------------------------------------------------------------------

record Nominal : Set₁ where
field
Aₛ : Set
≈ₐ : Rel Aₛ
eq≈ₐ : isEquivalence Aₛ ≈ₐ
Act : Perm → Aₛ → Aₛ
res : Act Preserves₂ pEquiv ⟶ ≈ₐ ⟶ ≈ₐ
p₁p₂↠ : p₁p₂Act {Perm}{Aₛ}{_++_}{≈ₐ}{Act}
ι↠ : ιAct {Perm}{Aₛ}{≈ₐ}{Act} ι

some_supp : Aₛ → List Atom
suppAx : (a : Aₛ) → (b c : Atom) → (b ∉ some_supp a) → (c ∉ some_supp a) → ≈ₐ (Act [ (b , c) ] a)  a

open Nominal public

--------------------------------------------------------------------------------------------------------
--Definition Equivariant functions
--------------------------------------------------------------------------------------------------------

record Equivar (X Y : Nominal) : Set where
field
ufun :  Aₛ X → Aₛ Y
eqi≈ : ufun Preserves (≈ₐ X) ⟶ (≈ₐ Y)
equiv : (p : Perm) → (x : Aₛ X) → (≈ₐ Y) ((Act Y) p (ufun x)) (ufun ((Act X) p x))

open Equivar public

--------------------------------------------------------------------------------------------------------
--Definition finitely supported functions
--------------------------------------------------------------------------------------------------------

record Funfs (X Y : Nominal) : Set where
field
ffun :  Aₛ X → Aₛ Y
fsupp : List Atom
fsuppAx : (b c : Atom) → (b ∉ fsupp) → (c ∉ fsupp) → (∀ (x : (Aₛ X)) → (≈ₐ Y) ((Act Y) [ ( b , c ) ] (ffun ((Act X) [ ( b , c ) ] x))) (ffun x))
feqi≈ : ffun Preserves (≈ₐ X) ⟶ (≈ₐ Y)

open Funfs public

fsch : {a b : Atom} (X Y : Nominal) → (F : Funfs X Y) → (x : Aₛ X) → a ∉ (fsupp F) → b ∉ (fsupp F) → (≈ₐ Y) ((Act Y) [(a , b)] ((ffun F) x)) ((ffun F) ((Act X) [(a , b)] x))
fsch {a}{b} X Y F x a∉f b∉f = let abfx = ((Act Y) [(a , b)] ((ffun F) x)) in let fabx = ((ffun F) ((Act X) [(a , b)] x)) in
let final = fabx
≣< ((Act Y) ι fabx) and abfx by (≈ₐ Y) as (eq≈ₐ Y) on
((Symm (eq≈ₐ Y)) ((ι↠ Y) {fabx})) >
(((Act Y) ι fabx)
≣< ((Act Y) ([(a , b)] ++ [(a , b)]) fabx) and abfx by (≈ₐ Y) as (eq≈ₐ Y) on
((Symm (eq≈ₐ Y)) ((res Y) (λ {w} → bc+bc=ι a b {w}) (≈≡ (eq≈ₐ Y) {fabx}{fabx} refl))) >
(((Act Y) ([(a , b)] ++ [(a , b)]) fabx)
≣< ((Act Y) [(a , b)] ((Act Y) [(a , b)] fabx)) and abfx by (≈ₐ Y) as (eq≈ₐ Y) on
((Symm (eq≈ₐ Y)) ((p₁p₂↠ Y) [(a , b)] [(a , b)] {fabx})) >
(((Act Y) [(a , b)] ((Act Y) [(a , b)] fabx))
≣< abfx and abfx by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (λ {w} → P≡≈ [(a , b)] {w}) ((fsuppAx F) a b a∉f b∉f x)) >
(abfx by (≈ₐ Y) as (eq≈ₐ Y) ▴)))) in (Symm (eq≈ₐ Y)) final

-------------------------------------------------------------------------------------------------------------------
--equivalence relation on finitely supported functions
------------------------------------------------------------------------------------------------------------------

≈fs : {X Y : Nominal} → (Rel (Funfs X Y))
≈fs {X} {Y} = λ F G → (∀ x → (≈ₐ Y) ((ffun F) x) ((ffun G) x))

eq≈fs : {X Y : Nominal} → isEquivalence (Funfs X Y) (≈fs {X} {Y})
eq≈fs {X}{Y} = record { Reflex = λ {F} → λ x → (Reflex (eq≈ₐ Y)) {(ffun F) x}
; Symm = λ {F G} → λ F≈G → λ x → (Symm (eq≈ₐ Y)) (F≈G x)
; Trans = λ {F G H} → λ F≈G → λ G≈H → λ x → (Trans (eq≈ₐ Y)) (F≈G x) (G≈H x)
}

---------------------------------------------------------------------------------------------------------------------------
--Examples of Nominal Sets
---------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------
--Atom is a Nominal Set
----------------------------------------------------------------------------------------------------------------------------

bc∉suppa : (a b c : Atom) → b ∉ (supp a) → c ∉ (supp a) → swap (b , c) a ≡ a
bc∉suppa a b c (a∉as a∉[] a≠b) (a∉as a∉[] a≠c) = swapabc≡c b c a a≠b a≠c

NominalAtom : Nominal
NominalAtom = record { Aₛ = Atom
; ≈ₐ = _≡_
; eq≈ₐ = aEquiv≡ Atom
; Act = PermAct
; res = λ {π₁ π₂ a₁ a₂} → λ π₁≈π₂ → λ a₁≡a₂ → (PermAct π₁ a₁ ≡< cong (λ w → PermAct π₁ w) a₁≡a₂ > (PermAct π₁ a₂ ≡< π₁≈π₂ {a₂} > (PermAct π₂ a₂) ▪ ))
; p₁p₂↠ = λ p₁ p₂ → (λ {x} → sym (p₁++p₂≡p₂p₁ {x} p₂ p₁))
; ι↠ = λ {x} → refl

; some_supp = supp
; suppAx = λ a → (λ b c → (λ b≠a c≠a → bc∉suppa a b c b≠a c≠a))
}

-------------------------------------------------------------------------------------------------------------------------
--Boolean is a discrete Nominal Set
-------------------------------------------------------------------------------------------------------------------------

𝔹Nom : Nominal
𝔹Nom = record { Aₛ = 𝔹
; ≈ₐ = _≡_
; eq≈ₐ = aEquiv≡ 𝔹
; Act = λ π → λ b → b
; res = λ π₁≈π₂ → λ b≡b → b≡b
; p₁p₂↠ = λ p₁ p₂ → λ {b} → (Reflex (aEquiv≡ 𝔹)) {b}
; ι↠ = λ {b} → (Reflex (aEquiv≡ 𝔹)) {b}
; some_supp = λ b → []
; suppAx = λ b → λ _ _ _ _ → (Reflex (aEquiv≡ 𝔹)) {b}
}

------------------------------------------------------------------------------------------------------------------------------
--NOMINAL SETS & EQUIVARIANT FUNCTIONS CATEGORY
------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
--equivalence relation on equivariant functions
-----------------------------------------------------------------------------------------------------------------------

≈̬ : {X Y : Nominal} → Rel (Equivar X Y)
≈̬ {X}{Y} = λ F G → (∀ x → (≈ₐ Y) ((ufun F) x) ((ufun G) x))

vEq : ∀ {X Y} → isEquivalence (Equivar X Y) (≈̬ {X}{Y})
vEq {X}{Y} = record { Reflex = λ {F} → (λ x → (Reflex (eq≈ₐ Y)) {(ufun F) x})
; Symm = λ {F G} → λ F≈G → (λ x → (Symm (eq≈ₐ Y)) (F≈G x))
; Trans = λ {F G H} → λ F≈G → λ G≈H → (λ x → (Trans (eq≈ₐ Y)) (F≈G x) (G≈H x))
}

----------------------------------------------------------------------------------------------------------------
--composition of equivariant functions
----------------------------------------------------------------------------------------------------------------

ø : {X Y Z : Nominal} → (F : Equivar X Y) → (G : Equivar Y Z) → Equivar X Z
ø {X}{Y}{Z} F G = record { ufun = (ufun G) ∘ (ufun F)
; eqi≈ = λ {x₁ x₂} → λ x₁≈x₂ → (eqi≈ G) ((eqi≈ F) x₁≈x₂)
; equiv = λ p x → let pgfx =  (Act Z) p (((ufun G) ∘ (ufun F)) x) in
let x≈x =  ((((ufun G) ∘ (ufun F)) ((Act X) p x))
≣< ((ufun G) ((Act Y) p ((ufun F) x))) and pgfx by (≈ₐ Z) as (eq≈ₐ Z) on ((eqi≈ G) ((Symm (eq≈ₐ Y)) ( (equiv F) p x ) )) >
(((ufun G) ((Act Y) p ((ufun F) x)))
≣< pgfx and pgfx by (≈ₐ Z) as (eq≈ₐ Z) on ((Symm (eq≈ₐ Z)) ((equiv G) p ((ufun F) x))) >
(pgfx by (≈ₐ Z) as (eq≈ₐ Z) ▴))) in (Symm (eq≈ₐ Z)) x≈x
}

----------------------------------------------------------------------------------------------------------------
--identity equivariant function
----------------------------------------------------------------------------------------------------------------

ø1 : (X : Nominal) → Equivar X X
ø1 X = record { ufun = λ x → x
; eqi≈ = λ x₁≈x₂ → x₁≈x₂
; equiv = λ p x → (Reflex (eq≈ₐ X)) {(Act X) p x}
}

----------------------------------------------------------------------------------------------------------------
--identity axioms
----------------------------------------------------------------------------------------------------------------

idl : {X Y : Nominal} → (F : Equivar X Y) → ≈̬ (ø (ø1 X) F) F
idl {X}{Y} F = λ x → (Reflex (eq≈ₐ Y)) {(ufun F) x}

idr : {X Y : Nominal} → (G : Equivar X Y) → ≈̬ (ø G (ø1 Y)) G
idr {X}{Y} G = λ x → (Reflex (eq≈ₐ Y)) {(ufun G) x}

----------------------------------------------------------------------------------------------------------------
--associativity axiom
----------------------------------------------------------------------------------------------------------------

assoEq : {X Y Z W : Nominal} → (F : Equivar X Y) → (G : Equivar Y Z)  → (H : Equivar Z W) → ≈̬ (ø (ø F G) H) (ø F (ø G H))
assoEq {X}{Y}{Z}{W} F G H = λ x → (Reflex (eq≈ₐ W)) {(((ufun H) ∘ (ufun G)) ∘ (ufun F)) x}

-------------------------------------------------------------------------------------------------------------------
--Nominal Sets and Equivariant functions category
-------------------------------------------------------------------------------------------------------------------

NomCat : Cat
NomCat = record { Obj = Nominal
; _⇒_ = λ X Y → Equivar X Y
; _≈_ = λ {M N} → ≈̬ {M}{N}
; isEq = λ {M N} → vEq {M}{N}
; id = λ {N} → ø1 N
; _⊚_ = λ MN NO → ø MN NO
; id1 = λ F → idl F
; id2 = λ G → idr G
; asso = λ f g h → assoEq f g h
; resp = λ {X Y Z} → λ {f g h i} → λ f≈g → λ h≈i → (λ x → let igx = ((ufun i) ∘ (ufun g)) x in
let hf≈ig = ( ((ufun h) ∘ (ufun f)) x
≣< (((ufun h) ∘ (ufun g)) x) and igx by (≈ₐ Z) as (eq≈ₐ Z) on ((eqi≈ h) (f≈g x)) >
( ((ufun h) ∘ (ufun g)) x
≣< igx and igx by (≈ₐ Z) as (eq≈ₐ Z) on (h≈i ((ufun g) x)) >
( igx by (≈ₐ Z) as (eq≈ₐ Z)  ▴))) in hf≈ig)

}

-----------------------------------------------------------------------------------------------------------------------
--Terminal Object
-----------------------------------------------------------------------------------------------------------------------

NomT : Nominal
NomT = record { Aₛ = ⊤
; ≈ₐ = _≡_
; eq≈ₐ = record { Reflex = λ {i} → refl
; Symm = λ {i j} → λ i≈j → sym (i≈j)
; Trans = λ {i j k} → λ i≈j → λ j≈k → i ≡< i≈j > j≈k
}
; Act = λ p a → One
; res = λ {π₁ π₂ a₁ a₂} → λ π₁≈π₂ → λ a₁≡a₂ → refl
; p₁p₂↠ = λ p₁ p₂ → (λ {a} → refl)
; ι↠ = λ {a} → refl
; some_supp = λ a → []
; suppAx = λ a → λ b c → λ b∉a c∉a → refl
}

-----------------------------------------------------------------------------------------------------------------------
--Unique morphism to terminal object
-----------------------------------------------------------------------------------------------------------------------

N→T : (N : Nominal) → (Equivar N NomT)
N→T N = record { ufun = λ n → One
; eqi≈ = λ {n₁ n₂} → λ n₁≈n₂ → refl
; equiv = λ p → λ n → refl
}

TNominal : Terminal NomCat
TNominal = record { Ter = NomT
; A→T = λ N → N→T N
; uni = λ N → λ F → (λ x → refl)
}

--------------------------------------------------------------------------------------------------------------------------
--Initial object
-------------------------------------------------------------------------------------------------------------------------

NomI : Nominal
NomI = record { Aₛ = ⊥
; ≈ₐ = _≡_
; eq≈ₐ = record { Reflex = λ {i} → refl
; Symm = λ {i j} → λ i≈j → sym (i≈j)
; Trans = λ {i j k} → λ i≈j → λ j≈k → i ≡< i≈j > j≈k
}
; Act = λ p → λ a → a
; res = λ {π₁} {π₂} → λ { { () } }
; p₁p₂↠ = λ p₁ p₂ → refl
; ι↠ = refl
; some_supp = λ ()
; suppAx = λ ()
}

-------------------------------------------------------------------------------------------------------------------
--Unique morphism from initial object
-------------------------------------------------------------------------------------------------------------------

I→N : (N : Nominal) → (Equivar NomI N)
I→N N = record { ufun = λ ()
; eqi≈ = λ {i₁ i₂} → λ i₁≈i₂ → ≈≡ (eq≈ₐ N) (cong (λ ()) i₁≈i₂)
; equiv = λ p → λ ()
}

INominal : Initial NomCat
INominal = record { Ini = NomI
; I→A = λ N → I→N N
; uni = λ N → λ F → λ ()
}

------------------------------------------------------------------------------------------------------------------------------------
--CARTESIAN CATEGORY
------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------------------
--Product
-----------------------------------------------------------------------------------------------------------------------

Prod : (X Y : Nominal) → Nominal
Prod X Y = record { Aₛ = (Aₛ X) × (Aₛ Y)
; ≈ₐ = λ p₁ p₂ → (((≈ₐ X) (proj₁ p₁) (proj₁ p₂)) × ((≈ₐ Y) (proj₂ p₁) (proj₂ p₂)))
; eq≈ₐ = record { Reflex = λ {p₁} → ((Reflex (eq≈ₐ X)) {proj₁ p₁} , (Reflex (eq≈ₐ Y)) {proj₂ p₁})
; Symm = λ {p₁ p₂} → λ p₁≈p₂ → ((Symm (eq≈ₐ X)) (proj₁ p₁≈p₂) , (Symm (eq≈ₐ Y)) (proj₂ p₁≈p₂))
; Trans = λ {p₁ p₂ p₃} → λ p₁≈p₂ → λ p₂≈p₃ → ((Trans (eq≈ₐ X)) (proj₁ p₁≈p₂) (proj₁ p₂≈p₃) , (Trans (eq≈ₐ Y)) (proj₂ p₁≈p₂) (proj₂ p₂≈p₃))
}
; Act = λ π → λ p → ((Act X) π (proj₁ p) , (Act Y) π (proj₂ p))
; res = λ {π₁ π₂ p₁ p₂} → λ π₁≈π₂ → λ p₁≈p₂ → ((res X) {π₁} {π₂} {proj₁ p₁} {proj₁ p₂} π₁≈π₂ (proj₁ p₁≈p₂) , (res Y) {π₁}{π₂}{proj₂ p₁}{proj₂ p₂} π₁≈π₂ (proj₂ p₁≈p₂))
; p₁p₂↠ = λ π π' → (λ {p} → (((p₁p₂↠ X) π π' {proj₁ p}) , ((p₁p₂↠ Y) π π' {proj₂ p})))
; ι↠ = λ {p} → ((ι↠ X) {proj₁ p} , (ι↠ Y) {proj₂ p})
; some_supp = λ p → ((some_supp X) (proj₁ p)) ++ ((some_supp Y) (proj₂ p))
; suppAx = λ p → λ b c → λ b∉p → λ c∉p → ((suppAx X) (proj₁ p) b c (∉⊆₁ b b∉p) (∉⊆₁ c c∉p) ,
(suppAx Y) (proj₂ p) b c (∉⊆₂ {(some_supp X) (proj₁ p)}{(some_supp Y) (proj₂ p)} b b∉p) (∉⊆₂ {(some_supp X) (proj₁ p)}{(some_supp Y) (proj₂ p)} c c∉p))
}

-----------------------------------------------------------------------------------------------------------------------------
--Projection morphism
-----------------------------------------------------------------------------------------------------------------------------

Fst : (X Y : Nominal) → Equivar (Prod X Y) X
Fst X Y = record { ufun = λ p → (proj₁ p)
; eqi≈ = λ {p₁ p₂} → λ p₁≈p₂ → (proj₁ p₁≈p₂)
; equiv = λ π → λ p → (Reflex (eq≈ₐ X)) {(Act X) π (proj₁ p)}
}

Snd : (X Y : Nominal) → Equivar (Prod X Y) Y
Snd X Y = record { ufun = λ p → (proj₂ p)
; eqi≈ = λ {p₁ p₂} → λ p₁≈p₂ → (proj₂ p₁≈p₂)
; equiv = λ π → λ p → (Reflex (eq≈ₐ Y)) {(Act Y) π (proj₂ p)}
}

-----------------------------------------------------------------------------------------------------------------------------
--Unique morphism
-----------------------------------------------------------------------------------------------------------------------------

Z→X×Y : (X Y Z : Nominal) → (F : Equivar Z X) → (G : Equivar Z Y) → Equivar Z (Prod X Y)
Z→X×Y X Y Z F G = record { ufun = λ z → ((ufun F) z , (ufun G) z)
;  eqi≈ = λ {z₁ z₂} → λ z₁≈z₂ → ((eqi≈ F) z₁≈z₂ , (eqi≈ G) z₁≈z₂)
; equiv = λ π → λ z → ((equiv F) π z , (equiv G) π z)
}

Com₁ : (X Y Z : Nominal) → (F : Equivar Z X) → (G : Equivar Z Y) → ≈̬ {Z}{X}(ø (Z→X×Y X Y Z F G) (Fst X Y)) F
Com₁ X Y Z F G = λ z → (Reflex (eq≈ₐ X)) {(ufun F) z}

Com₂ : (X Y Z : Nominal) → (F : Equivar Z X) → (G : Equivar Z Y) → ≈̬ {Z}{Y}(ø (Z→X×Y X Y Z F G) (Snd X Y)) G
Com₂ X Y Z F G = λ z → (isEquivalence.Reflex (eq≈ₐ Y)) {(ufun G) z}

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

_Nomₓ_ : (X Y : Nominal) → Product {NomCat} X Y
X Nomₓ Y = record { X×Y = Prod X Y
; π₁ = Fst X Y
; π₂ = Snd X Y
; 〈_,_〉 = λ {Z} → λ F G → Z→X×Y X Y Z F G
; c₁ = λ {Z} → λ {F} → λ {G}  → Com₁ X Y Z F G
; c₂ = λ {Z} → λ {F} → λ {G}  → Com₂ X Y Z F G
; uni = λ {Z} → λ {F G H} → λ HF → λ HG → (λ z → ((Symm (eq≈ₐ X)) (HF z) , (Symm (eq≈ₐ Y)) (HG z)))
}

--------------------------------------------------------------------------------------------------------------------------------
--Cartesian category
--------------------------------------------------------------------------------------------------------------------------------

CarNom : CarCat
CarNom = record { Ucat = NomCat
; UTer =  TNominal
; UProd = λ X Y → X Nomₓ Y
}

-------------------------------------------------------------------------------------------------------------------------------------------------------
--COCARTESIAN CATEGORY
-------------------------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------------
--Sum object
-----------------------------------------------------------------------------------------------------------------------------------

Sum : (X Y : Nominal) → Nominal
Sum X Y = record { Aₛ = (Aₛ X) ⊎ (Aₛ Y)
; ≈ₐ = λ {(inl x₁) (inl x₂) → (≈ₐ X) x₁ x₂ ;
(inr y₁) (inr y₂) → (≈ₐ Y) y₁ y₂ ;
(inl x₁) (inr y₂) → ⊥ ;
(inr y₁) (inl x₂) → ⊥ }
; eq≈ₐ =  record { Reflex = λ { {inl x} → (Reflex (eq≈ₐ X)) {x} ;
{inr y} → (Reflex (eq≈ₐ Y)) {y} }
; Symm = λ { {(inl x₁)} {(inl x₂)} → λ x₁≈x₂ → (Symm (eq≈ₐ X))  x₁≈x₂ ;
{(inr y₁)} {(inr y₂)} → λ y₁≈y₂ → (Symm (eq≈ₐ Y)) y₁≈y₂ ;
{(inl x₁)} {(inr y₂)} → λ () ;
{(inr y₁)} {(inl x₂)} → λ () }
; Trans = λ { {(inl x₁)} {(inl x₂)} {(inl x₃)} → λ x₁≈x₂ → λ x₂≈x₃ → (Trans (eq≈ₐ X)) x₁≈x₂ x₂≈x₃ ;
{(inr y₁)} {(inr y₂)} {(inr y₃)} → λ y₁≈y₂ → λ y₂≈y₃ → (Trans (eq≈ₐ Y)) y₁≈y₂ y₂≈y₃ ;
{(inl x₁)} {(inl x₂)} {(inr y₃)} → λ x₁≈x₂ → λ () ;
{(inl x₁)} {(inr y₂)} {(inl x₃)} → λ () ;
{(inl x₁)} {(inr y₂)} {(inr y₃)} → λ () ;
{(inr y₁)} {(inl x₂)} {(inl x₃)} → λ () ;
{(inr y₁)} {(inl x₂)} {(inr y₃)} → λ () ;
{(inr y₁)} {(inr y₂)} {(inl x₃)} → λ y₁≈y₂ → λ () } }
; Act =  λ π → λ { (inl x) → inl ((Act X) π x) ;
(inr y) → inr ((Act Y) π y) }
; res = λ {π₁}{π₂} → λ { {inl x₁} {inl x₂} → λ π₁≈π₂ → λ x₁≈x₂ → (res X) {π₁}{π₂}{x₁}{x₂} π₁≈π₂ x₁≈x₂ ;
{inr y₁} {inr y₂} → λ π₁≈π₂ → λ y₁≈y₂ → (res Y) {π₁}{π₂}{y₁}{y₂} π₁≈π₂ y₁≈y₂ ;
{inl x₁} {inr y₂} → λ π₁≈π₂ → λ () ;
{inr y₁} {inl x₂} → λ π₁≈π₂ → λ () }
; p₁p₂↠ = λ π π' → λ  { {inl x} → ((p₁p₂↠ X) π π' {x}) ;
{inr y} → ((p₁p₂↠ Y) π π' {y}) }
; ι↠ = λ { {inl x} → (ι↠ X) {x} ;
{inr y} → (ι↠ Y) {y} }
; some_supp = λ { (inl x) → (some_supp X) x ;
(inr y) → (some_supp Y) y }
; suppAx = λ { (inl x) → λ b c → λ b∉x → λ c∉x → (suppAx X) x b c b∉x c∉x ;
(inr y) → λ b c → λ b∉y → λ c∉y → (suppAx Y) y b c b∉y c∉y }
}

-----------------------------------------------------------------------------------------------------------------------------
--injection morphisms
-----------------------------------------------------------------------------------------------------------------------------

Fst' : (X Y : Nominal) → Equivar X (Sum X Y)
Fst' X Y = record { ufun = λ x → (inl x)
; eqi≈ = λ {x₁ x₂} → λ x₁≈x₂ → x₁≈x₂
; equiv = λ π → λ x → (Reflex (eq≈ₐ (Sum X Y))) {inl ((Act X) π x)}
}

Snd' : (X Y : Nominal) → Equivar Y (Sum X Y)
Snd' X Y = record { ufun = λ y → (inr y)
; eqi≈ = λ {y₁ y₂} → λ y₁≈y₂ → y₁≈y₂
; equiv = λ π → λ y → (Reflex (eq≈ₐ (Sum X Y))) {inr ((Act Y) π y)}
}

-------------------------------------------------------------------------------------------------------------------------
--unique morphism
------------------------------------------------------------------------------------------------------------------------

X+Y→Z : (X Y Z : Nominal) → (F : Equivar X Z) → (G : Equivar Y Z) → Equivar (Sum X Y) Z
X+Y→Z X Y Z F G = record { ufun = λ {(inl x) → (ufun F) x ;
(inr y) → (ufun G) y }
;  eqi≈ = λ { {(inl x₁)}{(inl x₂)} → λ x₁≈x₂ → (eqi≈ F) x₁≈x₂ ;
{(inr y₁)}{(inr y₂)} → λ y₁≈y₂ → (eqi≈ G) y₁≈y₂ ;
{(inl x₁)}{(inr y₂)} → λ () ;
{(inr y₁)}{(inl x₂)} → λ () }
; equiv = λ π → λ { (inl x) → (equiv F) π x ;
(inr y) → (equiv G) π y }
}

Com₁' : (X Y Z : Nominal) → (F : Equivar X Z) → (G : Equivar Y Z) → ≈̬ {X}{Z}(ø (Fst' X Y) (X+Y→Z X Y Z F G)) F
Com₁' X Y Z F G = λ x → (Reflex (eq≈ₐ Z)) {(ufun F) x}

Com₂' : (X Y Z : Nominal) → (F : Equivar X Z) → (G : Equivar Y Z) → ≈̬ {Y}{Z}(ø (Snd' X Y) (X+Y→Z X Y Z F G)) G
Com₂' X Y Z F G = λ y → (Reflex (eq≈ₐ Z)) {(ufun G) y}

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

_Nom₊_ : (X Y : Nominal) → Coproduct {NomCat} X Y
X Nom₊ Y = record { X+Y = Sum X Y
; i₁ = Fst' X Y
; i₂ = Snd' X Y
; [[_,_]] = λ {Z} → λ F G → X+Y→Z X Y Z F G
; c₁' = λ {Z} → λ {F} → λ {G}  → Com₁' X Y Z F G
; c₂' = λ {Z} → λ {F} → λ {G}  → Com₂' X Y Z F G
; uni' = λ {Z} → λ {F G H} → λ HF → λ HG → λ { (inl x) → (Symm (eq≈ₐ Z)) (HF x) ;
(inr y) → (Symm (eq≈ₐ Z)) (HG y) }
}

------------------------------------------------------------------------------------------------------------------------
--Co-cartesian category
------------------------------------------------------------------------------------------------------------------------

CoCarNom : CoCarCat
CoCarNom = record { UCcat = NomCat
; UIni = INominal
; UCoProd = λ X Y → X Nom₊ Y
}

-------------------------------------------------------------------------------------------------------------------------------
--CARTESIAN CLOSED CATEGORY
-------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------
--EXPONENTIAL OBJECT
-------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------------
--action on finitely supported functions
----------------------------------------------------------------------------------------------------------------------------------

fAct : {X Y : Nominal} → Perm → (F : Funfs X Y) → (Funfs X Y)
fAct {X}{Y} π F = record { ffun = λ x → (Act Y) π ((ffun F) ((Act X) (invPerm π) x))
; fsupp = (fsupp F) ++ (flatten π)
; fsuppAx = λ b c → λ b∉s → λ c∉s → (λ x → (Symm (eq≈ₐ Y))
((Act Y) π ((ffun F) ((Act X) (invPerm π) x))
≣< ((Act Y) π ((Act Y) [ ( b , c ) ] ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))))
and (((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))))))
by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) {π} {π}{(ffun F) ((Act X) (invPerm π) x)}{(Act Y) [ ( b , c ) ]
((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))}(P≡≈ π)
((Symm (eq≈ₐ Y)) ((fsuppAx F) b c (∉⊆₁ {fsupp F}{flatten π} b b∉s)
(∉⊆₁ {fsupp F}{flatten π} c c∉s) ((Act X) (invPerm π) x)))) >
((Act Y) π ((Act Y) [ ( b , c ) ] ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x))))
≣< ((Act Y) ([ ( b , c ) ] ++ π)  ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x))))
and (((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))))))
by (≈ₐ Y) as (eq≈ₐ Y) on
((p₁p₂↠ Y) π [ ( b , c ) ] {(ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x))}) >
((Act Y) ( [ ( b , c ) ] ++ π) ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))
≣< ((Act Y) (π ++ [ ( b , c ) ])  ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x))))
and (((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))))))
by (≈ₐ Y) as (eq≈ₐ Y) on
(res Y) { [ ( b , c ) ] ++ π }{π ++  [ ( b , c ) ] }
{((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))}
{((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))}
(ab∉pcom b c π (∉⊆₂ {fsupp F}{flatten π} b b∉s)
(∉⊆₂ {fsupp F}{flatten π} c c∉s)) (≈≡ (eq≈ₐ Y)
{((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))}
{((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))} refl) >
((Act Y) (π ++ [ ( b , c ) ]) ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))
≣< ((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)))))
and (((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))))))
by (≈ₐ Y) as (eq≈ₐ Y) on
(Symm (eq≈ₐ Y)) ((p₁p₂↠ Y) [ ( b , c ) ] π
{(ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x))}) >
((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x))))
≣<
(((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))))))
and (((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))))))
by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (λ {x} → P≡≈ [ ( b , c ) ] {x}) ((res Y) (P≡≈ π) ((feqi≈ F) ((Act X) [ ( b , c ) ] ((Act X) (invPerm π) x)
≣<  ((Act X) ((invPerm π) ++ [ ( b , c ) ] ) x)
and ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))
by (≈ₐ X) as (eq≈ₐ X) on
(p₁p₂↠ X) [ ( b , c) ] (invPerm π) {x} >
((Act X) ((invPerm π) ++ [ ( b , c ) ] ) x
≣< ((Act X) ([ ( b , c ) ] ++ (invPerm π)) x)
and ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))
by (≈ₐ X) as (eq≈ₐ X) on
(res X) {(invPerm π) ++ [ ( b , c ) ]}
{[ ( b , c ) ] ++ (invPerm π)}{x}{x}
(++⁻¹ [ ( b , c ) ] π (ab∉pcom b c π (∉⊆₂ {fsupp F}{flatten π} b b∉s)
(∉⊆₂ {fsupp F}{flatten π} c c∉s))) (≈≡ (eq≈ₐ X) {x}{x} refl) >
((Act X) ([ ( b , c ) ] ++ (invPerm π)) x
≣< ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))
and ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))
by (≈ₐ X) as (eq≈ₐ X) on
(Symm (eq≈ₐ X)) ((p₁p₂↠ X) (invPerm π)
[ ( b , c ) ] {x}) >
(((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x) by (≈ₐ X) as (eq≈ₐ X) ▴))))))))                >
(((Act Y) [ ( b , c ) ] ((Act Y) π ((ffun F) ((Act X) (invPerm π) ((Act X) [ ( b , c ) ] x))))) by (≈ₐ Y) as (eq≈ₐ Y) ▴)))))))

; feqi≈ = λ {x₁ x₂} → λ x₁≈x₂ → (res Y) (P≡≈ π) ((feqi≈ F) ((res X) (P≡≈ (invPerm π)) x₁≈x₂))
}

-----------------------------------------------------------------------------------------------------------------------------------------------------
--action preserves equivalence relation
-----------------------------------------------------------------------------------------------------------------------------------------------------

fActRes : (X Y : Nominal) → fAct Preserves₂ pEquiv ⟶ (≈fs {X} {Y})  ⟶ (≈fs {X} {Y})
fActRes X Y = λ {π₁ π₂ F G} → λ π₁≈π₂ → λ F≈G → λ x → (((Act Y) π₁ ((ffun F) ((Act X) (invPerm π₁) x)))
≣<  ((Act Y) π₂ ((ffun F) ((Act X) (invPerm π₁) x)))
and ((Act Y) π₂ ((ffun G) ((Act X) (invPerm π₂) x)))
by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) π₁≈π₂ (≈≡ (eq≈ₐ Y) {(ffun F) ((Act X) (invPerm π₁) x)}{(ffun F) ((Act X) (invPerm π₁) x)} refl)) >
(((Act Y) π₂ ((ffun F) ((Act X) (invPerm π₁) x)))
≣< ((Act Y) π₂ ((ffun G) ((Act X) (invPerm π₁) x)))
and ((Act Y) π₂ ((ffun G) ((Act X) (invPerm π₂) x)))
by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (P≡≈ π₂) (F≈G ((Act X) (invPerm π₁) x))) >
(((Act Y) π₂ ((ffun G) ((Act X) (invPerm π₁) x)))
≣< ((Act Y) π₂ ((ffun G) ((Act X) (invPerm π₂) x)))
and ((Act Y) π₂ ((ffun G) ((Act X) (invPerm π₂) x)))
by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (P≡≈ π₂) ((feqi≈ G) ((res X) (p≈q⇒p⁻¹≈q⁻¹ π₁ π₂ π₁≈π₂) (≈≡ (eq≈ₐ X){x}{x} refl)))) >
(((Act Y) π₂ ((ffun G) ((Act X) (invPerm π₂) x))) by (≈ₐ Y) as (eq≈ₐ Y) ▴))))

-----------------------------------------------------------------------------------------------------------------------------------------
--associativity axiom
-----------------------------------------------------------------------------------------------------------------------------------------

fp₁p₂↠ : {X Y : Nominal} → p₁p₂Act {Perm}{Funfs X Y}{_++_}{≈fs {X}{Y}}{fAct {X}{Y}}
fp₁p₂↠ {X}{Y} = λ π₁ π₂ → (λ {F} →  (λ x → (((Act Y) π₁ ((Act Y) π₂ ((ffun F) ((Act X) (invPerm π₂) ((Act X) (invPerm π₁) x)))))
≣< ((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) (invPerm π₂) ((Act X) (invPerm π₁) x))))
and ((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) (invPerm (π₂ ++ π₁)) x)))
by (≈ₐ Y) as (eq≈ₐ Y) on
((p₁p₂↠ Y) π₁ π₂ {(ffun F) ((Act X) (invPerm π₂) ((Act X) (invPerm π₁) x))}) >
(((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) (invPerm π₂) ((Act X) (invPerm π₁) x))))
≣< ((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) ((invPerm π₁) ++ (invPerm π₂)) x)))
and ((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) (invPerm (π₂ ++ π₁)) x)))
by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (P≡≈ (π₂ ++ π₁)) ((feqi≈ F) ((p₁p₂↠ X) (invPerm π₂) (invPerm π₁) {x}))) >
(((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) ((invPerm π₁) ++ (invPerm π₂)) x)))
≣< ((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) (invPerm (π₂ ++ π₁)) x)))
and ((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) (invPerm (π₂ ++ π₁)) x)))
by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (P≡≈ (π₂ ++ π₁)) ((feqi≈ F) ((res X)
((isEquivalence.Symm (pEquiv≡)) {invPerm (π₂ ++ π₁)}{(invPerm π₁) ++ (invPerm π₂)} (p₁p₂⁻¹≈p₂⁻¹p₁⁻¹ π₂ π₁)) (≈≡ (eq≈ₐ X) {x}{x} refl)))) >
(((Act Y) (π₂ ++ π₁) ((ffun F) ((Act X) (invPerm (π₂ ++ π₁)) x))) by (≈ₐ Y) as (eq≈ₐ Y) ▴) )))))

-----------------------------------------------------------------------------------------------------------------------------------------------
--identity axiom
-----------------------------------------------------------------------------------------------------------------------------------------------

fι↠ : {X Y : Nominal} → ιAct {Perm}{Funfs X Y}{≈fs {X}{Y}}{fAct {X}{Y}} ι
fι↠ {X}{Y} = λ {F} → (λ x → (((Act Y) ι ((ffun F) ((Act X) ι x)))
≣< ((ffun F) ((Act X) ι x))
and ((ffun F) x)
by (≈ₐ Y) as (eq≈ₐ Y) on
(ι↠ Y) {((ffun F) ((Act X) ι x))} >
(((ffun F) ((Act X) ι x))
≣< ((ffun F) x)
and ((ffun F) x)
by (≈ₐ Y) as (eq≈ₐ Y) on
(feqi≈ F)((ι↠ X) {x}) >
(((ffun F) x) by (≈ₐ Y) as (eq≈ₐ Y) ▴))))

------------------------------------------------------------------------------------------------------------------
--exponential object
------------------------------------------------------------------------------------------------------------------

NomExp : (X Y : Nominal) → Nominal
NomExp X Y = record { Aₛ = Funfs X Y
; ≈ₐ = ≈fs {X} {Y}
; eq≈ₐ = eq≈fs {X}{Y}
; Act = λ π → λ F → fAct {X}{Y} π F
; res = λ {π₁ π₂ F G} → λ π₁≈π₂ → λ F≈G → fActRes X Y {π₁}{π₂}{F}{G} π₁≈π₂ F≈G
; p₁p₂↠ = fp₁p₂↠ {X}{Y}
; ι↠ = λ {F} → fι↠ {X}{Y}{F}
; some_supp = λ F → (fsupp F)
; suppAx = λ F → λ b c → λ b∉F → λ c∉F → λ x → ((fsuppAx F) b c b∉F c∉F x)
}

-------------------------------------------------------------------------------------------------------------------------------------
--APPLICATION MORPHISM
-------------------------------------------------------------------------------------------------------------------------------------

appN : (X Y : Nominal) → Equivar (Prod (NomExp X Y) X) Y
appN X Y = record { ufun = λ fx → (ffun (proj₁ fx)) (proj₂ fx)
; eqi≈ = λ {fx₁ fx₂} → λ fx₁≈fx₂ → ((ffun (proj₁ fx₁)) (proj₂ fx₁)
≣< ((ffun (proj₁ fx₂)) (proj₂ fx₁)) and ((ffun (proj₁ fx₂)) (proj₂ fx₂)) by (≈ₐ Y) as (eq≈ₐ Y) on ((proj₁ fx₁≈fx₂) (proj₂ fx₁)) >
((ffun (proj₁ fx₂)) (proj₂ fx₁)
≣< ((ffun (proj₁ fx₂)) (proj₂ fx₂)) and ((ffun (proj₁ fx₂)) (proj₂ fx₂)) by (≈ₐ Y) as (eq≈ₐ Y) on (feqi≈ (proj₁ fx₂))(proj₂ fx₁≈fx₂) >
(((ffun (proj₁ fx₂)) (proj₂ fx₂)) by (≈ₐ Y) as (eq≈ₐ Y) ▴)))
; equiv = λ π → λ fx → (isEquivalence.Symm (eq≈ₐ Y))
(((Act Y) π ((ffun (proj₁ fx))((Act X) (invPerm π) ((Act X) π (proj₂ fx)))))
≣< ((Act Y) π ((ffun (proj₁ fx))((Act X) (π ++ (invPerm π)) (proj₂ fx)))) and ((Act Y) π ((ffun (proj₁ fx)) (proj₂ fx))) by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (P≡≈ π) ((feqi≈ (proj₁ fx))((p₁p₂↠ X) (invPerm π) π {proj₂ fx})))  >
(((Act Y) π ((ffun (proj₁ fx))((Act X) (π ++ (invPerm π)) (proj₂ fx))))
≣<  ((Act Y) π ((ffun (proj₁ fx))((Act X) ι (proj₂ fx)))) and ((Act Y) π ((ffun (proj₁ fx)) (proj₂ fx))) by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (P≡≈ π) ((feqi≈ (proj₁ fx))((res X)(pp⁻¹≡ι π)(≈≡ (eq≈ₐ X) {proj₂ fx}{proj₂ fx} refl))))   >
(((Act Y) π ((ffun (proj₁ fx))((Act X) ι (proj₂ fx))))
≣< ((Act Y) π ((ffun (proj₁ fx)) (proj₂ fx))) and ((Act Y) π ((ffun (proj₁ fx)) (proj₂ fx))) by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (P≡≈ π) ((feqi≈ (proj₁ fx))((ι↠ X) {proj₂ fx})))   >
(((Act Y) π ((ffun (proj₁ fx)) (proj₂ fx))) by (≈ₐ Y) as (eq≈ₐ Y) ▴))))
}

----------------------------------------------------------------------------------------------------------------------------------------
--CURRYING
----------------------------------------------------------------------------------------------------------------------------------------

currN : (X Y Z : Nominal) → (F : Equivar (Prod Z X) Y) → Equivar Z (NomExp X Y)
currN X Y Z F = record { ufun = λ z → record { ffun = λ x → (ufun F) ( z , x )
; fsupp = (some_supp Z) z
; fsuppAx = λ b c → λ b∉s → λ c∉s → λ x →
(((Act Y) [ ( b , c ) ] ((ufun F) (z , ((Act X) [ ( b , c ) ] x))))
≣< ((Act Y) [ ( b , c ) ] ((ufun F) (((Act Z) [ ( b , c ) ] z) , ((Act X) [ ( b , c ) ] x)))) and (ufun F (z , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((res Y) (λ {x} → P≡≈ [ ( b , c ) ] {x}) ((eqi≈ F) (((isEquivalence.Symm (eq≈ₐ Z))((suppAx Z) z b c b∉s c∉s)) ,
((isEquivalence.Reflex (eq≈ₐ X)){(Act X) [ ( b , c ) ] x }))))  >
((Act Y) [ ( b , c ) ] ((ufun F) (((Act Z) [ ( b , c ) ] z) , ((Act X) [ ( b , c ) ] x)))
≣< ((ufun F) (((Act Z) [ ( b , c ) ] ((Act Z) [ ( b , c ) ] z)) , ((Act X) [ ( b , c ) ] ((Act X) [ ( b , c ) ] x)))) and (ufun F (z , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((equiv F) [ ( b , c ) ] ((Act (Prod Z X)) [ ( b , c ) ] ( z , x ))) >
(((ufun F) (((Act Z) [ ( b , c ) ] ((Act Z) [ ( b , c ) ] z)) , ((Act X) [ ( b , c ) ] ((Act X) [ ( b , c ) ] x))))
≣< ((ufun F) (((Act Z) ([ ( b , c ) ] ++ [ ( b , c ) ]) z) , ((Act X) ([ ( b , c ) ] ++ [ ( b , c ) ]) x))) and (ufun F (z , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((eqi≈ F) (((p₁p₂↠ Z) [ ( b , c ) ] [ ( b , c ) ] {z}) , ((p₁p₂↠ X) [ ( b , c ) ] [ ( b , c ) ] {x}))) >
(((ufun F) (((Act Z) ([ ( b , c ) ] ++ [ ( b , c ) ]) z) , ((Act X) ([ ( b , c ) ] ++ [ ( b , c ) ]) x)))
≣< ((ufun F) (((Act Z) ι z) , ((Act X) ι x))) and (ufun F (z , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((eqi≈ F) (((res Z) (pp⁻¹≡ι [ ( b , c ) ]) (≈≡ (eq≈ₐ Z) {z}{z} refl)) , ((res X) (pp⁻¹≡ι [ ( b , c ) ]) (≈≡ (eq≈ₐ X) {x}{x} refl)))) >
(((ufun F) (((Act Z) ι z) , ((Act X) ι x)))
≣< (ufun F (z , x)) and (ufun F (z , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((eqi≈ F) (((ι↠ Z) {z}) , ((ι↠ X) {x}))) >
((ufun F (z , x)) by (≈ₐ Y) as (eq≈ₐ Y) ▴))))))
; feqi≈ = λ {x₁}{x₂} → λ x₁≈x₂ →  (eqi≈ F) ((Reflex (eq≈ₐ Z)) {z} , x₁≈x₂)
}
; eqi≈ = λ {z₁}{z₂} → λ z₁≈z₂ → λ x → (eqi≈ F) ( z₁≈z₂ , (Reflex (eq≈ₐ X)) {x})
; equiv = λ π → λ z → λ x → (((Act Y) π ((ufun F) (z , ((Act X) (invPerm π) x))))
≣< ((ufun F) (((Act Z) π z) , ((Act X) π ((Act X) (invPerm π) x)))) and ((ufun F) (((Act Z) π z) , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((equiv F) π (z , ((Act X) (invPerm π) x))) >
(((ufun F) (((Act Z) π z) , ((Act X) π ((Act X) (invPerm π) x))))
≣< (((ufun F) (((Act Z) π z) , ((Act X) ((invPerm π) ++ π) x)))) and ((ufun F) (((Act Z) π z) , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((eqi≈ F)(((Reflex (eq≈ₐ Z)) {(Act Z) π z}) , ((p₁p₂↠ X) π (invPerm π) {x})))  >
((((ufun F) (((Act Z) π z) , ((Act X) ((invPerm π) ++ π) x))))
≣< (((ufun F) (((Act Z) π z) , ((Act X) ι x)))) and ((ufun F) (((Act Z) π z) , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((eqi≈ F)(((Reflex (eq≈ₐ Z)) {(Act Z) π z}) , ((res X) (p⁻¹p≡ι π) (≈≡ (eq≈ₐ X) {x}{x} refl))))  >
((((ufun F) (((Act Z) π z) , ((Act X) ι x))))
≣< (((ufun F) (((Act Z) π z) ,  x))) and ((ufun F) (((Act Z) π z) , x)) by (≈ₐ Y) as (eq≈ₐ Y) on
((eqi≈ F)(((Reflex (eq≈ₐ Z)) {(Act Z) π z}) , ((ι↠ X) {x})))  >
(((ufun F) (((Act Z) π z) , x)) by (≈ₐ Y) as (eq≈ₐ Y) ▴)))))
}

-------------------------------------------------------------------------------------------------------------------------------------------------
--cartesian closed category
-------------------------------------------------------------------------------------------------------------------------------------------------

ExpN : (X Y : Nominal) → Exp{CarNom} X Y
ExpN X Y = record { Yˣ = NomExp X Y
; app = appN X Y
; curr = λ Z → λ F → currN X Y Z F
; comm = λ Z → λ F → λ zx → (Reflex (eq≈ₐ Y)) {(ufun F) ((proj₁ zx) , (proj₂ zx))}
; univ = λ Z → λ F → λ H → λ FC → λ z → λ x → (Symm (eq≈ₐ Y)) (FC (z , x))
}

NomCCC : CCC
NomCCC = record { CarC = CarNom
; exp = λ X Y → ExpN X Y
}

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

----------------------------------------------------------------------------------------------------------------------------------------------------
--EQUIVARIANT SUBSETS
---------------------------------------------------------------------------------------------------------------------------------------------------

EqCon : (N : Nominal) → (Con : (Aₛ N) → Set) → Set
EqCon N Con = ∀ (π : Perm) → (n : Aₛ N) → Con n → Con ((Act N) π n)

record SubEq (N : Nominal) (Con : Aₛ N → Set) (Eq : EqCon N Con) : Set where
constructor EQ
field
n∈N : Aₛ N
satisfy : Con n∈N

open SubEq public

-------------------------------------------------------------------------------------------------------------------------------------------------------
--equivariant subsets are nominal sets
-------------------------------------------------------------------------------------------------------------------------------------------------------

NomSubEq : (N : Nominal) → (Con : Aₛ N → Set) → (Eq : EqCon N Con) → Nominal
NomSubEq N Con Eq = record { Aₛ = SubEq N Con Eq
;  ≈ₐ = λ n₁ n₂ → (≈ₐ N) (n∈N n₁) (n∈N n₂)
;  eq≈ₐ = record { Reflex = λ {n} → (Reflex (eq≈ₐ N)) {n∈N n}
; Symm = λ n₁≈n₂ → (Symm (eq≈ₐ N)) n₁≈n₂
; Trans = λ n₁≈n₂ n₂≈n₃ → (Trans (eq≈ₐ N)) n₁≈n₂ n₂≈n₃
}
;  Act = λ π → λ n → EQ ((Act N) π (n∈N n)) (Eq π (n∈N n) (satisfy n))
;  res = λ π₁≈π₂ n₁≈n₂ → (res N) π₁≈π₂ n₁≈n₂
;  p₁p₂↠ = λ p₁ p₂ {n} → (p₁p₂↠ N) p₁ p₂ {n∈N n}
;  ι↠ = λ {n} → (ι↠ N) {n∈N n}
;  some_supp = λ n → (some_supp N) (n∈N n)
;  suppAx = λ n b c b∉n c∉n → (suppAx N) (n∈N n) b c b∉n c∉n
}

-----------------------------------------------------------------------------------------------------------------------------------------------------
--PULLBACKS IN NOM
-----------------------------------------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------------------------------
--object
-----------------------------------------------------------------------------------------------------------------------------------------------

NomPullback : (X Y Z : Nominal) → (Equivar X Z) → (Equivar Y Z) → Nominal
NomPullback X Y Z F G = NomSubEq (Prod X Y) (λ xy → (≈ₐ Z) ((ufun F) (proj₁ xy)) ((ufun G) (proj₂ xy))) (λ π → λ xy → λ fx≈gy → let πx = (Act X) π (proj₁ xy) in let πy = (Act Y) π (proj₂ xy) in
let fπx≈gπy = ((ufun F) πx) ≣< ((Act Z) π ((ufun F) (proj₁ xy))) and ((ufun G) πy) by (≈ₐ Z) as (eq≈ₐ Z) on ((Symm (eq≈ₐ Z)) ((equiv F) π (proj₁ xy))) >
(((Act Z) π ((ufun F) (proj₁ xy))) ≣< ((Act Z) π ((ufun G) (proj₂ xy))) and ((ufun G) πy) by (≈ₐ Z) as (eq≈ₐ Z) on ((res Z) (λ {w} → P≡≈ π {w}) fx≈gy) >
(((Act Z) π ((ufun G) (proj₂ xy))) ≣< ((ufun G) πy) and ((ufun G) πy) by (≈ₐ Z) as (eq≈ₐ Z) on ((equiv G) π (proj₂ xy)) >
(((ufun G) πy) by (≈ₐ Z) as (eq≈ₐ Z) ▴))) in fπx≈gπy)

--------------------------------------------------------------------------------------------------------------------------------------------
--projection morphisms
--------------------------------------------------------------------------------------------------------------------------------------------

NomPull1 : (X Y Z : Nominal) → (F : Equivar X Z) → (G : Equivar Y Z) → Equivar (NomPullback X Y Z F G) X
NomPull1 X Y Z F G = record { ufun = λ xyₛ → proj₁ (n∈N xyₛ)
;  eqi≈ = λ xy≈xy → proj₁ xy≈xy
;  equiv = λ π xyₛ → (Reflex (eq≈ₐ X)) {(Act X) π (proj₁ (n∈N xyₛ))}
}

NomPull2 : (X Y Z : Nominal) → (F : Equivar X Z) → (G : Equivar Y Z) → Equivar (NomPullback X Y Z F G) Y
NomPull2 X Y Z F G = record { ufun = λ xyₛ → proj₂ (n∈N xyₛ)
;  eqi≈ = λ xy≈xy → proj₂ xy≈xy
;  equiv = λ π xyₛ → (Reflex (eq≈ₐ Y)) {(Act Y) π (proj₂ (n∈N xyₛ))}
}

------------------------------------------------------------------------------------------------------------------------
--pullbacks
------------------------------------------------------------------------------------------------------------------------

NomPull : (X Y Z : Nominal) → (F : Equivar X Z) → (G : Equivar Y Z) → Pullbacks NomCat X Y Z F G
NomPull X Y Z F G = record { X⊗Y = NomPullback X Y Z F G
;  X⊗Y→X = NomPull1 X Y Z F G
;  X⊗Y→Y = NomPull2 X Y Z F G
;  f∘p₁≡g∘p₂ = λ xyₛ → satisfy xyₛ
;  W→X⊗Y = λ W F' G' FF'≈GG' → record { ufun = λ w → EQ (((ufun F') w) , ((ufun G') w)) (FF'≈GG' w)
;  eqi≈ = λ w₁≈w₂ → (((eqi≈ F') w₁≈w₂) , ((eqi≈ G') w₁≈w₂))
;  equiv = λ π w → (((equiv F') π w) , ((equiv G') π w))
}
;  WXY₁ = λ W F' G' FF'≈GG' → λ w → (Reflex (eq≈ₐ X)) {(ufun F') w}
;  WXY₂ = λ W F' G' FF'≈GG' → λ w → (Reflex (eq≈ₐ Y)) {(ufun G') w}
;  W↠X⊗Y = λ W F' G' FF'≈GG' H P₁H≈F' P₂H≈G' → λ w → (((Symm (eq≈ₐ X))(P₁H≈F' w)) , ((Symm (eq≈ₐ Y))(P₂H≈G' w)))
}

PullNom : CatPull NomCat
PullNom = record { Pulls = λ X Y Z F G → NomPull X Y Z F G }

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

```