{-# OPTIONS --without-K --safe #-}

module Data.Sum where

open import Level
open import Function

infixr 3 _⊎_
data _⊎_ (A : Type a) (B : Type b) : Type (a ℓ⊔ b) where
  inl : A  A  B
  inr : B  A  B

either :  {} {C : A  B  Type }   ((a : A)  C (inl a))  ((b : B)  C (inr b))
         (x : A  B)  C x
either f _ (inl x) = f x
either _ g (inr y) = g y

either′ : (A  C)  (B  C)  (A  B)  C
either′ = either

_▿_ : (A  C)  (B  C)  A  B  C
(f  g) (inl  x) = f x
(f  g) (inr  x) = g x

map-⊎ :  {a₁ a₂ b₁ b₂} {A₁ : Type a₁} {A₂ : Type a₂} {B₁ : Type b₁} {B₂ : Type b₂} 
      (A₁  A₂) 
      (B₁  B₂) 
      (A₁  B₁) 
      (A₂  B₂)
map-⊎ f g = either (inl  f) (inr  g)

mapˡ : (A  B)  A  C  B  C
mapˡ f = map-⊎ f id

mapʳ : (A  B)  C  A  C  B
mapʳ = map-⊎ id

open import Path

inl-inj : Injective (inl {A = A} {B = B})
inl-inj {y = y} = cong (either′ id (const y))

inr-inj : Injective (inr {A = A} {B = B})
inr-inj {x = x} = cong (either′ (const x) id)

open import Data.Bool
open import Data.Bool.Properties

is-l : A  B  Bool
is-l = either′ (const true) (const false)

inr≢inl : {x : A} {y : B}  inr x  inl y
inr≢inl = false≢true  cong is-l

inl≢inr : {x : A} {y : B}  inl x  inr y
inl≢inr = true≢false  cong is-l

open import Decidable
open import Data.Sigma

Discrete-⊎ : Discrete A  Discrete B  Discrete (A  B)
Discrete-⊎ lhs _ (inl x) (inl y) = iff-dec (cong inl , inl-inj) (lhs x y)
Discrete-⊎ _ _ (inl x) (inr x₁) = no inl≢inr
Discrete-⊎ _ _ (inr x) (inl x₁) = no inr≢inl
Discrete-⊎ _ rhs (inr x) (inr y) = iff-dec (cong inr , inr-inj) (rhs x y)