{-# LANGUAGE MultiParamTypeClasses, ScopedTypeVariables, TypeFamilies, RankNTypes, DefaultSignatures, TypeApplications, UndecidableInstances, PackageImports #-} module Data.Reflection.Constraint where import Prelude hiding (Functor, (<$>), map) import Control.Categorical.Functor import Data.Constraint import Data.Function (on) import Data.Morphism.Iso import Data.Proxy import Data.Reflection (Reifies (..), reify) newtype Reflected c s a = Reflected { unReflected :: a } unReflected' :: proxy s -> Reflected c s a -> a unReflected' _ = unReflected class Functor (Iso (->)) (->) (Methods c) => Reifiable c where data Methods c a reifiable :: Reifies s (Methods c a) => Dict (c (Reflected c s a)) default reifiable :: c (Reflected c s a) => Dict (c (Reflected c s a)) reifiable = Dict reifiable' :: (Reifiable c, Reifies s (Methods c a)) => proxy s -> Dict (c (Reflected c s a)) reifiable' _ = reifiable by :: ∀ c f a . (Reifiable c, Functor (Iso (->)) (->) f) => Methods c a -> (∀ a . c a => f a) -> f a by methods a = reify methods (\ proxy -> Iso (unReflected' proxy) (Reflected @c) <$> withDict (reifiable' proxy) a) instance Reifiable Eq where newtype Methods Eq a = EqMethods { eqMethod :: a -> a -> Bool } instance Reifiable Ord where newtype Methods Ord a = OrdMethods { compareMethod :: a -> a -> Ordering } instance Reifiable Semigroup where newtype Methods Semigroup a = SemigroupMethods { combineMethod :: a -> a -> a } instance Reifiable Monoid where data Methods Monoid a = MonoidMethods { semigroupMethods :: Methods Semigroup a , memptyMethod :: a } instance {-# OVERLAPPING #-} Functor (Iso (->)) (->) (Methods Ord) where map (Iso _ f) (OrdMethods cmp) = OrdMethods (cmp `on` f) instance {-# OVERLAPPING #-} Functor (Iso (->)) (->) (Methods Eq) where map (Iso _ f) (EqMethods eq) = EqMethods (eq `on` f) instance {-# OVERLAPPING #-} Functor (Iso (->)) (->) (Methods Semigroup) where map (Iso f f') (SemigroupMethods (<>)) = SemigroupMethods (\ a b -> f (f' a <> f' b)) instance {-# OVERLAPPING #-} Functor (Iso (->)) (->) (Methods Monoid) where map φ@(Iso f _) (MonoidMethods sg mempty) = MonoidMethods (φ <$> sg) (f mempty) instance Reifies s (Methods Eq a) => Eq (Reflected Eq s a) where (==) = (eqMethod . reflect) (Proxy @s) `on` unReflected instance Reifies s (Methods Ord a) => Eq (Reflected Ord s a) where x == y = EQ == compare x y instance Reifies s (Methods Ord a) => Ord (Reflected Ord s a) where compare = (compareMethod . reflect) (Proxy @s) `on` unReflected instance Reifies s (Methods Semigroup a) => Semigroup (Reflected Semigroup s a) where a <> b = Reflected $ ((combineMethod . reflect) (Proxy @s) `on` unReflected) a b instance Reifies s (Methods Monoid a) => Semigroup (Reflected Monoid s a) where a <> b = Reflected $ ((combineMethod . semigroupMethods . reflect) (Proxy @s) `on` unReflected) a b instance Reifies s (Methods Monoid a) => Monoid (Reflected Monoid s a) where mempty = Reflected $ (memptyMethod . reflect) (Proxy @s)