{-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} module Language.Symantic.Typing.Constraint where import Data.Maybe (fromMaybe) import Data.Proxy import Data.Type.Equality import Language.Symantic.Typing.Kind import Language.Symantic.Typing.Constant import Language.Symantic.Typing.Type -- * Type 'Con' -- | Captures the proof of a 'Constraint' -- (and its dictionary for a type class): -- pattern matching on the 'Con' constructor -- brings the 'Constraint' into scope. data Con c where Con :: c => Con c -- * Type family 'Consts_imported_by' -- | Return the /type constant/s that a given /type constant/ -- wants to be part of the final list of /type constants/. type family Consts_imported_by (c::k) :: [*] type instance Consts_imported_by [] = [ Proxy Applicative , Proxy Eq , Proxy Foldable , Proxy Functor , Proxy Monad , Proxy Monoid , Proxy Ord , Proxy Traversable ] type instance Consts_imported_by (->) = [ Proxy Applicative , Proxy Functor , Proxy Monad , Proxy Monoid ] type instance Consts_imported_by Applicative = '[] type instance Consts_imported_by Bool = [ Proxy Bounded , Proxy Enum , Proxy Eq , Proxy Ord ] type instance Consts_imported_by Bounded = '[] type instance Consts_imported_by Eq = '[] type instance Consts_imported_by Enum = '[] type instance Consts_imported_by Foldable = '[] type instance Consts_imported_by Functor = '[] type instance Consts_imported_by Int = [ Proxy Bounded , Proxy Enum , Proxy Eq , Proxy Integral , Proxy Num , Proxy Ord , Proxy Real ] type instance Consts_imported_by Integer = [ Proxy Enum , Proxy Eq , Proxy Integral , Proxy Num , Proxy Ord , Proxy Real ] type instance Consts_imported_by Integral = [ Proxy Enum , Proxy Real ] type instance Consts_imported_by IO = [ Proxy Applicative , Proxy Functor , Proxy Monad ] type instance Consts_imported_by Maybe = [ Proxy Applicative , Proxy Eq , Proxy Foldable , Proxy Functor , Proxy Monad , Proxy Monoid , Proxy Traversable ] type instance Consts_imported_by Monad = '[] type instance Consts_imported_by Monoid = '[] type instance Consts_imported_by Num = '[] type instance Consts_imported_by Ord = '[] type instance Consts_imported_by Real = '[] type instance Consts_imported_by Traversable = '[] -- * Type 'Proj_Con' -- | Convenient type synonym wrapping 'Proj_ConR' -- to initiate its recursion. type Proj_Con cs = Proj_ConR cs cs -- | Project the 'Constraint' indexed by the given 'Type' -- onto its proof, captured by 'Con' when it holds. proj_con :: forall cs q. Proj_Con cs => Type cs 'KiCon q -> Maybe (Con (UnProxy q)) proj_con = proj_conR (Proxy::Proxy cs) -- ** Class 'Proj_ConR' -- | Intermediate type class to construct an instance of 'Proj_Con' -- from many instances of 'Proj_ConC', one for each 'Const' of @cs@. -- -- * @cs@: starting list of /type constants/. -- * @rs@: remaining list of /type constants/. class Proj_ConR cs rs where proj_conR :: Proxy rs -> Type cs 'KiCon q -> Maybe (Con (UnProxy q)) proj_conR _c _q = Nothing -- | Test whether @c@ handles the work of 'Proj_Con' or not, -- or recurse on @rs@, preserving the starting list of /type constants/. instance ( Proj_ConC cs c , Proj_ConR cs rs ) => Proj_ConR cs (c ': rs) where proj_conR _cs q = proj_conR (Proxy::Proxy rs) q `fromMaybe` proj_conC (Proxy::Proxy c) q -- | End the recursion. instance Proj_ConR cs '[] where proj_conR _cs _q = Nothing -- ** Class 'Proj_ConC' -- | Handle the work of 'Proj_Con' for a given /type constant/ @c@, -- that is: maybe it handles the given 'Constraint', -- and if so, maybe the 'Constraint' holds. class Proj_ConC cs c where proj_conC :: Proxy c -> Type cs 'KiCon q -> Maybe (Maybe (Con (UnProxy q))) proj_conC _c _q = Nothing instance -- [] ( Proj_Const cs (Proxy []) , Proj_Consts cs (Consts_imported_by []) , Proj_Con cs ) => Proj_ConC cs (Proxy []) where proj_conC _ (TyConst q :$ TyConst c) | Just Refl <- proj_const c (Proxy::Proxy []) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Applicative) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Foldable) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Functor) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Monad) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Traversable) -> Just Con _ -> Nothing proj_conC _ (t@(TyConst q) :$ (TyConst c :$ a)) | Just Refl <- proj_const c (Proxy::Proxy []) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Eq) , Just Con <- proj_con (t :$ a) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Monoid) , Just Con <- proj_con (t :$ a) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Ord) , Just Con <- proj_con (t :$ a) -> Just Con _ -> Nothing proj_conC _c _q = Nothing instance -- (->) ( Proj_Const cs (Proxy (->)) , Proj_Consts cs (Consts_imported_by (->)) , Proj_Con cs ) => Proj_ConC cs (Proxy (->)) where proj_conC _ (TyConst q :$ (TyConst c :$ _r)) | Just Refl <- proj_const c (Proxy::Proxy (->)) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Functor) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Applicative) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Monad) -> Just Con _ -> Nothing proj_conC _ (t@(TyConst q) :$ (TyConst c :$ _a :$ b)) | Just Refl <- proj_const c (Proxy::Proxy (->)) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Monoid) , Just Con <- proj_con (t :$ b) -> Just Con _ -> Nothing proj_conC _c _q = Nothing instance -- Applicative ( Proj_Const cs (Proxy Applicative) , Proj_Consts cs (Consts_imported_by Applicative) ) => Proj_ConC cs (Proxy Applicative) instance -- Bool ( Proj_Const cs (Proxy Bool) , Proj_Consts cs (Consts_imported_by Bool) ) => Proj_ConC cs (Proxy Bool) where proj_conC _ (TyConst q :$ TyConst c) | Just Refl <- proj_const c (Proxy::Proxy Bool) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Bounded) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Enum) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Eq) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Ord) -> Just Con _ -> Nothing proj_conC _c _q = Nothing instance -- Bounded ( Proj_Const cs (Proxy Bounded) , Proj_Consts cs (Consts_imported_by Bounded) ) => Proj_ConC cs (Proxy Bounded) instance -- Enum ( Proj_Const cs (Proxy Enum) , Proj_Consts cs (Consts_imported_by Enum) ) => Proj_ConC cs (Proxy Enum) instance -- Eq ( Proj_Const cs (Proxy Eq) , Proj_Consts cs (Consts_imported_by Eq) ) => Proj_ConC cs (Proxy Eq) instance -- Foldable ( Proj_Const cs (Proxy Foldable) , Proj_Consts cs (Consts_imported_by Foldable) ) => Proj_ConC cs (Proxy Foldable) instance -- Functor ( Proj_Const cs (Proxy Functor) , Proj_Consts cs (Consts_imported_by Functor) ) => Proj_ConC cs (Proxy Functor) instance -- Int ( Proj_Const cs (Proxy Int) , Proj_Consts cs (Consts_imported_by Int) ) => Proj_ConC cs (Proxy Int) where proj_conC _ (TyConst q :$ TyConst c) | Just Refl <- proj_const c (Proxy::Proxy Int) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Bounded) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Enum) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Eq) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Integral) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Num) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Ord) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Real) -> Just Con _ -> Nothing proj_conC _c _q = Nothing instance -- Integer ( Proj_Const cs (Proxy Integer) , Proj_Consts cs (Consts_imported_by Integer) ) => Proj_ConC cs (Proxy Integer) where proj_conC _ (TyConst q :$ TyConst c) | Just Refl <- proj_const c (Proxy::Proxy Integer) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Enum) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Eq) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Integral) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Num) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Ord) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Real) -> Just Con _ -> Nothing proj_conC _c _q = Nothing instance -- Integral ( Proj_Const cs (Proxy Integral) , Proj_Consts cs (Consts_imported_by Integral) ) => Proj_ConC cs (Proxy Integral) instance -- IO ( Proj_Const cs (Proxy IO) , Proj_Consts cs (Consts_imported_by IO) ) => Proj_ConC cs (Proxy IO) where proj_conC _ (TyConst q :$ TyConst c) | Just Refl <- proj_const c (Proxy::Proxy IO) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Applicative) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Functor) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Monad) -> Just Con _ -> Nothing proj_conC _c _q = Nothing instance -- Maybe ( Proj_Const cs (Proxy Maybe) , Proj_Consts cs (Consts_imported_by Maybe) , Proj_Con cs ) => Proj_ConC cs (Proxy Maybe) where proj_conC _ (TyConst q :$ TyConst c) | Just Refl <- proj_const c (Proxy::Proxy Maybe) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Applicative) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Foldable) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Functor) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Monad) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Traversable) -> Just Con _ -> Nothing proj_conC _ (t@(TyConst q) :$ (TyConst c :$ a)) | Just Refl <- proj_const c (Proxy::Proxy Maybe) = Just $ case () of _ | Just Refl <- proj_const q (Proxy::Proxy Eq) , Just Con <- proj_con (t :$ a) -> Just Con | Just Refl <- proj_const q (Proxy::Proxy Monoid) , Just Con <- proj_con (t :$ a) -> Just Con _ -> Nothing proj_conC _c _q = Nothing instance -- Monad ( Proj_Const cs (Proxy Monad) , Proj_Consts cs (Consts_imported_by Monad) ) => Proj_ConC cs (Proxy Monad) instance -- Monoid ( Proj_Const cs (Proxy Monoid) , Proj_Consts cs (Consts_imported_by Monoid) ) => Proj_ConC cs (Proxy Monoid) instance -- Num ( Proj_Const cs (Proxy Num) , Proj_Consts cs (Consts_imported_by Num) ) => Proj_ConC cs (Proxy Num) instance -- Ord ( Proj_Const cs (Proxy Ord) , Proj_Consts cs (Consts_imported_by Ord) ) => Proj_ConC cs (Proxy Ord) instance -- Real ( Proj_Const cs (Proxy Real) , Proj_Consts cs (Consts_imported_by Real) ) => Proj_ConC cs (Proxy Real) instance -- Traversable ( Proj_Const cs (Proxy Traversable) , Proj_Consts cs (Consts_imported_by Traversable) ) => Proj_ConC cs (Proxy Traversable)