That look really nice! Unfortunately I need to have an heterogeneous list of all events with their handlers. With this test code it won't compile:
test1 = addEvent (New :: Event Player) (H (undefined::(Player -> IO ()))) [] test2 = addEvent (New :: Event Rule) (H (undefined::(Rule -> IO ()))) test1 On Thu, Jun 14, 2012 at 10:05 PM, Alexander Solla <[email protected]>wrote: > > > On Thu, Jun 14, 2012 at 12:15 PM, Corentin Dupont < > [email protected]> wrote: > >> Hi folks, >> I'm trying to make a simple event driven engine. It simply consists of >> two functions: >> - "addEvent", where you pass the event name with a callback, >> - "triggerEvent" where you pass the event name with the data. >> the data shall be passed to the callback of the corresponding event. >> >> I have trouble making it correctly typed. >> Here is my try: >> * >> type Player = Int --dummy types for the example >> type Rule = Int >> data EventEnum = NewPlayer | NewRule deriving Eq >> data Data = P Player | R Rule >> data Handler = H (Data -> IO ()) >> >> addEvent :: EventEnum -> Handler -> [(EventEnum, Handler)] -> >> [(EventEnum, Handler)] >> addEvent e h es = (e,h):es >> >> triggerEvent :: EventEnum -> Data -> [(EventEnum, Handler)] -> IO () >> triggerEvent e d es = do >> let r = lookup e es >> case r of >> Nothing -> return () >> Just (H h) -> h d* >> >> The trouble is that I want the user to be only able to add an event that >> is compatible with its handler: >> For example the event NewPlayer should have a handler of type Player -> >> IO (). The data passed when triggering this event should be only of type >> Player. >> How can I do that? It sound like dependant typing... >> >> > Haven't tried it, and I don't know if it actually does what you want in > the big picture. But you can do "dynamic" dependent typing with dummy > (free) type variables. > > * > type Player = Int --dummy types for the example > type Rule = Int > data Event d = New deriving Eq -- not necessary for this example, but you > might want to enumerate other events. > > * > *class Handled data where -- Corresponds to your "Data" type > > * > *data Handler d = H (d -> IO ())* > * > * > *instance Handled Player* > *instance Handled Rule* > * > * > *addEvent :: (Handled d) => Event d -> Handler d -> [(Event d, Handler > d)] -> [(Event d, Handler)]* > *triggerEvent :: (Handled d) => Event d -> d -> [(Event d, Handler d)] -> > IO ()* > * > * > Basically, this means that Events are "keyed" into separate spaces by the > Handled types. (New :: Event Player) has a different type as (New :: Event > Rule). > > You might want to look into ScopedTypeVariables. >
_______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
