It might be helpful to define a couple type aliases, to make it a bit more explicit what all those arrows and brackets are doing:
type F1 a b = a -> b -- type synonym for single-argument functions
type List a = [a] -- type synonym for lists
so now you can write map's type signature as:
map :: F1 s t -> List s -> List t
which, if you're more familiar with Java or C++ or whatever, looks syntactically a bit more like:
List<T> map(F1<S, T> fun, List<S> list); // applies fun to each element in list
So you can think of it this way: map takes a function and a list, and returns another list. However, since functions are curried in Haskell, you don't have to pass all parameters at once. You could get away with partially applying map to just its first argument. So really its type signature is more like:
F1<List<S>, List<T>> map(F1<S, T> fun); // returns a function that applies fun to each element in a list
... which, when you call map with just that one fun argument, gives you something that sort of looks like:
List<T> mapFun(List<S> list); // applies fun to each element in list
So now back to Haskell: you can read map :: (s -> t) -> [s] -> [t] either as:
- "
map takes a function from s to t, and a list of s, and returns a list of t"
- "
map takes a function from s to t, and turns it into a function from a list of s to a list of t"
The former is fine; the latter is more helpful.