
Corentin Dupon wrote about essentially the read-show problem:
class (Typeable e) => Event e
data Player = Player Int deriving (Typeable) data Message m = Message String deriving (Typeable)
instance Event Player
instance (Typeable m) => Event (Message m)
viewEvent :: (Event e) => e -> IO () viewEvent event = do case cast event of Just (Player a) -> putStrLn $ show a Nothing -> return () case cast event of Just (Message s) -> putStrLn $ show s Nothing -> return ()
Indeed the overloaded function cast needs to know the target type -- the type to cast to. In case of Player, the pattern (Player a) uniquely determines the type of the desired value: Player. This is not so for Message: the pattern (Message s) may correspond to the type Message (), Message Int, etc. To avoid the problem, just specify the desired type explicitly
case cast event of Just (Message s::Message ()) -> putStrLn $ show s Nothing -> return ()
(ScopedTypeVariables extension is needed). The exact type of the message doesn't matter, so I chose Message (). BTW, if the set of events is closed, GADTs seem a better fit
data Player data Message s
data Event e where Player :: Int -> Event Player Message :: String -> Event (Message s)
viewEvent :: Event e -> IO () viewEvent (Player a) = putStrLn $ show a viewEvent (Message s) = putStrLn $ show s