3 {-# OPTIONS_GHC -Wno-deprecations #-}
4 {-# OPTIONS_GHC -Wno-orphans #-}
5 {-# OPTIONS_GHC -Wno-unused-top-binds #-}
7 module Logic.Theory.Bool (
26 type NotAsNonExistent,
31 type NonContradiction,
37 import Control.Applicative (Applicative (..), liftA3)
38 import Control.Monad (Monad (..))
39 import Data.Either (Either (..), either)
40 import Data.Function (id, (.))
41 import Data.Functor ((<$>))
42 import Data.Tuple (fst, snd)
43 import Data.Void (Void)
44 import Data.Void qualified as Void
54 -- | From a falsity, prove anything.
55 -- (aka. ex falso quodlibet).
62 -- The conjunction in the logic side,
63 -- is the product type in the programming side.
67 and :: Proof p -> Proof q -> Proof (p && q)
71 andL :: Proof (p && q) -> Proof p
74 andR :: Proof (p && q) -> Proof q
77 unAnd :: Proof (p && q) -> (Proof p, Proof q)
78 unAnd c = (andL c, andR c)
80 -- The disjunction in the logic side,
81 -- is the sum type in the programming side.
85 leftOr :: Proof p -> Proof (p || q)
88 rightOr :: Proof q -> Proof (p || q)
91 type UnOr p q r = (p -> r) -> (q -> r) -> (p || q) -> r
92 instance Lemma (UnOr p q r) where
98 unOr :: (Proof p -> Proof r) -> (Proof q -> Proof r) -> Proof (p || q) -> Proof r
99 unOr p2r q2r = (>>= either (p2r . pure) (q2r . pure))
101 unOrL :: (Proof p -> Proof r) -> Proof (p || q) -> (Proof q -> Proof r) -> Proof r
102 unOrL p2r poq q2r = unOr p2r q2r poq
104 unOrR :: (Proof q -> Proof r) -> Proof (p || q) -> (Proof p -> Proof r) -> Proof r
105 unOrR q2r poq p2r = unOr p2r q2r poq
107 -- | CorrectnessNote: the existence of a construction of @(`Not` p)@ is much stronger
108 -- than the non-existence of a construction of @(p)@.
109 newtype Not p = Not ()
111 -- | A construction of @(`Not` p)@, treated like @(p `->` `False`)@,
112 -- is an algorithm that, from a (hypothetical) construction of @(p)@
113 -- produces a non-existent object.
114 type NotAsNonExistent p = Not p <-> (p -> False)
116 instance Axiom (NotAsNonExistent p)
119 not :: (Proof p -> Proof False) -> Proof (Not p)
120 not f = liftA2 (<--) (axiom @(NotAsNonExistent _)) (implies f)
123 modusTollens :: Proof (p -> q) -> Proof (Not q) -> Proof (Not p)
124 modusTollens p2qP nqP = not (contradicts nqP . unImplies p2qP)
125 {-# INLINE modusTollens #-}
127 -- | Non contradiction
128 type NonContradiction p = Not (p && Not p)
130 instance Axiom (NonContradiction p)
132 contradicts :: Proof (Not p) -> Proof p -> Proof False
133 contradicts = liftA3 (-->) (axiom @(NotAsNonExistent _))
134 {-# INLINE contradicts #-}
137 -- > It has been known for a long time, however, that principles such as AC and LEM are fundamentally
138 -- > antithetical to computability, since they assert baldly that certain things exist without giving any
139 -- > way to compute them. Thus, avoiding them is necessary to maintain the character of type theory
140 -- > as a theory of computation.
142 -- Intuitionistic logic rejects excluded middle (and the many equivalent rules)
143 type ExcludedMiddle p = p || Not p
145 type Contradiction p = (Not p -> False) -> p
146 instance Axiom (ExcludedMiddle p) => Lemma (Contradiction p) where
147 lemma = (\em np2f -> runOr id (absurd . np2f) em) <$> axiom @(ExcludedMiddle p)