\begin{code}
{-# OPTIONS --cubical --safe #-}

module Snippets.Classical where

open import Prelude

doubleNeg-elim : Type a → Type a
doubleNeg-elim A =
\end{code}
%<*doubleneg-elim>
\begin{code}
¬ ¬ A → A
\end{code}
%</doubleneg-elim>
%<*classical-def>
\begin{code}
Classical : Type a → Type a
Classical A = ¬ ¬ A
\end{code}
%</classical-def>
\begin{code}
pure : A → Classical A
pure x ¬x = ¬x x

_>>=_ : Classical A → (A → Classical B) → Classical B
¬¬x >>= f = λ ¬B → ¬¬x (λ x → f x ¬B)
\end{code}
\begin{code}
_<*>_ : Classical (A → B) → Classical A → Classical B
¬¬f <*> ¬¬x = λ ¬B → ¬¬x (λ x → ¬¬f (λ f → ¬B (f x)))

_>>_ : Classical A → Classical B → Classical B
_ >> x = x

\end{code}
%<*lem-proof>
\begin{code}
lem : Classical (A ⊎ (¬ A))
lem ¬lem = ¬lem (inr λ p → ¬lem (inl p))
\end{code}
%</lem-proof>
\begin{code}
open import Cardinality.Finite.Cardinal using (𝒞; ¬⟨𝒞⋂ℬᶜ⟩)
open import Cardinality.Finite.ManifestBishop.Inductive using (ℬ)

module _ {A : Type a} { B : Type b} where
\end{code}
%<*classical-impl>
\begin{code}
classical-impl : ¬ (A × ¬ B) → Classical (A → B)
classical-impl ¬A×¬B = do
A? ← lem {A = A}
B? ← lem {A = B}
case (A? , B?) of
λ { (inl  a   , inl   b   ) → pure (const b)
; (inl  a   , inr   ¬b  ) → ⊥-elim (¬A×¬B (a , ¬b))
; (inr  ¬a  , inl   b   ) → pure (const b)
; (inr  ¬a  , inr   ¬b  ) → pure (λ x → ⊥-elim (¬a x))
}
\end{code}
%</classical-impl>