[Haskell-cafe] Am I using type families well?
Ryan Ingram
ryani.spam at gmail.com
Mon Nov 1 20:48:01 EDT 2010
This one is easy:
> -- | Class describing a resource of type @rsc@
> class (Ord (IdOf rsc)) => Resource rsc where
> type IdOf rsc
> type LocOf rsc
> type CfgOf rsc
> retrieveLoc :: CfgOf rsc -> IdOf rsc -> LocOf rsc
> load :: LocOf rsc -> IO (Maybe rsc)
> -- ^ Called when a resource needs to be loaded
> unload :: rsc -> IO ()
> -- ^ Idem for unloading
Consider this:
instance Resource () where
type IdOf () = Int
type LocOf () = String
type CfgOf () = ()
retrieveLoc () n = "Unit_" ++ show n
load = undefined
unload = undefined
instance Resource Int where
type IdOf () = Int
type LocOf () = String
type CfgOf () = ()
retrieveLoc () n = "Int_ " ++ show n
load = undefined
unload = undefined
foo = retrieveLoc :: () -> Int -> String -- which retrieveLoc is called here?
The problem, in case you haven't surmised it, is that retrieveLoc is
ambiguous; you can never call it! There's no way to know which
instance you might be referring to. You can work around it by making
one of the type families into a data family (which is injective; you
know that if CfgOf x = CfgOf y, then x = y). Or you can add a proxy
parameter to retrieveLoc:
> data Proxy a = Proxy
> retrieveLoc :: Proxy rsc -> CfgOf rsc -> IdOf rsc -> LocOf rsc
now:
> foo = retrieveLoc (Proxy :: Proxy ())
and ghc can correctly infer foo's type as
> foo :: () -> Int -> String
and foo will call the retrieveLoc from the () instance.
-- ryan
More information about the Haskell-Cafe
mailing list