summaryrefslogtreecommitdiff
path: root/src/Data/Setoid/Pair.idr
blob: 2cb93578309133b6d506438a918631dd8adc5a86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
||| Product of setoids
module Data.Setoid.Pair

import Data.Setoid.Definition
import Data.Setoid.Either

%default total

||| Binary relation conjunction
public export
record And {A,B : Type} (p : Rel A) (q : Rel B) (xy1, xy2 : (A, B)) where
  constructor MkAnd
  fst : p (fst xy1) (fst xy2)
  snd : q (snd xy1) (snd xy2)

||| Product of setoids
public export
Pair : (a,b : Setoid) -> Setoid
Pair a b = MkSetoid
  { U = (U a, U b)
  , equivalence = MkEquivalence
    { relation = a.equivalence.relation `And` b.equivalence.relation
    , reflexive = \xy => MkAnd
        (a.equivalence.reflexive $ fst xy)
        (b.equivalence.reflexive $ snd xy)
    , symmetric  = \xy1,xy2,prf => MkAnd
        (a.equivalence.symmetric (fst xy1) (fst xy2) prf.fst)
        (b.equivalence.symmetric (snd xy1) (snd xy2) prf.snd)
    , transitive = \xy1,xy2,xy3,prf1,prf2 => MkAnd
        (a.equivalence.transitive (fst xy1) (fst xy2) (fst xy3) prf1.fst prf2.fst)
        (b.equivalence.transitive (snd xy1) (snd xy2) (snd xy3) prf1.snd prf2.snd)
    }
  }

||| Left projection setoid homomorphism
public export
(.fst) : {0 a,b : Setoid} -> Pair a b ~> a
(.fst) = MkSetoidHomomorphism
  { H = Builtin.fst
  , homomorphic = \xy1,xy2,prf => prf.fst
  }

||| Right projection setoid homomorphism
public export
(.snd) : {0 a,b : Setoid} -> Pair a b ~> b
(.snd) = MkSetoidHomomorphism
  { H = Builtin.snd
  , homomorphic = \xy1,xy2,prf => prf.snd
  }

||| Setoid homomorphism constructor
public export
tuple : {0 a,b,c : Setoid} -> c ~> a -> c ~> b -> c ~> Pair a b
tuple f g = MkSetoidHomomorphism
  { H = \z => (f.H z, g.H z)
  , homomorphic = \z1,z2,prf => MkAnd
      (f.homomorphic z1 z2 prf)
      (g.homomorphic z1 z2 prf)
  }

||| Unique value of type unit
public export
unitVal : (x,y : Unit) -> x = y
unitVal () () = Refl

||| The unique setoid map into the terminal type
public export
unit : {a : Setoid} -> a ~> cast Unit
unit = MkSetoidHomomorphism
  { H = const ()
  , homomorphic = \_,_,_ => unitVal () ()
  }

||| The constant function as a setoid morphism
public export
const : {a,b : Setoid} -> (x : U b) -> a ~> b
const x = mate (Prelude.const x) . unit

||| Setoid homomorphism constructor
public export
bimap : {a,b,c,d : Setoid} -> c ~> a -> d ~> b -> Pair c d ~> Pair a b
bimap f g = tuple (f . (.fst)) (g . (.snd))

-- Distribution of products over sums, degenerate case:

||| Function underlying the bijection 2 x s <~> s + s
public export
distributeFunction : {s : Setoid} -> (Bool, U s) -> (U s `Either` U s)
distributeFunction (False, x) = Left  x
distributeFunction (True , x) = Right x

||| States: the function underlying the bijection 2 x s <~> s + s is a setoid homomorphism
public export
distributeHomomorphism : {s : Setoid} ->
  SetoidHomomorphism ((cast Bool) `Pair` s) (s `Either` s)
    (distributeFunction {s})
distributeHomomorphism (b1,x1) (b2,x2) prf =
  case prf.fst of
    Refl => case b2 of
      False => Left  prf.snd
      True  => Right prf.snd

||| Setoid homomorphism involved in the bijection 2 x s <~> s + s
public export
distribute : {s : Setoid} -> ((cast Bool) `Pair` s) ~> (s `Either` s)
distribute = MkSetoidHomomorphism
  { H = distributeFunction
  , homomorphic = distributeHomomorphism
  }

public export
pairIso : {a,b,c,d : Setoid} -> (a <~> c) -> (b <~> d) -> (Pair a b <~> Pair c d)
pairIso ac bd = MkIsomorphism (bimap ac.Fwd bd.Fwd) (bimap ac.Bwd bd.Bwd)
                  (IsIsomorphism (\(x,y) => MkAnd (ac.Iso.BwdFwdId x) (bd.Iso.BwdFwdId y))
                                 (\(x,y) => MkAnd (ac.Iso.FwdBwdId x) (bd.Iso.FwdBwdId y)))