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.