/-
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura

Define squash type (aka propositional truncation) using quotients.
This definition is slightly better than defining the squash type ∥A∥ as (nonempty A).
If we define it using (nonempty A), then we can only lift functions A → B to ∥A∥ → B
when B is a proposition. With quotients, we can lift to any B type that is a subsingleton
(i.e., has at most one element).
-/
open quot

private definition eqv {A : Type} (a b : A) : Prop := true
local infix ~ := eqv

private lemma eqv_refl {A : Type} : ∀ a : A, a ~ a :=
λ a, trivial

private lemma eqv_symm {A : Type} : ∀ a b : A, a ~ b → b ~ a :=
λ a b h, trivial

private lemma eqv_trans {A : Type} : ∀ a b c : A, a ~ b → b ~ c → a ~ c :=
λ a b c h₁ h₂, trivial

definition squash_setoid (A : Type) : setoid A :=
setoid.mk (@eqv A) (mk_equivalence (@eqv A) (@eqv_refl A) (@eqv_symm A) (@eqv_trans A))

definition squash (A : Type) : Type :=
quot (squash_setoid A)

namespace squash
local attribute squash_setoid [instance]

notation `∥`:0 A `∥` := squash A

definition mk {A : Type} (a : A) : ∥A∥ :=
⟦a⟧

protected definition irrelevant {A : Type} : ∀ a b : ∥A∥, a = b :=
λ a b, quot.induction_on₂ a b (λ a b, quot.sound trivial)

definition lift {A B : Type} [h : subsingleton B] (f : A → B) : ∥A∥ → B :=
λ s, quot.lift_on s f (λ a₁ a₂ r, subsingleton.elim (f a₁) (f a₂))
end squash

open squash decidable

definition decidable_eq_squash [instance] (A : Type) : decidable_eq ∥A∥ :=
λ a b, inl (squash.irrelevant a b)

definition subsingleton_squash [instance] (A : Type) : subsingleton ∥A∥ :=
subsingleton.intro (@squash.irrelevant A)
