reflection-0.7: examples/Monoid.hs
{-# LANGUAGE Rank2Types, KindSignatures #-}
import Data.Reflection
import Data.Monoid
import Data.Proxy
newtype M (s :: * -> *) a = M { runM :: a }
data Monoid_ a = Monoid_ { mappend_ :: a -> a -> a, mempty_ :: a }
instance Reified s => Monoid (M s a) where
mappend a b = M $ mappend_ (reflectM a) (runM a) (runM b)
mempty = r where r = M $ mempty_ $ reflectM r
monoidProxy :: M s a -> Proxy (s (Monoid_ a))
monoidProxy _ = Proxy
reflectM :: Reified s => M s a -> Monoid_ a
reflectM m = reflect (monoidProxy m)
reifyMonoid :: (a -> a -> a) -> a -> (forall s. Reified s => Proxy (s (Monoid_ a)) -> r) -> r
reifyMonoid f z = reify (Monoid_ f z)
-- > ghci> withMonoid (+) 0 (mempty `mappend` M 2)
-- > 2
withMonoid :: (a -> a -> a) -> a -> (forall s. Reified s => M s a) -> a
withMonoid f z v = reifyMonoid f z (\p -> runM (v `asProxyOf` p)) where
asProxyOf :: M s x -> Proxy (s (Monoid_ x)) -> M s x
asProxyOf a _ = a