
Hi David,
that may be also a way to go. I've also looked into this way (view
patterns), unfortunately it seems that I will be obliged to maintain 2
parallel structures:
for each Event instance, I will have to add a ViewEvent element as well
carrying the same information:
instance Event Time where
eventType = TimeEvent
data EventType e where
PlayerEvent :: EventType Player
MessageEvent :: EventType (Message m)
TimeEvent :: EventType Time
That's why I like the all-GADT solution...
Corentin
On Tue, Sep 11, 2012 at 6:46 PM, David Menendez
I'm not sure I understand
Yes. That's fantastic! This GADT is the missing piece of my puzzle. I
On Tue, Sep 11, 2012 at 11:06 AM, Corentin Dupont
wrote: transformed a bit your solution, polluting it with some classes instances and fleshing the functions:
data Player = Arrive | Leave deriving (Show, Typeable, Eq) data Message m = Message String deriving (Show, Typeable, Eq)
data Data a where PlayerData :: Int -> Data Player MessageData :: m -> Data (Message m)
data Handler where Handler :: (Typeable e) => e -> (Data e -> IO ()) -> Handler
instance forall e. (Typeable e) => Typeable (Data e) where typeOf _ = mkTyConApp (mkTyCon( ("Expression.EventData (" ++ (show $ typeOf (undefined::e))) ++ ")" )) []
addEvent :: (Typeable e) => e -> (Data e -> IO ()) -> [Handler] -> [Handler] addEvent e h hs = (Handler e h) : hs
triggerEvent :: (Eq e, Typeable e) => e -> Data e -> [Handler] -> IO () triggerEvent e d hs = do let filtered = filter (\(Handler e1 _) -> e1 === e) hs mapM_ f filtered where f (Handler _ h) = case cast h of Just castedH -> do castedH d Nothing -> return ()
viewEvent :: (Typeable e) => e -> IO()
viewEvent event = do case cast event of Just (a :: Player) -> putStrLn $ "Player" ++ show a
Nothing -> return () case cast event of (Just (Message s)) -> putStrLn $ "Player" ++ s Nothing -> return ()
Unfortunately, I still cannot pattern match on the events to view them (viewEvent won't compile)...
Mixing GADTs and Typeable seems like a bad idea. If you really don't want to put viewEvent in the Event typeclass, but the class of events is closed, you could use a GADT to witness the event type.
class Event e where eventType :: EventType e ...
data EventType e where PlayerEvent :: EventType Player MessageEvent :: EventType (Message m)
viewEvent :: Event e => e -> IO () viewEvent = viewEvent' eventType
viewEvent' :: EventType e -> e -> IO () viewEvent' PlayerEvent e = ... viewEvent' MessageEvent (Message s) = ...
-- Dave Menendez
http://www.eyrie.org/~zednenem/