
I have found it useful to use Dynamic-like existential types such as (fake example):
data Number = forall a. (Num a, Typeable a) => Number a
which supports precisely the same API as Dynamic, but with a Num constraint on everything. However, writing that API for this particular type requires copy-pasting the definitions of fromDyn and fromDynamic as boilerplate, which is (ahem) stupid. Now that we have the Constraint kind, it is possible to generalize this in a form suitable for Data.Dynamic:
data CDynamic (c :: Type -> Constraint) = forall a. (c a) => CDynamic (TypeRep a) a
toCDyn :: (c a, Typeable a) => a -> CDynamic c fromCDyn :: (c a, Typeable a) => CDynamic c -> a -> a fromCDynamic :: (c a, Typeable a) => CDynamic c -> Maybe a relaxCDyn :: CDynamic c -> Dynamic dynApplyC :: CDynamic c1 -> CDynamic c2 -> Maybe Dynamic dynAppC :: CDynamic c1 -> CDynamic c2 -> Dynamic dynTypeRepC :: CDynamic c -> SomeTypeRep
instance Show (CDynamic c) instance Exception (CDynamic c)
class NoC a where -- intentionally empty, can be used unsaturated instance NoC a where -- also empty type Dynamic = CDynamic NoC
-- Specializations of all the above functions
I think it's clear how to fill in the definitions. I added an apparently necessary function relaxCDyn that also does the obvious thing; I'm not really happy with its type signature but offhand I can't say how to generalize it. I think this is useful, and if I'm not missing anything (obvious or subtle) about it, I want to propose that it goes into Data.Dynamic.