singletons-2.6: tests/ByHand2.hs
{-# LANGUAGE DataKinds, PolyKinds, TypeFamilies, GADTs, TypeOperators,
DefaultSignatures, ScopedTypeVariables, InstanceSigs,
MultiParamTypeClasses, FunctionalDependencies,
UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-missing-signatures #-}
module ByHand2 where
import Prelude hiding ( Eq(..), Ord(..), Bool(..), Ordering(..), not )
import Data.Kind (Type)
import Data.Singletons (Sing)
data Nat = Zero | Succ Nat
data Bool = False | True
data Ordering = LT | EQ | GT
not :: Bool -> Bool
not False = True
not True = False
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
infix 4 ==, /=
x == y = not (x /= y)
x /= y = not (x == y)
instance Eq Nat where
Zero == Zero = True
Zero == Succ _ = False
Succ _ == Zero = False
Succ x == Succ y = x == y
data SBool :: Bool -> Type where
SFalse :: SBool 'False
STrue :: SBool 'True
type instance Sing = SBool
data SNat :: Nat -> Type where
SZero :: SNat 'Zero
SSucc :: SNat n -> SNat ('Succ n)
type instance Sing = SNat
type family Not (x :: Bool) :: Bool where
Not 'True = 'False
Not 'False = 'True
sNot :: Sing b -> Sing (Not b)
sNot STrue = SFalse
sNot SFalse = STrue
class PEq a where
type (==) (x :: a) (y :: a) :: Bool
type (/=) (x :: a) (y :: a) :: Bool
type x == y = Not (x /= y)
type x /= y = Not (x == y)
instance PEq Nat where
type 'Zero == 'Zero = 'True
type 'Succ x == 'Zero = 'False
type 'Zero == 'Succ x = 'False
type 'Succ x == 'Succ y = x == y
class SEq a where
(%==) :: Sing (x :: a) -> Sing (y :: a) -> Sing (x == y)
(%/=) :: Sing (x :: a) -> Sing (y :: a) -> Sing (x /= y)
default (%==) :: ((x == y) ~ (Not (x /= y))) => Sing (x :: a) -> Sing (y :: a) -> Sing (x == y)
x %== y = sNot (x %/= y)
default (%/=) :: ((x /= y) ~ (Not (x == y))) => Sing (x :: a) -> Sing (y :: a) -> Sing (x /= y)
x %/= y = sNot (x %== y)
instance SEq Nat where
(%==) :: forall (x :: Nat) (y :: Nat). Sing x -> Sing y -> Sing (x == y)
SZero %== SZero = STrue
SSucc _ %== SZero = SFalse
SZero %== SSucc _ = SFalse
SSucc x %== SSucc y = x %== y
instance Eq Ordering where
LT == LT = True
LT == EQ = False
LT == GT = False
EQ == LT = False
EQ == EQ = True
EQ == GT = False
GT == LT = False
GT == EQ = False
GT == GT = True
class Eq a => Ord a where
compare :: a -> a -> Ordering
(<) :: a -> a -> Bool
x < y = compare x y == LT
class PEq a => POrd a where
type Compare (x :: a) (y :: a) :: Ordering
type (<) (x :: a) (y :: a) :: Bool
type x < y = Compare x y == 'LT
instance Ord Nat where
compare Zero Zero = EQ
compare Zero (Succ _) = LT
compare (Succ _) Zero = GT
compare (Succ a) (Succ b) = compare a b
instance POrd Nat where
type Compare 'Zero 'Zero = 'EQ
type Compare 'Zero ('Succ x) = 'LT
type Compare ('Succ x) 'Zero = 'GT
type Compare ('Succ x) ('Succ y) = Compare x y
data SOrdering :: Ordering -> Type where
SLT :: SOrdering 'LT
SEQ :: SOrdering 'EQ
SGT :: SOrdering 'GT
type instance Sing = SOrdering
instance PEq Ordering where
type 'LT == 'LT = 'True
type 'LT == 'EQ = 'False
type 'LT == 'GT = 'False
type 'EQ == 'LT = 'False
type 'EQ == 'EQ = 'True
type 'EQ == 'GT = 'False
type 'GT == 'LT = 'False
type 'GT == 'EQ = 'False
type 'GT == 'GT = 'True
instance SEq Ordering where
SLT %== SLT = STrue
SLT %== SEQ = SFalse
SLT %== SGT = SFalse
SEQ %== SLT = SFalse
SEQ %== SEQ = STrue
SEQ %== SGT = SFalse
SGT %== SLT = SFalse
SGT %== SEQ = SFalse
SGT %== SGT = STrue
class SEq a => SOrd a where
sCompare :: Sing (x :: a) -> Sing (y :: a) -> Sing (Compare x y)
(%<) :: Sing (x :: a) -> Sing (y :: a) -> Sing (x < y)
default (%<) :: ((x < y) ~ (Compare x y == 'LT)) => Sing (x :: a) -> Sing (y :: a) -> Sing (x < y)
x %< y = sCompare x y %== SLT
instance SOrd Nat where
sCompare SZero SZero = SEQ
sCompare SZero (SSucc _) = SLT
sCompare (SSucc _) SZero = SGT
sCompare (SSucc x) (SSucc y) = sCompare x y
class Pointed a where
point :: a
class PPointed a where
type Point :: a
class SPointed a where
sPoint :: Sing (Point :: a)
instance Pointed Nat where
point = Zero
instance PPointed Nat where
type Point = 'Zero
instance SPointed Nat where
sPoint = SZero
--------------------------------
class FD a b | a -> b where
meth :: a -> a
l2r :: a -> b
instance FD Bool Nat where
meth = not
l2r False = Zero
l2r True = Succ Zero
t1 = meth True
t2 = l2r False
class PFD a b | a -> b where
type Meth (x :: a) :: a
type L2r (x :: a) :: b
instance PFD Bool Nat where
type Meth a = Not a
type L2r 'False = 'Zero
type L2r 'True = 'Succ 'Zero
type T1 = Meth 'True
type T2 = L2r 'False
class SFD a b | a -> b where
sMeth :: forall (x :: a). Sing x -> Sing (Meth x :: a)
sL2r :: forall (x :: a). Sing x -> Sing (L2r x :: b)
instance SFD Bool Nat where
sMeth x = sNot x
sL2r SFalse = SZero
sL2r STrue = SSucc SZero
sT1 = sMeth STrue
sT2 :: Sing (T2 :: Nat)
sT2 = sL2r SFalse