Ответ 1
Да, есть разница, потому что конструктор типа ->
является право-ассоциативным. Другими словами,
a -> b -> f a -> f b
эквивалентно
a -> (b -> (f a -> f b))
Эта сигнатура типа обозначает функцию, которая принимает параметр типа a
и возвращает функцию, которая сама принимает параметр типа b
и возвращает функцию, которая сама принимает параметр типа f a
и возвращает значение типа f b
.
С другой стороны,
(a -> b) -> f a -> f b
обозначает функцию, которая принимает параметр типа a -> b
(т.е. функцию, которая принимает параметр типа a
и возвращает значение типа b
) и возвращает функцию, которая сама принимает параметр типа f a
и возвращает значение типа f b
.
Вот надуманный пример, иллюстрирующий разницу между двумя типами сигнатур:
f :: (Int -> Bool) -> [Int] -> [Bool]
f = map
g :: Int -> Bool -> [Int] -> [Bool]
g n b = map (\n' -> (n' == n) == b)
λ> let ns = [42, 13, 42, 17]
λ> f (== 42) ns
[True,False,True,False]
λ> g 42 True ns
[True,False,True,False]
λ> g 42 False ns
[False,True,False,True]