{- | ==A small singleton core module A trimmed down core version of the singletons library made for my use case or more specifically Hreq but still general enough for similar use cases. ===Motivation The singleton library has pretty long compile times which can be hard to justify when you are using only a small portion of it. It is also not backward compatible with previous GHC releases. So if you want to support earlier GHC releases in a library that depends on singletons, you are pretty much left to the mercy of CPP hacks and careful Cabal dependency configurations. ===Attribution Some of the code in this module was directly borrowed from the Singletons library -} {-# LANGUAGE TypeInType #-} module Data.Singletons where import Data.Kind import GHC.TypeLits import Data.Typeable -- * Sing Type family type family Sing :: k -> Type class SingI a where sing :: Sing a -- TODO: Maybe add a SingKind class and SingKind instances -- * Type-lits ------------------- data SNat (n :: Nat) = KnownNat n => SNat type instance Sing = SNat instance KnownNat a => SingI (a :: Nat) where sing = SNat data SSymbol (n :: Symbol) = KnownSymbol n => SSym type instance Sing = SSymbol instance KnownSymbol a => SingI (a :: Symbol) where sing = SSym -- | Given a singleton for @Nat@, call something requiring a -- @KnownNat@ instance. withKnownNat :: Sing n -> (KnownNat n => r) -> r withKnownNat SNat f = f -- | Given a singleton for @Symbol@, call something requiring -- a @KnownSymbol@ instance. withKnownSymbol :: Sing n -> (KnownSymbol n => r) -> r withKnownSymbol SSym f = f -- * Lists ---------------------- data SList :: [k] -> Type where SNil :: SList '[] SCons :: forall k (h :: k) (t :: [k]). Sing h -> SList t -> SList (h ': t) type instance Sing = SList instance SingI ('[] :: [k]) where sing = SNil instance (SingI x, SingI xs) => SingI ( (x ': xs) :: [k]) where sing = SCons sing sing -- * Tuples ------------------- data STuple2 (a :: (k1, k2)) where STuple2 :: Sing x -> Sing y -> STuple2 '(x, y) instance (SingI x, SingI y) => SingI ( '(x, y) :: (k1, k2)) where sing = STuple2 sing sing type instance Sing = STuple2 -- * TypeRep ---------------------------------- data STypeRep :: Type -> Type where STypeRep :: forall (t :: Type). Typeable t => STypeRep t type instance Sing = STypeRep instance Typeable a => SingI (a :: Type) where sing = STypeRep