module Setoid where module Logic where infix 4 _/\_ -- infix 2 _\/_ data True : Set where tt : True data False : Set where data _/\_ (P Q : Set) : Set where andI : P -> Q -> P /\ Q -- Not allowed if we have proof irrelevance -- data _\/_ (P Q : Set) : Set where -- orIL : P -> P \/ Q -- orIR : Q -> P \/ Q module Setoid where data Setoid : Set1 where setoid : (A : Set) -> (_==_ : A -> A -> Set) -> (refl : (x : A) -> x == x) -> (sym : (x y : A) -> x == y -> y == x) -> (trans : (x y z : A) -> x == y -> y == z -> x == z) -> Setoid El : Setoid -> Set El (setoid A _ _ _ _) = A module Projections where eq : (A : Setoid) -> El A -> El A -> Set eq (setoid _ e _ _ _) = e refl : (A : Setoid) -> {x : El A} -> eq A x x refl (setoid _ _ r _ _) = r _ sym : (A : Setoid) -> {x y : El A} -> (h : eq A x y) -> eq A y x sym (setoid _ _ _ s _) = s _ _ trans : (A : Setoid) -> {x y z : El A} -> eq A x y -> eq A y z -> eq A x z trans (setoid _ _ _ _ t) = t _ _ _ module Equality (A : Setoid) where infix 6 _==_ _==_ : El A -> El A -> Set _==_ = Projections.eq A refl : {x : El A} -> x == x refl = Projections.refl A sym : {x y : El A} -> x == y -> y == x sym = Projections.sym A trans : {x y z : El A} -> x == y -> y == z -> x == z trans = Projections.trans A module EqChain (A : Setoid.Setoid) where infixl 5 _===_ _=-=_ infix 8 _since_ open Setoid private open module EqA = Equality A eqProof>_ : (x : El A) -> x == x eqProof> x = refl _=-=_ : (x : El A) -> {y : El A} -> x == y -> x == y x =-= eq = eq _===_ : {x y z : El A} -> x == y -> y == z -> x == z _===_ = trans _since_ : {x : El A} -> (y : El A) -> x == y -> x == y _ since eq = eq module Fun where open Logic open Setoid infixr 10 _=>_ _==>_ open Setoid.Projections using (eq) data _=>_ (A B : Setoid) : Set where lam : (f : El A -> El B) -> ({x y : El A} -> eq A x y -> eq B (f x) (f y) ) -> A => B app : {A B : Setoid} -> (A => B) -> El A -> El B app (lam f _) = f cong : {A B : Setoid} -> (f : A => B) -> {x y : El A} -> eq A x y -> eq B (app f x) (app f y) cong (lam _ resp) = resp data EqFun {A B : Setoid}(f g : A => B) : Set where eqFunI : ({x y : El A} -> eq A x y -> eq B (app f x) (app g y)) -> EqFun f g eqFunE : {A B : Setoid} -> {f g : A => B} -> {x y : El A} -> EqFun f g -> eq A x y -> eq B (app f x) (app g y) eqFunE (eqFunI h) = h _==>_ : Setoid -> Setoid -> Setoid A ==> B = setoid (A => B) EqFun r s t where module Proof where open module EqChainB = EqChain B module EqA = Equality A open module EqB = Equality B -- either abstract or --proof-irrelevance needed -- (we don't want to compare the proofs for equality) -- abstract r : (f : A => B) -> EqFun f f r f = eqFunI (\xy -> cong f xy) s : (f g : A => B) -> EqFun f g -> EqFun g f s f g fg = eqFunI (\{x}{y} xy -> app g x =-= app g y since cong g xy === app f x since sym (eqFunE fg xy) === app f y since cong f xy ) t : (f g h : A => B) -> EqFun f g -> EqFun g h -> EqFun f h t f g h fg gh = eqFunI (\{x}{y} xy -> app f x =-= app g y since eqFunE fg xy === app g x since cong g (EqA.sym xy) === app h y since eqFunE gh xy ) open Proof infixl 100 _$_ _$_ : {A B : Setoid} -> El (A ==> B) -> El A -> El B _$_ = app lam2 : {A B C : Setoid} -> (f : El A -> El B -> El C) -> ({x x' : El A} -> eq A x x' -> {y y' : El B} -> eq B y y' -> eq C (f x y) (f x' y') ) -> El (A ==> B ==> C) lam2 {A} f h = lam (\x -> lam (\y -> f x y) (\y -> h EqA.refl y)) (\x -> eqFunI (\y -> h x y)) where module EqA = Equality A lam3 : {A B C D : Setoid} -> (f : El A -> El B -> El C -> El D) -> ({x x' : El A} -> eq A x x' -> {y y' : El B} -> eq B y y' -> {z z' : El C} -> eq C z z' -> eq D (f x y z) (f x' y' z') ) -> El (A ==> B ==> C ==> D) lam3 {A} f h = lam (\x -> lam2 (\y z -> f x y z) (\y z -> h EqA.refl y z)) (\x -> eqFunI (\y -> eqFunI (\z -> h x y z))) where module EqA = Equality A eta : {A B : Setoid} -> (f : El (A ==> B)) -> eq (A ==> B) f (lam (\x -> f $ x) (\xy -> cong f xy)) eta f = eqFunI (\xy -> cong f xy) id : {A : Setoid} -> El (A ==> A) id = lam (\x -> x) (\x -> x) {- Now it looks okay. But it's incredibly slow! Proof irrelevance makes it go fast again... The problem is equality checking of (function type) setoids which without proof irrelevance checks equality of the proof that EqFun is an equivalence relation. It's not clear why using lam3 involves so many more equality checks than using lam. Making the proofs abstract makes the problem go away. -} compose : {A B C : Setoid} -> El ((B ==> C) ==> (A ==> B) ==> (A ==> C)) compose = lam3 (\f g x -> f $ (g $ x)) (\f g x -> eqFunE f (eqFunE g x)) _∘_ : {A B C : Setoid} -> El (B ==> C) -> El (A ==> B) -> El (A ==> C) f ∘ g = compose $ f $ g const : {A B : Setoid} -> El (A ==> B ==> A) const = lam2 (\x y -> x) (\x y -> x) module Nat where open Logic open Setoid open Fun infixl 10 _+_ data Nat : Set where zero : Nat suc : Nat -> Nat module NatSetoid where eqNat : Nat -> Nat -> Set eqNat zero zero = True eqNat zero (suc _) = False eqNat (suc _) zero = False eqNat (suc n) (suc m) = eqNat n m data EqNat (n m : Nat) : Set where eqnat : eqNat n m -> EqNat n m uneqnat : {n m : Nat} -> EqNat n m -> eqNat n m uneqnat (eqnat x) = x r : (x : Nat) -> eqNat x x r zero = tt r (suc n) = r n -- reflexivity of EqNat rf : (n : Nat) -> EqNat n n rf = \ x -> eqnat (r x) s : (x y : Nat) -> eqNat x y -> eqNat y x s zero zero _ = tt s (suc n) (suc m) h = s n m h s zero (suc _) () s (suc _) zero () -- symmetry of EqNat sy : (x y : Nat) -> EqNat x y -> EqNat y x sy = \x y h -> eqnat (s x y (uneqnat h)) t : (x y z : Nat) -> eqNat x y -> eqNat y z -> eqNat x z t zero zero z xy yz = yz t (suc x) (suc y) (suc z) xy yz = t x y z xy yz t zero (suc _) _ () _ t (suc _) zero _ () _ t (suc _) (suc _) zero _ () -- transitivity of EqNat tr : (x y z : Nat) -> EqNat x y -> EqNat y z -> EqNat x z tr = \x y z xy yz -> eqnat (t x y z (uneqnat xy) (uneqnat yz)) NAT : Setoid NAT = setoid Nat NatSetoid.EqNat NatSetoid.rf NatSetoid.sy NatSetoid.tr _+_ : Nat -> Nat -> Nat zero + m = m suc n + m = suc (n + m) plus : El (NAT ==> NAT ==> NAT) plus = lam2 (\n m -> n + m) eqPlus where module EqNat = Equality NAT open EqNat open NatSetoid eqPlus : {n n' : Nat} -> n == n' -> {m m' : Nat} -> m == m' -> n + m == n' + m' eqPlus {zero} {zero} _ mm = mm eqPlus {suc n} {suc n'} (eqnat nn) {m}{m'} (eqnat mm) = eqnat (uneqnat (eqPlus{n}{n'} (eqnat nn) {m}{m'} (eqnat mm) ) ) eqPlus {zero} {suc _} (eqnat ()) _ eqPlus {suc _} {zero} (eqnat ()) _ module List where open Logic open Setoid data List (A : Set) : Set where nil : List A _::_ : A -> List A -> List A LIST : Setoid -> Setoid LIST A = setoid (List (El A)) eqList r s t where module EqA = Equality A open EqA eqList : List (El A) -> List (El A) -> Set eqList nil nil = True eqList nil (_ :: _) = False eqList (_ :: _) nil = False eqList (x :: xs) (y :: ys) = x == y /\ eqList xs ys r : (x : List (El A)) -> eqList x x r nil = tt r (x :: xs) = andI refl (r xs) s : (x y : List (El A)) -> eqList x y -> eqList y x s nil nil h = h s (x :: xs) (y :: ys) (andI xy xys) = andI (sym xy) (s xs ys xys) s nil (_ :: _) () s (_ :: _) nil () t : (x y z : List (El A)) -> eqList x y -> eqList y z -> eqList x z t nil nil zs _ h = h t (x :: xs) (y :: ys) (z :: zs) (andI xy xys) (andI yz yzs) = andI (trans xy yz) (t xs ys zs xys yzs) t nil (_ :: _) _ () _ t (_ :: _) nil _ () _ t (_ :: _) (_ :: _) nil _ () open Fun