If I understand, the SomeEvent event acts as a proxy to hide the diversity of the events? That&#39;s interesting.<br>This way I don&#39;t have to use an heterogeneous list and a lot of casting...<br><br><div class="gmail_quote">
On Wed, Sep 12, 2012 at 7:44 AM,  <span dir="ltr">&lt;<a href="mailto:oleg@okmij.org" target="_blank">oleg@okmij.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Let me see if I understand. You have events of different sorts: events<br>
about players, events about timeouts, events about various<br>
messages. Associated with each sort of event is a (potentially open)<br>
set of data types: messages can carry payload of various types. A<br>
handler specifies behavior of a system upon the reception of an<br>
event. A game entity (player, monster, etc) is a collection of<br>
behaviors. The typing problem is building the heterogeneous collection<br>
of behaviors and routing an event to the appropriate handler. Is this<br>
right?<br>
<br>
There seem to be two main implementations, with explicit types and latent<br>
(dynamic) types. The explicit-type representation is essentially HList<br>
(a Type-indexed Record, TIR, to be precise). Let&#39;s start with the<br>
latent-type representation. Now I understand your problem better, I<br>
think your original approach was the right one. GADT was a<br>
distraction, sorry. Hopefully you find the code below better reflects<br>
your intentions.<br>
<br>
{-# LANGUAGE ExistentialQuantification, DeriveDataTypeable #-}<br>
{-# LANGUAGE StandaloneDeriving #-}<br>
<br>
import Data.Typeable<br>
<br>
-- Events sorts<br>
<br>
data Player = Player PlayerN PlayerStatus<br>
        deriving (Eq, Show, Typeable)<br>
<br>
type PlayerN = Int<br>
data PlayerStatus = Enetering | Leaving<br>
        deriving (Eq, Show)<br>
<br>
newtype Message m = Message m<br>
        deriving (Eq, Show)<br>
<br>
deriving instance Typeable1 Message<br>
<br>
newtype Time = Time Int<br>
        deriving (Eq, Show, Typeable)<br>
<br>
data SomeEvent = forall e. Typeable e =&gt; SomeEvent e<br>
        deriving (Typeable)<br>
<br>
-- They are all events<br>
<br>
class Typeable e =&gt; Event e where                       -- the Event predicate<br>
  what_event :: SomeEvent -&gt; Maybe e<br>
  what_event (SomeEvent e) = cast e<br>
<br>
<br>
instance Event Player<br>
instance Event Time<br>
instance Typeable m =&gt; Event (Message m)<br>
<br>
instance Event SomeEvent where<br>
  what_event = Just<br>
<br>
-- A handler is a reaction on an event<br>
-- Given an event, a handler may decline to handle it<br>
type Handler e = e -&gt; Maybe (IO ())<br>
<br>
inj_handler :: Event e =&gt; Handler e -&gt; Handler SomeEvent<br>
inj_handler h se | Just e &lt;- what_event se = h e<br>
inj_handler _ _ = Nothing<br>
<br>
<br>
type Handlers = [Handler SomeEvent]<br>
<br>
trigger :: Event e =&gt; e -&gt; Handlers -&gt; IO ()<br>
trigger e [] = fail &quot;Not handled&quot;<br>
trigger e (h:rest)<br>
  | Just rh &lt;- h (SomeEvent e) = rh<br>
  | otherwise      = trigger e rest<br>
<br>
-- Sample behaviors<br>
<br>
-- viewing behavior (although viewing is better with Show since all<br>
-- particular events implement it anyway)<br>
<br>
view_player :: Handler Player<br>
view_player (Player x s) = Just . putStrLn . unwords $<br>
                              [&quot;Player&quot;, show x, show s]<br>
<br>
-- View a particular message<br>
view_msg_str :: Handler (Message String)<br>
view_msg_str (Message s) = Just . putStrLn . unwords $<br>
                             [&quot;Message&quot;, s]<br>
<br>
-- View any message<br>
view_msg_any :: Handler SomeEvent<br>
view_msg_any (SomeEvent e)<br>
  | (tc1,[tr]) &lt;- splitTyConApp (typeOf e),<br>
    (tc2,_)    &lt;- splitTyConApp (typeOf (undefined::Message ())),<br>
    tc1 == tc2 =<br>
        Just . putStrLn . unwords $ [&quot;Some message of the type&quot;, show tr]<br>
view_msg_any _ = Nothing<br>
<br>
viewers = [inj_handler view_player, inj_handler view_msg_str, view_msg_any]<br>
<br>
<br>
test1 = trigger (Player 1 Leaving) viewers<br>
-- Player 1 Leaving<br>
<br>
test2 = trigger (Message &quot;str1&quot;) viewers<br>
-- Message str1<br>
<br>
test3 = trigger (Message (2::Int)) viewers<br>
-- Some message of the type Int<br>
<br>
<br>
</blockquote></div><br>