ND
1 What do propositions actually mean in logic
2 Conjunction
\[\frac{\Gamma \vdash M : A \qquad \Gamma \vdash N : B }{ \Gamma \vdash <M,N> : A \land B}\]
\[\frac{\Gamma \vdash M : A \land B}{\Gamma \vdash fst\ M : A}\]
3 Implication
\[ \frac{\Gamma, u: A \vdash M:B}{\Gamma \vdash (\lambda u: A. M): A \rightarrow B}\]
\[\frac{\Gamma \vdash M: A \rightarrow B \qquad \Gamma \vdash N: A}{\Gamma \vdash M\ N : B}\]
\[\cfrac{[A]^u}{\cfrac{...}{\cfrac{B}{A \rightarrow B}}}\]
\[\cfrac{A \rightarrow B \qquad A}{B}\]
4 Disjunction
\[\cfrac{\Gamma \vdash M : A}{\Gamma \vdash inl\ M : A \lor B}\]
\[\cfrac{\Gamma \vdash M : A \lor B \qquad \Gamma,u:A \vdash p : C \qquad \Gamma,w:B \vdash q: C}{\Gamma \vdash case\ M\ of\ (inl\ u \Rightarrow p\ |\ inr\ w \Rightarrow q): C}\]
\[ \cfrac{A\lor B \qquad \cfrac{[A]^u}{\cfrac{...}{C}} \qquad \cfrac{[B]^w}{\cfrac{...}{C}} }{C}\]
{-# LANGUAGE Rank2Types #-}
import Data.Void
import Data.Bifunctor
import Data.Functor.Identity
type Not a = a -> Void
type Peirce = forall a b. ((a -> b) -> a) -> a
type LEM = forall a. Either (Not a) a
callCC_lem :: Peirce -> LEM
= callCC $ \cc -> Left (\a -> cc (Right a))
callCC_lem callCC
lem_callCC :: LEM -> Peirce
= either (\n -> \f -> f (absurd . n)) const lem
lem_callCC lem
-- Bonus exercise: prove Peirce’s law <=> double negation elimination
type DNE = forall a. Not (Not a) -> a
lem_dne :: LEM -> DNE
= either (\f -> \g -> absurd (g f)) const lem
lem_dne lem
dne_lem :: DNE -> LEM
= dne $ \n -> n (Right . dne $ \m -> n (Left m))
dne_lem dne
callCC_dne :: Peirce -> DNE
= \dn -> callCC $ \cc -> absurd (dn cc)
callCC_dne callCC
dne_callCC :: DNE -> Peirce
= dne $ \n -> n (f . dne $ \m -> m (absurd . n))
dne_callCC dne f
-- Self-inflicted exercise: prove dual Frobenius rule <=> everything else
data Voider a = Voider { unVoider :: Void }
type DualFrobenius = forall x p q. (x -> Either (p x) q) -> Either (x -> p x) q
lem_df :: LEM -> DualFrobenius
= bimap (\nq -> either id (absurd . nq) . f) id lem
lem_df lem f
df_lem :: DualFrobenius -> LEM
= first (\f -> unVoider . f) (df Right)
df_lem df
callCC_df :: Peirce -> DualFrobenius
= callCC $ \cc -> Left $ \x -> either id (cc . Right) (f x)
callCC_df callCC f
df_callCC :: DualFrobenius -> Peirce
= either (\g -> f (absurd . unVoider . g)) id (df Right)
df_callCC df f
dne_df :: DNE -> DualFrobenius
= dne $ \n -> n (Left $ \x -> dne $ \m -> either (m) (n . Right) (f x))
dne_df dne f
df_dne :: DualFrobenius -> DNE
= either (\f -> (absurd . dn) (unVoider . f)) id (df Right) df_dne df dn