3 ms·
First, here is a note about the notation that I will use here: Let `1` denote the unit type, the type with one inhabitant. Let `()` denote the inhabitant of the
by TheAsprngHacker 7y ago
First, here is a note about the notation that I will use here: Let `1` denote the unit type, the type with one inhabitant. Let `()` denote the inhabitant of the unit type. Let `a + b` or `Either a b` denote the sum of types `a` and `b`. Let `Left` and `Right` be the constructors of the sum type.
Before defining the integers, one must define the natural numbers. Natural numbers are defined as an inductive type, which is a little different from an ordinary sum type:
data Nat = Z | Suc Nat
Here is another way of defining them. Start by removing the self-reference:
data NatF a = Z | Suc a
Notice that NatF is the same thing as the Maybe/Option type, AKA 1+a, AKA the sum of the unit type and a.
Given a "fix" type:
data Fix f = MkFix (f (Fix f))
the definition of the natural numbers would be:
type Nat = Fix NatF
An "F-algebra" is a way of defining some algebraic structure or data type as a map from a "sum of products" to the type. More precisely, an F-algebra consists of an "object" (type) A and a map F(A) -> A. For the natural numbers, the F is NatF and the map would be a function mkNat : NatF Nat -> Nat, AKA mkNat : (Maybe Nat) -> Nat or mkNat : (1 + Nat) -> Nat.
Related links:
- https://ncatlab.org/nlab/show/inductive+type https://ncatlab.org/nlab/show/inductive+type
- https://ncatlab.org/nlab/show/natural+numbers+object https://ncatlab.org/nlab/show/natural+numbers+object
- https://ncatlab.org/nlab/show/initial+algebra+of+an+endofunctor https://ncatlab.org/nlab/show/initial+algebra+of+an+endofunc...
- https://en.wikipedia.org/wiki/F-algebra https://en.wikipedia.org/wiki/F-algebra
---
One way of defining the integers is as the product of the natural numbers with themselves, or Nat * Nat, equipped with an equivalence relation ~ where
(a, b) ~ (c, d) := a + d = b + c
(a, b) can be understood as a - b. Of course, a - b = c - d <-> a + d = b + c.
Another way of defining the integers is as:
data Int = Neg Nat | Zero | Pos Nat
where 0 = Zero, -1 = Neg Z, and +1 = Pos Z.
---
Booleans can be defined as 1 + 1. Left () = True and Right () = False, or vice versa.
- roenxi 7y agoI'm guessing at least a majority of the readers are like me and don't know Haskell, so on behalf of the confused: data Nat = Z | Suc Nat ^ What does this crazy construction mean syntactically? It looks like it is trying to do something like (from your link) Coq's Inductive nat : Type := | zero : nat | succ : nat -> nat. But obviously defining natural numbers in terms of Z/the integers doesn't work because I could then call -1 a natural number.
- jolmg 7y agoYou can't have negative numbers with that definition. Here are numbers and the way you would write them with that definition: 0 == Z 1 == Suc Z 2 == Suc (Suc Z) 3 == Suc (Suc (Suc Z)) You can define some arithmetic operators for it: data Nat = Z | Suc Nat deriving (Show, Eq) instance Num Nat where (Suc x) + y = Suc (x + y) Z + y = y (Suc x) - (Suc y) = x - y x - Z = x Z - (Suc _) = undefined Z * y = Z (Suc x) * y = (x * y) + y negate = undefined abs x = x signum (Suc _) = Suc Z signum Z = Z fromInteger 0 = Z fromInteger x | x < 0 = undefined | otherwise = Suc (fromInteger (x - 1)) The definition `fromInteger` is used by GHC to implicitly convert decimal numbers in the code to our Nat. We can use it like this: ghci> 0 == Z True ghci> 1 == Suc Z True ghci> 2 == Suc (Suc Z) True ghci> 3 :: Nat Suc (Suc (Suc Z)) ghci> 3 + 2 :: Nat Suc (Suc (Suc (Suc (Suc Z)))) ghci> 3 - 2 :: Nat Suc Z ghci> 3 * 2 :: Nat Suc (Suc (Suc (Suc (Suc (Suc Z))))) ghci> 3 - 4 :: Nat *** Exception: Prelude.undefined CallStack (from HasCallStack): error, called at libraries/base/GHC/Err.hs:78:14 in base:GHC.Err undefined, called at <interactive>:70:15 in interactive:Ghci8
- TheAsprngHacker 7y agoIn my code, the Z doesn't mean integer; it stands for zero. Nat is an inductive type, and Z is the base case. Z has type Nat.