{-# LANGUAGE ExistentialQuantification, DeriveDataTypeable, PatternSignatures #-} import Data.Typeable import Control.Concurrent import Control.Concurrent.MVar import Control.Concurrent.Chan -- Core data types data Message = forall t . Typeable t => Message t | StopMessage deriving Typeable data Handler = forall t . Typeable t => Handler (t -> IO ()) -- Worker thread data Worker = Worker (Chan Message) (MVar ()) workerThread :: [Handler] -> Chan Message -> MVar () -> IO () workerThread handlers chan finish = loop where loop = do message <- readChan chan case message of StopMessage -> putMVar finish () Message val -> do foldr (tryHandler val) (putStrLn "Unhandled message") handlers loop tryHandler val (Handler h) rest = maybe rest h (cast val) startWorker :: [Handler] -> IO Worker startWorker handlers = do chan <- newChan finish <- newEmptyMVar forkIO (workerThread handlers chan finish) return $ Worker chan finish send :: Typeable m => Worker -> m -> IO () send (Worker chan _) message = do writeChan chan $ Message message stopWorker :: Worker -> IO () stopWorker (Worker chan finish) = do writeChan chan $ StopMessage takeMVar finish -- Some tests data Test = Test Bool String deriving Typeable intHandler :: Int -> IO () intHandler val = putStrLn $ "Int: " ++ show (val * 2) strHandler :: String -> IO () strHandler val = putStrLn $ "String: " ++ reverse val testHandler :: Test -> IO () testHandler (Test b s) = putStrLn $ "Test: " ++ show b ++ " " ++ show s main = do w <- startWorker [ Handler intHandler, Handler (\(val::Char) -> putStrLn $ "Char: " ++ show val), Handler strHandler, Handler testHandler] send w (5::Int) send w False send w 'a' send w "foo" send w (Test True "bar") stopWorker w putStrLn "Finished!"