Это потому что
Каждая функция в Haskell принимает единственный параметр и возвращает одно значение
Если функция должна принимать несколько значений, она была бы карри-функцией, или она должна принимать один кортеж .
Если мы добавим скобки, сигнатура функции станет:
sum :: (Num a) => a -> (a -> a)
В Haskell сигнатура функции: A -> B
означает функцию, «домен» функции - A
, а «кодомен» функции - B
; или на языке программиста функция принимает параметр типа A
и возвращает значение типа B
.
Следовательно, определение функции sum :: Num -> (Num -> Num)
означает, что сумма является «функцией, которая принимает параметр типа a
и возвращает функцию типа Num -> Num
».
По сути, это приводит к карри / частичной функции.
Концепция карри важна в функциональных языках, таких как Haskell, потому что вы захотите сделать что-то вроде:
map (sum 5) [1, 2, 3, 5, 3, 1, 3, 4] -- note: it is usually better to use (+ 5)
В этом коде (сумма 5) является функцией, которая принимает один параметр, эта функция (сумма 5) будет вызываться для каждого элемента в списке, например, ((сумма 5) 1) возвращает 6.
Если бы sum
имел подпись sum :: (Num, Num) -> Num
, то sum пришлось бы получать оба параметра одновременно, потому что теперь sum является «функцией, которая получает tuple (Num, Num)
и возвращает Num».
Теперь, второй вопрос, что означает Num a => a -> a
? По сути, это сокращение, чтобы сказать, что каждый раз, когда вы видите a
в подписи, заменяйте его на Num или на один из его производных классов.