-- Copyright 2016 Julian Hall. See LICENSE file at top level for details.
{-# LANGUAGE DataKinds,MultiParamTypeClasses,ConstraintKinds #-}
{-# LANGUAGE FunctionalDependencies,KindSignatures,TypeFamilies #-}
{-# LANGUAGE FlexibleInstances,PolyKinds,GADTs,UndecidableInstances #-}
module Data.Type.HasClass where
import GHC.Exts(Constraint)
import Data.Proxy
-- | Stores a constraint context. When pattern matched upon, the compiler
-- knows the constraint is true.
data TDict (c :: k -> Constraint) (t :: k) where
TDict :: c t => TDict c t
-- | Identifies whether or not a type has an instance of a type class,
-- and provides a standard means for capturing a context that allows them
-- to be used.
-- Unfortunately, because instances cannot be selected on the basis of
-- whether a context matches, instances of this class need to be listed manually
-- whenever we need to modify behaviour depending on whether an instance
-- of a class is available or not. If a class @c@ has an instance for type @t@
-- there should be an @instance HasClass c t True where classDict _ _ _ = TDict@.
-- For cases where additional context is required, see examples in the
-- @Data.Type.HasClassPreludeInstances@ module.
class HasClass (c :: k -> Constraint) (t :: k) (b :: Bool) | c t -> b where
classDict :: Proxy c -> Proxy t -> Proxy b -> TDict c t
-- | Default instance for types and classes that do not have an available
-- instance.
instance {-# OVERLAPPABLE #-} False ~ b => HasClass c t b where
classDict _ _ _ = undefined
-- | Combine type level 'Bool's. @And a b c@ has an instance @And a b True@
-- if and only if both @a@ and @b@ are 'True', and @And a b False@ otherwise.
class And (a :: Bool) (b :: Bool) (c :: Bool) | a b -> c
instance And True b b
instance And False b False