
ghci> :set +t
ghci> "foo" "foo" it :: String
ghci> reverse "foo" "oof" it :: [Char]
I'm not a GHC expert, but my guess is: It must have something to do with unifying the argument types with the type signature of the function. In (<>), the two argument and the result types are identical. Hence it can be safely said that x <> whatever as long as this expression is valid, has the same type as x. In contrast, the result type of (++) is always of the shape [a]. Hence String gets unified with [a] which forces expansion of the type synonym. Consider: class Foo a where {rev :: a -> a; conc :: a -> a -> a} instance Foo [a] where {rev = reverse; conc = (++)} revconc :: Foo a => a -> a; revconc a = conc a (rev a) :t revconc ("foo" :: String) revconc ("foo" :: String) :: String So as long has you hide (++) in a type signature that proves input and output are the same, synonyms don't get expanded. Olaf