
On Thu, Apr 02, 2009 at 11:53:00AM -0400, Jeff Heard wrote:
and so forth to be compatible with Bus [EData a], but I think that in the end so many widgets will reuse the EData type that it's just as well to make it part of the Event rather than force the user to be explicit about it every time. But if I'm generally disagreed with about this, I can change it -- I'm pretty neutral about it, to be honest.
Why not trying something like what was done with the new extensible extensions, using typeable existencials and casts? That way you could put any value you want and they would all be first class citizens. Another random idea: a phantom type could be used to be explicit about the type of event something produces or expects, something on the lines of
data EData a = forall b. Typeable b => EData b deriving (Typeable)
-- | Extract the data. extract :: EData a -> a extract (EData d) = case cast d of Just x -> x Nothing -> error "extract: phantom didn't match"
-- | Carefull extract the data, returns @Nothing@ if the phantom -- type doesn't match. extractM :: EData a -> Maybe a extractM (EData d) = cast d
-- | Extracts any type of data from a polymorphic 'EData'. extractAny :: (forall a. EData a) -> Maybe b extractAny (EData d) = cast d -- Is the forall above useful to prevent mistakes or not?
-- | Unsafely casts the phantom type to another one. unsafeCastData :: EData a -> EData b unsafeCastData (EData d) = EData d
Your examples would become something like
commandLineArgsWidget :: Widget [String] commandLineArgsWidget = getArgs >>= \args -> produce' "Environment" "CommandLineArgsWidget" "argv" Persistent args
environmentWidget :: Widget String environmentWidget b = getEnvironment >>= mapM_ (\(k,v) -> produce' "Environment" "EnvironmentWidget" k Persistent v b)
progNameWidget :: Widget String progNameWidget b = getProgName >>= \v -> produce' "Environment" "ProgramNameWidget" "ProgramName" Persistent v b
where I'm assuming that you could construct the EData inside produce' as now that's the only constructor available. The bus could then be polymorphic on the phantom type. Why use phantom types at all, then? It at least serves for documentation purposes. Well, it is a random idea after all :). -- Felipe.