
I'm writing a tool for which there will be multiple storage formats. The user can choose his favorite storage mechanism through a configuration file. Possible storage mechanisms might include in-memory storage or on-disk storage. To represent this abstraction, I created a Storage type class and two simple instances: class Storage a where open :: String -> IO a data Disk = Disk instance Storage Disk where open file = do putStrLn $ "opening disk: " ++ file return Disk data Memory = Memory instance Storage Memory where open _ = do putStrLn "opening memory" return Memory I can load this code into ghci (version 6.10.1, if that matters) and it behaves as I expected it to: *Main> open "foo" :: IO Disk opening disk: foo *Main> open "foo" :: IO Memory opening memory Eventually a configuration facility will provide a string indicating which storage mechanism the user prefers. This will return a string like "memory" or "disk". Based on that string, I want to return a value whose type belongs to the Storage type class. I thought this would do the job: by_type :: Storage a => String -> String -> IO a by_type "disk" x = open x :: IO Disk by_type "memory" x = open x :: IO Memory by_type _ t = error $ "no such storage type " ++ t but I get the following compile errors: Couldn't match expected type `Disk' against inferred type `Memory' Expected type: IO a Inferred type: IO Memory In the expression: open x :: IO Memory In the definition of `by_type': by_type "memory" x = open x :: IO Memory It seems as though the type variable `a' is binding to Disk which prevents it from later binding to Memory. That makes sense but I don't see a way forward from here. How can I accomplish multiple implementations of the same interface? Are type classes the right way? Thank you for any help. -- Michael