Larry,
By your definition
f x = x
this function returns whatever it got in it's argument, thus:
1. compiler infers that it's argument is of type String from class-definition
2. String is actually a type-synonim for list of chars
type String = [Char]
3. So now, on one hand function is returning something of a concrete type [Char], and on the other (from class-definition) it should be some type only restricted by operations on type-class.
Regarding your question on "how to do things properly" -- I'm not sure what exactly are you trying to achieve. Could you describe a problem you're trying to solve?
If you want to return something of type b, which is only constrainted by being an instance of a type-class A, then you need to create it with a function defined in class A. But since only function is f, it's not enough. Here's an example of solution for the original "return something of another instance" problem:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
class A a where
f :: A b => a -> b
def :: a
instance A Int where
f x = def
def = 4
instance A String where
f x = def
def = "asd"
main :: IO ()
main = print $ (f "asd" :: Int)
Cheers.