[Haskell-cafe] type variable in class instance
Sean Leather
leather at cs.uu.nl
Tue Sep 11 22:18:30 CEST 2012
On Tue, Sep 11, 2012 at 9:18 PM, Corentin Dupont wrote:
> That's very interesting.
> One problem is, if the set of event is closed, the set of possible data
> types is not (the user can choose any data type for a Message callback for
> example). I think this can be solved using a class instead of a GADT for
> "Type". One can also use a type witness?
>
Just a "bit" more complicated...
{-# LANGUAGE TypeFamilies, GADTs #-}
import Data.Typeable
import Unsafe.Coerce
data Player = Arrive | Leave deriving Show
newtype Message t = Message String deriving (Eq, Show)
data Type :: * -> * where
MessageT :: Typeable t => Proxy t -> Type (Message t)
PlayerT :: Type Player
data Proxy t
typeOfProxy :: Typeable t => Proxy t -> TypeRep
typeOfProxy x = typeOf (unproxy x)
where
unproxy :: Proxy t -> t
unproxy = undefined
data TEq :: * -> * -> * where
Refl :: TEq a a
teq :: Type a -> Type b -> Maybe (TEq a b)
teq (MessageT p) (MessageT q)
| typeOfProxy p == typeOfProxy q = Just (unsafeCoerce Refl)
teq PlayerT PlayerT = Just Refl
teq _ _ = Nothing
type family Data t :: *
type instance Data (Message t) = t
type instance Data Player = Int
data Event t = Event (Type t) t
data Handler where
Handler :: Event t -> (Data t -> IO ()) -> Handler
runHandler :: Eq t => Event t -> Data t -> Handler -> IO ()
runHandler (Event t e) d (Handler (Event u e') f) =
case teq t u of
Just Refl | e == e' -> f d
_ -> return ()
runHandlers :: Eq t => Event t -> Data t -> [Handler] -> IO ()
runHandlers e d hs = mapM_ (runHandler e d) hs
-- Replacement for viewEvent
instance Show (Event t) where
show (Event ty e) =
case ty of
MessageT t -> show e ++ " of type " ++ show (typeOfProxy t)
PlayerT -> "Player " ++ show e
messageEvent :: Typeable t => Proxy t -> String -> Event (Message t)
messageEvent t s = Event (MessageT t) (Message s)
playerEvent :: Player -> Event Player
playerEvent = Event PlayerT
-- Tests
int :: Proxy Int
int = undefined
event1 = messageEvent int "give me a number" -- No type signature
necessary!
handler1 = Handler event1 (\n -> putStrLn $ "Your number is: " ++ show n)
test1 = runHandlers event1 1 [handler1] -- Yields "Your number is: 1"
The Proxy type is not absolutely necessary, because you can use the type
directly. But I think the Proxy makes it clear that no (non-bottom) terms
of the type are expected.
Regards,
Sean
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20120911/50afdf31/attachment.htm>
More information about the Haskell-Cafe
mailing list