Это все примеры «ограничений класса»: они ограничивают, какие типы могут использоваться вместо переменной типа, которая следует за ними (в данном случае a
), требуя, чтобы она принадлежала определенному классу типа .Ord
, Eq
и Num
являются примерами классов типов.
Ord a => ...
означает, что a
- это тип, с которым связано естественное понятие порядка.Например, целые числа могут быть естественным образом расположены от меньшего к большему.В математических терминах существует общий порядок на a
.Очевидным примером функции, которая требует этого ограничения, является sort :: Ord a => [a] -> [a]
;читайте эту подпись как говорящую о том, что sort
работает только со списками вещей, которые можно упорядочить относительно друг друга.
Eq a => ...
означает, что a
- это тип, члены которогоможно сравнить друг с другом для некоторого понятия равенства.В математических терминах существует отношение эквивалентности на a
.Обратите внимание, что это суперкласс Ord
, означающий, что все, что имеет понятие упорядочения, также должно иметь понятие эквивалентности.Примером функции, которая требует этого ограничения, является elem :: Eq a => a -> [a] -> Bool
(который определяет, содержит ли список данный элемент);прочитайте эту подпись как о том, что elem
работает только со списками вещей, которые можно сравнить друг с другом на равенство.Если вы думаете о том, как бы вы написали elem
самостоятельно, это должно иметь смысл.
Num a => ...
означает, что a
- это числовой тип, то есть он поддерживает некоторые основные арифметические операции:+
, *
, -
, abs
.Я считаю, что это примерно аналогично математическому понятию кольцо .В основном все типы, которые вы считаете «типами чисел», принадлежат этому классу: Int
, Double
и т. Д. Вы увидите ограничение Num a =>
перед сигнатурой, если функция была написана для работы с любымвид числа.Например, sum :: Num a => [a] -> a
, который суммирует все элементы списка чисел, может одинаково хорошо работать на [Int]
, [Double]
, [Rational]
и т. Д. ... все, что он должен сделать, это сложить его содержимое,независимо от того, что это за цифры.Но числами они должны быть!
По сути, эти классы / ограничения типов являются подходом к "принципиальной перегрузке" функций.Мы можем использовать (==) :: Eq a => a -> a -> Bool
для различных типов, но не только для любых типов .Некоторые вещи, например функции, не имеют смысла сравнивать на равенство (возможно, из-за того, что равенство не решаемо для этого типа), и это никогда имеет смысл сравнивать две вещи разных типов для равенства (в отличие от Java, где вы можете сравнивать любые два объекта, возможно, разных типов на равенство).
Для дальнейшего (очень доступного) чтения классов и ограничений типов я настоятельно рекомендую Learn You a Haskell .