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
I'm not sure I understand
Mixing GADTs and Typeable seems like a bad idea. If you really don't
On Tue, Sep 11, 2012 at 11:06 AM, Corentin Dupont
<corentin.dupont@gmail.com> wrote:
> Yes.
> That's fantastic! This GADT is the missing piece of my puzzle. I 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)...
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 <dave@zednenem.com>
<http://www.eyrie.org/~zednenem/>