Первое, что путает вещи, это Num a =>
, поэтому мы сейчас будем игнорировать это. Вместо этого давайте рассмотрим Int -> Int -> Int
, что является одной из возможных специализаций подписи типа, которую вы дали.
Функции почти всегда curried в Haskell. Это означает, что функция с несколькими аргументами фактически является функцией одного аргумента, который возвращает функцию, которая принимает следующий аргумент, и так далее.
->
является правильным ассоциативным, поэтому Int -> Int -> Int
- это то же самое, что и Int -> (Int -> Int)
.
Это также означает, что это определение
f :: Int -> Int -> Int
f x y = x + y
такая же, как
f :: Int -> Int -> Int
f x = \y -> x + y
На самом деле, все функции в Haskell взять ровно один аргумент. Также существуют кортежи, но они являются первоклассными гражданами, поэтому они больше, чем просто список аргументов.
Num a =>
- это немного другой аспект системы типов. В нем говорится, что переменная типа a
должна быть экземпляром класса типа Num
. Общие примеры типов, которые являются экземплярами Num
, включают Int
и Double
. Таким образом, Num
не является самим типом, это класс типа. Num a =>
представляет собой ограничение на переменную типа a
, это не является еще одним аргументом для функции.
(+)
метод является членом класса Num
типа, так что вы должны ограничить a
таким образом, чтобы использовать (+)
. Если вы попытаетесь дать f
подпись a -> a -> a
(без ограничений), это не сработает, потому что a
полностью не имеет ограничений, и мы ничего не знаем о том, какие типы это могут быть. В результате мы не смогли использовать (+)
.
Что бы вы написали, если бы у вас был '(Ord a, Num a) => a -> a -> a'? – Squidly