Hi,<br>it works very well!<br>I tried to implement it. Here is my test code. Apparently I need some casts to search the list.<br>The syntax looks good. Only addEvent will be on the interface, so that should be fine. If I understand well, that's this function that enforces the right types to be used. The events are referenced via the type of data they use.<br>
It just bothers me a little that I'm not able to enumerate the events, and also that the user is able to create events with wrong types (like New :: Event String), even if they won't be able to register them.<br><br>
I also have several unrelated events that use the same type of data, so this would be a problem. Adding more events like<br><i>data Event d = NewPlayer | NewRule deriving (Typeable, Eq)</i><br>is not correct because I can add wrong events like:<br>
addEvent (NewPlayer :: Event Rule) (H(undefined::(Rule -> IO()))) []<br><i></i><br>Also one question: I don't understand the "where" clause in your class. If I remove it, it works the same...<br><br>Here is my code:<br>
<br><i>newtype Player = P Int deriving Typeable <br>newtype Rule = R Int deriving Typeable<br>data Event d = New deriving (Typeable, Eq) <br><br>class (Typeable d) => Handled d where <br>data Handler d = H (d -> IO ())<br>
<br>data EventHandler = forall d . (Handled d) => EH (Event d) (Handler d)<br><br>instance Handled Player<br>instance Handled Rule<br><br>addEvent :: (Handled d) => Event d -> Handler d -> [EventHandler] -> [EventHandler] <br>
addEvent e h ehs = (EH e h):ehs<br> <br>triggerEvent :: (Handled d) => Event d -> d -> [EventHandler] -> IO ()<br>triggerEvent e d ehs = do<br> let r = find (\(EH myEvent _) -> cast e == Just myEvent) ehs<br>
case r of<br> Nothing -> return ()<br> Just (EH _ (H h)) -> case cast h of<br> Just castedH -> castedH d<br> Nothing -> return ()<br><br>h1 :: Player -> IO ()<br>h1 (P a) = putStrLn $ "Welcome Player " ++ (show a) ++ "!"<br>
h2 :: Rule -> IO ()<br>h2 (R a) = putStrLn $ "New Rule " ++ (show a)<br>eventList1 = addEvent (New :: Event Player) (H h1) []<br>eventList2 = addEvent (New :: Event Rule) (H h2) eventList1<br><br>trigger1 = triggerEvent (New :: Event Player) (P 1) eventList2 -- yelds "Welcome Player 1!"<br>
trigger2 = triggerEvent (New :: Event Rule) (R 2) eventList2 --yelds "New Rule</i> 2"<br><br>Best,<br>Corentin<br><br><div class="gmail_quote">On Fri, Jun 15, 2012 at 12:40 AM, Alexander Solla <span dir="ltr"><<a href="mailto:alex.solla@gmail.com" target="_blank">alex.solla@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br><br><div class="gmail_quote"><div class="im">On Thu, Jun 14, 2012 at 2:04 PM, Corentin Dupont <span dir="ltr"><<a href="mailto:corentin.dupont@gmail.com" target="_blank">corentin.dupont@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
That look really nice!<br>Unfortunately I need to have an heterogeneous list of all events with their handlers.<br>With this test code it won't compile:<br><br>test1 = addEvent (New :: Event Player) (H (undefined::(Player -> IO ()))) []<br>
test2 = addEvent (New :: Event Rule) (H (undefined::(Rule -> IO ()))) test1<div><div><br></div></div></blockquote><div><br></div></div><div>Right, okay. Heterogenous lists are tricky, but I think we can get away with using ExistentialQuantification, since you seem to only want to dispatch over the heterogenous types. The assumption I made is a big deal! It means you can't extract the d value. You can only apply properly typed functions (your handlers) on it.</div>
<div> </div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote><i><div style="text-align:left;display:inline!important">{-# LANGUAGE ExistentialQuantification #-} </div></i><br><blockquote style="margin:0 0 0 40px;border:none;padding:0px">
</blockquote><i><div style="display:inline!important"><div style="text-align:left;display:inline!important"><i><div style="display:inline!important">type Player = Int</div></i></div></div></i><div class="im"><br><blockquote style="margin:0 0 0 40px;border:none;padding:0px">
</blockquote><i><div style="display:inline!important"><div style="text-align:left;display:inline!important"><i><div style="display:inline!important">type Rule = Int</div></i></div></div></i><br><blockquote style="margin:0 0 0 40px;border:none;padding:0px">
</blockquote><i><div style="text-align:left;display:inline!important"><i>data Event d = New d</i></div></i><br><i><br></i><blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote></div><i style="text-align:left">class Handled data where -- Together with EventHandler, corresponds to your "Data" type</i><br>
<i><br></i><blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote><i style="text-align:left">data EventHandler = forall d . (Handled d) => EH (Event d) (d -> IO ()) -- EventHandler takes the place of your (Event d, Handler d) pairs without referring to d.</i><div class="im">
<br>
<i><br></i><blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote><i style="text-align:left">instance Handled Player</i><br><blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote><i style="text-align:left">instance Handled Rule</i><br>
<div style="text-align:left"><br></div><div style="text-align:left"><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote></div><i style="text-align:left">addEvent :: (Handled d) => Event d -> Handler d -> [EventHandler] -> [EventHandler] -- Every [EventHandler] made using addEvent will be of "correct" types (i.e., preserve the typing invariants you want), but YOU must ensure that only [EventHandler]s made in this way are used. This can be done statically with another type and an explicit export list. We can talk about that later, if this works in principle.</i><br>
<blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote><span style="text-align:left"> </span><br><blockquote style="margin:0 0 0 40px;border:none;padding:0px"></blockquote><span style="text-align:left"> </span><br>
<div class="gmail_quote"><div><div><div class="gmail_quote"><div class="gmail_quote"><div style="text-align:left"><i>triggerEvent :: (Handled d) => Event d -> d -> [EventHandler] -> IO ()</i></div>
</div></div></div></div></div><div class="gmail_quote"><div> </div></div><br>
</blockquote></div><br>