\import Data.Or \func Rel (A : \Type) : \Type => A -> A -> \Type \record StraightJoin {A : \Type} (a b : A) (rel : Rel A) | common-reduct : A | a~>cr : rel a common-reduct | b~>cr : rel b common-reduct \data Closure {A : \Type} (R : A -> A -> \Type) (a b : A) | c-trivial (a = b) | c-basic (a `R` b) | c-connect (c : A) (a `R` c) (Closure R c b) \where { \func compose {A : \Type} {R : Rel A} {a b c : A} (a~>b : Closure R a b) (b~>c : Closure R b c) : Closure R a c \elim a~>b, b~>c | c-basic r, rx => c-connect b r rx | c-connect c1 r a~>b, rx => c-connect c1 r (compose a~>b rx) | c-trivial idp, b~>c => b~>c \func lift {A B : \Type} {rel : Rel A} {rel' : Rel B} (map : A -> B) (rel-map : \Pi {a b : A} (rel a b) -> rel' (map a) (map b)) (x y : A) (closure : Closure rel x y) : Closure rel' (map x) (map y) \elim closure | c-basic r => c-basic (rel-map r) | c-connect c r closure => c-connect (map c) (rel-map r) (lift map rel-map c y closure) | c-trivial idp => c-trivial idp \func flatten {A : \Type} {rel : Rel A} {x y : A} (closure : Closure (Closure rel) x y) : Closure rel x y \elim closure | c-basic r => r | c-connect c r closure => compose r (flatten closure) | c-trivial idp => c-trivial idp \func extract {A : \Type} {rel : Rel A} {x y : A} (closure : Closure rel x y) : Or (x = y) (\Sigma (z : A) (rel x z)) \elim closure | c-trivial p => inl p | c-basic r => inr (y, r) | c-connect c r closure => inr (c, r) }