2 {-# LANGUAGE BangPatterns #-}
4 {-# LANGUAGE ExistentialQuantification #-}
5 -- For `Exists` instances
6 {-# LANGUAGE QuantifiedConstraints #-}
8 {-# LANGUAGE RankNTypes #-}
10 -- For `UnNamed` and `Exists` instances
11 {-# LANGUAGE UndecidableInstances #-}
13 -- {-# LANGUAGE AllowAmbiguousTypes #-}
14 -- For pattern `Named`
15 {-# LANGUAGE ViewPatterns #-}
58 import Control.Applicative (Applicative (..))
59 import Control.Monad (Monad (..))
60 import Data.Eq (Eq (..))
61 import Data.Function ((.))
62 import Data.Functor (Functor (..))
63 import Data.Ord (Ord (..))
64 import Data.Tuple (fst, snd)
65 import Text.Show (Show (..), showParen, showString)
66 import Type.Reflection (Typeable, typeRep)
68 -- | A value of type @(a `:::` name)@ has the same runtime
69 -- representation as a value of type @a@, with a nominal "name" attached.
71 -- The newtype constructor of `(:::)` is not exported
72 -- as it would break the "smart constructor" confidence.
73 newtype (:::) name a = NameAxiom a
76 instance Show a => Show (name ::: a) where
77 showsPrec p (NameAxiom a) = showsPrec p a
79 type role (:::) nominal representational
82 -- | A safe pattern matcher to unwrap a name attached with `(:::)`.
83 pattern Named :: UnName a => UnNamed a -> a
84 pattern Named x <- (unName -> x)
86 {-# COMPLETE Named #-}
88 -- | Attach a name to a value of type @(a)@.
89 -- This name must be inhabited,
90 -- it means that if it's a data or newtype constructor,
91 -- attaching such a name can be restricted to a module's boundary
92 -- by not exporting that constructor out of that module.
93 (...) :: name -> a -> name ::: a
100 unitName :: a -> () ::: a
102 {-# INLINE unitName #-}
104 -- | Unwrap `(:::)` at the type-level.
106 -- This is not recursive like `coerce` would.
107 type family UnNamed a where
108 UnNamed (n ::: a) = a
109 UnNamed (SuchThat a p) = UnNamed a
110 UnNamed (That a pred x) = UnNamed (() ::: a `SuchThat` pred ())
113 -- | Unwrap `(:::)` at the value-level.
115 -- Note: this is not recursive like `Data.Coerce.coerce`.
117 unName :: a -> UnNamed a
119 instance {-# OVERLAPS #-} UnName (n ::: a) where
120 unName (NameAxiom a) = a
121 {-# INLINE unName #-}
122 instance {-# OVERLAPS #-} UnName a => UnName (SuchThat a p) where
123 unName (SuchThat a) = unName a
124 {-# INLINE unName #-}
125 instance {-# OVERLAPS #-} UnName a => UnName (That a pred x) where
126 unName (That a) = unName a
127 {-# INLINE unName #-}
128 instance UnNamed a ~ a => UnName a where
130 {-# INLINE unName #-}
132 -- | Introduce a name for the argument,
133 -- and pass the named argument into the given function.
134 letName :: a -> (forall x. x ::: a -> res) -> res
135 letName x k = k (NameAxiom x)
136 {-# INLINE letName #-}
140 -- | Introduce names for two arguments,
141 -- and pass the named arguments into the given function.
142 letName2 :: a -> b -> (forall x y. x ::: a -> y ::: b -> res) -> res
143 letName2 x y k = k (NameAxiom x) (NameAxiom y)
144 {-# INLINE letName2 #-}
148 -- | Introduce names for three arguments,
149 -- and pass the named arguments into the given function.
150 letName3 :: a -> b -> c -> (forall x y z. x ::: a -> y ::: b -> z ::: c -> res) -> res
151 letName3 x y z k = k (NameAxiom x) (NameAxiom y) (NameAxiom z)
152 {-# INLINE letName3 #-}
156 -- | Introduce names for four arguments,
157 -- and pass the named arguments into the given function.
158 letName4 :: a -> b -> c -> d -> (forall x y z w. x ::: a -> y ::: b -> z ::: c -> w ::: d -> res) -> res
159 letName4 x y z w k = k (NameAxiom x) (NameAxiom y) (NameAxiom z) (NameAxiom w)
160 {-# INLINE letName4 #-}
164 -- \| Injects a `Symbol` into a `Type` for `letSymbol`.
165 -- data Name (s :: Symbol)
167 -- \| Like `letName` but with a `Symbol` hint and a `Typeable` constraint
168 -- enabling to `show` @(name)@.
169 -- letSymbol :: forall (s :: Symbol) a res. KnownSymbol s => a -> (forall name. Typeable name => name ::: a -> res) -> res
171 -- let n = hashUnique (unsafePerformIO newUnique)
172 -- in case someSymbolVal (symbolVal (Proxy @s) <> show n) of
173 -- SomeSymbol (Proxy :: Proxy n) ->
174 -- k @(Name n) (NameAxiom a)
176 -- | Infix alias to `letName`.
177 namedAs :: a -> (forall name. name ::: a -> res) -> res
178 namedAs a k = k (NameAxiom a)
179 {-# INLINE namedAs #-}
183 -- | Introduce a name for the argument,
184 -- and pass the named argument into the given function.
185 liftName :: (forall x. x ::: a -> res) -> a -> res
186 liftName k x = k (NameAxiom x)
187 {-# INLINE liftName #-}
191 -- | Introduce names for two arguments,
192 -- and pass the named arguments into the given function.
193 liftName2 :: (forall x y. x ::: a -> y ::: b -> res) -> a -> b -> res
194 liftName2 k x y = k (NameAxiom x) (NameAxiom y)
195 {-# INLINE liftName2 #-}
199 -- | Introduce names for three arguments,
200 -- and pass the named arguments into the given function.
201 liftName3 :: (forall x y z. x ::: a -> y ::: b -> z ::: c -> res) -> a -> b -> c -> res
202 liftName3 k x y z = k (NameAxiom x) (NameAxiom y) (NameAxiom z)
203 {-# INLINE liftName3 #-}
207 -- | Introduce names for four arguments,
208 -- and pass the named arguments into the given function.
209 liftName4 :: (forall x y z w. x ::: a -> y ::: b -> z ::: c -> w ::: d -> res) -> a -> b -> c -> d -> res
210 liftName4 k x y z w = k (NameAxiom x) (NameAxiom y) (NameAxiom z) (NameAxiom w)
211 {-# INLINE liftName4 #-}
215 -- | Operator version of `letName`.
216 (=:) :: a -> (forall name. name ::: a -> res) -> res
217 (=:) a k = k (NameAxiom a)
222 -- | Here, a proposition in the logic side,
223 -- is a type in the programming side.
224 -- And a proven proposition is an inhabited type.
226 -- * `Logic.Name.RefHoTTBook`
227 -- * https://groups.seas.harvard.edu/courses/cs152/2016sp/lectures/lec16-curryhoward.pdf
228 -- * https://en.wikipedia.org/wiki/Type_inhabitation_problem
229 -- * https://homepages.inf.ed.ac.uk/wadler/papers/propositions-as-types/propositions-as-types.pdf
230 -- * https://ncatlab.org/nlab/show/propositions+as+types
231 data Proof proposition = ProofAxiom
233 instance Typeable p => Show (Proof p) where
237 ( showString "Proof "
238 . showsPrec prec (typeRep @p)
243 proven :: a -> Proof a
244 proven !_ = ProofAxiom
245 {-# INLINE proven #-}
247 type role Proof nominal
249 instance Functor Proof where
250 fmap _f !_ = ProofAxiom
252 instance Applicative Proof where
253 -- Observing an instance of 'a'
254 -- Therefore, an instance of 'a' exists.
256 (<*>) !_ !_ = ProofAxiom
258 instance Monad Proof where
259 -- There exist a proof that proves the existence of a proof of 'a'
260 -- Therefore, a proof of 'a' exists.
261 !_ >>= !_ = ProofAxiom
263 -- | The implication in the logic side,
264 -- is the function type of the programming side.
265 implies :: (Proof p -> Proof q) -> Proof (p -> q)
266 implies !_ = ProofAxiom
267 {-# INLINE implies #-}
270 unImplies :: Proof (p -> q) -> (Proof p -> Proof q)
272 {-# INLINE unImplies #-}
274 -- | Reify a `Proof` or `(:::)` to inspect it.
275 class Provable a where
277 prove :: a -> ProofOf a
279 -- nameProof :: ProofOf n a -> n ::: a
282 -- | CorrectnessWarning: the default definition declares an axiom.
283 -- This is the only way to declare an axiom out of this module
284 -- (except through `undefined` or `TemplateHaskell` if LANGUAGE Safe is not used).
286 -- Beware that `Axiom` instances can be hidden from the documentation
287 -- when not exporting a type involved in defining them,
288 -- however their do appear in:
291 -- ghci> :info! Axiom
295 {-# WARNING axiom "x-logic-axiom" #-}
300 type (<->) p q = ((p -> q), (q -> p))
303 (-->) :: (<->) p q -> p -> q
308 (<--) :: (<->) p q -> q -> p
313 type Commutative op x y = op x y <-> op y x
314 type Associative op x y z = op (op x y) z <-> op x (op y z)
316 -- | Existential quantification.
317 data Exists p = forall x. Exists (p x)
319 instance (forall x. Show (p x)) => Show (Exists p) where
320 showsPrec p (Exists px) = showsPrec p px
322 -- | Class alias working around the impossibility
323 -- to refer to the type family `UnNamed`
324 -- in the quantified constraint of the @(`Eq` (`Exists` p))@ instance.
326 -- IssueRef: https://gitlab.haskell.org/ghc/ghc/-/issues/14860#note_495352
327 class (Eq (UnNamed (p x)), UnName (p x), UnNamed (p x) ~ UnNamed (p y)) => EqUnNamed p x y
329 instance (Eq (UnNamed (p x)), UnName (p x), UnNamed (p x) ~ UnNamed (p y)) => EqUnNamed p x y
331 instance (forall x y. EqUnNamed p x y) => Eq (Exists p) where
332 (==) (Exists (Named px)) (Exists (Named py)) = (==) px py
334 newtype SuchThat a p = SuchThat a
336 type role SuchThat representational nominal
338 instance Show a => Show (SuchThat a p) where
339 showsPrec p (SuchThat a) = showsPrec p a
341 -- | Convenient alias to `SuchThat`.
346 (/) :: a -> Proof p -> a `SuchThat` p
347 (/) a ProofAxiom = SuchThat a
350 suchThatProof :: a `SuchThat` p -> Proof p
351 suchThatProof SuchThat{} = ProofAxiom
352 {-# INLINE suchThatProof #-}
354 newtype That a p x = That (x ::: a `SuchThat` p x)
356 type role That representational nominal nominal
357 instance Show a => Show (That a p x) where
358 showsPrec p (That a) = showsPrec p a
361 -- ^ Reference to [Homotopy Type Theory: Univalent Foundations of Mathematics](https://homotopytypetheory.org/book)
367 -- > "family": "Univalent Foundations Program",
371 -- > "id": "hottbook",
379 -- > "publisher": "https://homotopytypetheory.org/book",
380 -- > "publisher-place": "Institute for Advanced Study",
381 -- > "title": "Homotopy Type Theory: Univalent Foundations of Mathematics",
382 -- > "title-short": "Homotopy Type Theory",