isobmff-0.14.0.0: src/Data/Kind/Extra.hs
{-# LANGUAGE UndecidableInstances #-}
-- / Utilities to provide better error messages
--
-- When dealing with type level programming in Haskell, especially when involving
-- undecidable instances, one is often confronted with irritating compiler
-- behaviour. This module shall mitigate the problems.
--
-- A group of types that all 'From' into the same type. This
-- is an /open/ and /extensible/ alternative to defining an algebraic data type
-- and using the promoted constructors. 'A' goes hand-in-hand with 'Extends' for
-- better readability.
--
-- For example:
--
-- @
-- data PrettyPrinter c where
-- RenderText :: Symbol -> PrettyPrinter Symbol
-- WithColor :: Color -> PrettyPrinter c -> PrettyPrinter c
--
-- data Color = Black | White
--
-- data ColoredText :: Color -> Symbol -> 'Extends' (PrettyPrinter Symbol)
--
-- type instance 'From' (ColoredText c txt) = 'WithColor c ('RenderText txt)
-- @
module Data.Kind.Extra
( type Extends
, type Konst
, (:~:)
, type From
, type Apply
, Labelled
, Named
, Name
, type (:#)
, Anonymous
, type ($)
, type (:>>=:)
, type (:>>>:)
, type (:^>>>:)
, type (:>>>^:)
, type Extract
, type Optional
, type FoldMap
, type Fun1
, type Fun2
, type Fun3
, type Fun4
) where
import Data.Kind (type Type)
import Data.Type.Equality ((:~:))
import GHC.TypeLits (Symbol)
-- | Indicates that a type constructs another.
type Extends a = (a -> Type :: Type)
-- | An open type family to turn /symbolic/ type representations created with
-- 'A' or 'Extends' into the actual types.
type family From (t :: a -> Type) :: a
-- | A @Konst a@, @'Extends' a@.
type Konst (a :: k) = ((:~:) a :: Extends k)
type instance From ((:~:) a) = a
-- | Phantom type for things that have a name
data Named s
-- | Assign a name to something that has no name
data Name :: Symbol -> Extends s -> Extends (Named s)
-- | Alias for 'Name'
type (name :: Symbol) :# (x :: Extends s) = Name name x
infixr 7 :#
-- | Remove tha name of a 'NamedStructure' to get to a 'Structure'
data Anonymous (x :: Extends (Named s)) :: Extends s
-- | Assign a symbol to any type in a group.
data Labelled (s :: Symbol) :: Extends a -> Extends a
type instance From (Labelled s t) = From t
-- | An open family of functions from @a@ to @b@
type family Apply (f :: Extends (a -> b)) (x :: a) :: b
-- | An alias for 'Apply'
type f $ x = Apply f x
-- | Compose functions
data (:>>>:) :: Extends (good -> better) -> Extends (better -> best) -> Extends (good -> best)
infixl 1 :>>>:
type instance Apply (f :>>>: g) x = g $ (f $ x)
-- | From Input & Compose
data (:^>>>:) :: Extends (good -> better) -> Extends (better -> best) -> Extends (Extends good -> best)
infixl 1 :^>>>:
type instance Apply (f :^>>>: g) x = g $ (f $ From x)
-- | Compose and 'Konst'
data (:>>>^:) :: Extends (good -> better) -> Extends (better -> best) -> Extends (good -> Extends best)
infixl 1 :>>>^:
type instance Apply (f :>>>^: g) x = Konst (g $ (f $ x))
-- | A function that applies 'From'
data Extract :: Extends (Extends x -> x)
type instance Apply Extract x = From x
-- | From and ApplyCompose functions
data (:>>=:) :: Extends a -> Extends (a -> Extends b) -> Extends b
infixl 1 :>>=:
type instance From (x :>>=: f) = From (f $ From x)
-- | Either use the value from @Just@ or return a fallback value(types(kinds))
data Optional :: Extends t -> Extends (s -> Extends t) -> Extends (Maybe s -> Extends t)
type instance Apply (Optional fallback f) ('Just s) = f $ s
type instance Apply (Optional fallback f) 'Nothing = fallback
-- | Map over the elements of a list and fold the result.
type family
FoldMap
(append :: Extends (b -> Extends (b -> b)))
(zero :: b)
(f :: Extends (a -> b))
(xs :: [(a :: Type)]) :: (b :: Type) where
FoldMap append zero f '[] = zero
FoldMap append zero f (x ': xs) = append $ (f $ x) $ FoldMap append zero f xs
-- TODONT safe coercions (with undecidable instances) could be done only with a
-- type-level equivilant of a type class dictionary, A good place for that
-- might be 'A'. For now I only had trouble with 'CoerceTo' because it is open
-- and the compiler often used up __all__ main memory when an instance was
-- missing.
-- | Like @TyCon1@ from Data.Singletons
data Fun1 :: (a -> Extends b)
-> Extends (a -> Extends b)
type instance Apply (Fun1 f) x = (f x)
data Fun2 :: (a -> b -> Extends c)
-> Extends (a -> Extends (b -> Extends c))
type instance Apply (Fun2 f) x = Fun1 (f x)
data Fun3 :: (a -> b -> c -> Extends d)
-> Extends (a -> Extends (b -> Extends (c -> Extends d)))
type instance Apply (Fun3 f) x = Fun2 (f x)
data Fun4 :: (a -> b -> c -> d -> Extends e)
-> Extends (a -> Extends (b -> Extends (c -> Extends (d -> Extends e))))
type instance Apply (Fun4 f) x = Fun3 (f x)