I want to be able to have a function, which implementation will choose a typeclass based on the manual type specification of it's return type.
Here's a contrived example: a typeclass and two instances:
class ToString a where
toString :: a -> String
instance ToString Double where
toString = const "double"
instance ToString Int where
toString = const "int"
I'm able to choose the instance by calling the toString with Int
type:
function :: String
function = toString (undefined :: Int)
So far so good. What I'd like to do is to be able to write the function, so it will work for any a
if there exists a typeclass for it:
function' :: (ToString a) => String
function' = toString (undefined :: a)
Here, the function'
doesn't compile, because the a
type parameter is not mentioned anywhere in the signature and it's not possible to specify the typeclass upon calling.
So it looks like the only option is to pass the type information about the type of a
into the return type:
data Wrapper a = Wrapper {
field :: String }
function'' :: (ToString a) => Wrapper a
function'' = Wrapper $ toString (undefined :: a)
showToString :: String
showToString = field (function'' :: Wrapper Int)
I define a Wrapper
type just for carrying the type information. In the showToString
, my hope is that since I specify the exact type of Wrapper
, then the typechecker can infer that the a
in function''
is and Int
and pick the Int
instance of the ToString
typeclass.
But the reality doesn't correspond with my hopes, this is the message from compiler
Could not deduce (ToString a0) arising from a use of `toString'
Is there a way, how to convince the compiler, that he can pick the right typeclass in the function''
, because I specify the it by having the type declaration of :: Wrapper Int
?
function''
the type expressionundefined::a
could be writtenundefined::b
without change in meaning, as type variables are not scoped (unless you turned the corresponding GHC extension on). – Ingo