OP's point was not so much that the Haskell syntax is clean, but more that there is a huge difference between
Map Integer String -> String -> Integer
Map Integer String -> String -> IO Integer
The latter is allowed to do IO, while the former is not. There are very few languages that allow you to express this difference and have the compiler enforce it (Haskell being one of them). So "Map Integer String -> String -> Integer" tells you a lot more than "def boo(map: Map[Integer, String], key: String) : Integer" does.
For more information about what exactly types tell you, look up parametricity or read Philip Wadler's "Theorems for free".