I have a function that has type Read a => String -> a
, is it possible to have another function with the same name that does things differently when a
is for example String
? Are there any GHC extensions that allow this?
Something like:
f :: Read a => String -> a
f = read
f :: String -> String
f = id
In Haskell, this kind of function overloading (ad-hoc polymorphism) is accomplished by using type classes, not by binding the same name under multiple types.
{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
class F a where f :: String -> a
instance F String where f = id
instance F Int where f = read
instance F Char where f = read
instance F Float where f = read
-- etc.
Now, f
can operate on any type for which an instance of F
has been declared.
Unfortunately, you can't get away with the following:
instance Read a => F a where f = read
Perhaps unintuitively, this does not declare an instance of F
only for types which have an instance of Read
. Because GHC resolves instances using only the head of the instance declaration (the part to the right of the =>
), this actually declares all types a
to be instances of F
, but makes it a type error to call f
on anything which is not also an instance of Read
.
It will compile if you enable the UndecidableInstances
extension, but this just leads to other problems. It's a rabbit hole you don't really want to venture down.
Instead, you should declare an instance of F
for each individual type you intend f
to operate on. This isn't very burdensome for a simple class like this one, but if you use a recent version of GHC, you can use the following to make it slightly easier:
{-# LANGUAGE DefaultSignatures #-}
class F a where f :: String -> a
default f :: Read a => String -> a
f = read
Now, for any type which is an instance of Read
, you may declare its instance of F
without having to provide the implementation of f
explicitly:
instance F Int
instance F Char
instance F Float
-- etc.
For any types without instances of Read
, you'll still have to write an explicit implementation for f
.