. В этом смысле они являются полиморфными константами.
Все кортежи также являются частью класса >Bounded, если их компоненты принадлежат классу >Bounded.
>ghci> maxBound :: (Bool, Int, Char)
>(True,2147483647,'\1114111')
Класс >Num – это класс типов для чисел. Его экземпляры могут вести себя как числа. Давайте проверим тип некоторого числа:
>ghci> :t 20
>20 :: (Num t) => t
Похоже, что все числа также являются полиморфными константами. Они могут вести себя как любой тип, являющийся экземпляром класса >Num (>Int, >Integer, >Float или >Double).
>ghci> 20 :: Int
>20
>ghci> 20 :: Integer
>20
>ghci> 20 :: Float
>20.0
>ghci> 20 :: Double
>20.0
Если проверить тип оператора >*, можно увидеть, что он принимает любые числа.
>ghci> :t (*)
>(*) :: (Num a) => a –> a –> a
Он принимает два числа одинакового типа и возвращает число этого же типа. Именно поэтому >(5 :: Int) * (6 :: Integer) приведёт к ошибке, а >5 * (6 :: Integer) будет работать нормально и вернёт значение типа >Integer потому, что 5 может вести себя и как >Integer, и как >Int.
Чтобы присоединиться к классу >Num, тип должен «подружиться» с классами >Show и >Eq.
Класс >Floating включает в себя только числа с плавающей точкой, то есть типы >Float и >Double.
Функции, которые принимают и возвращают значения, являющиеся экземплярами класса >Floating, требуют, чтобы эти значения могли быть представлены в виде числа с плавающей точкой для выполнения осмысленных вычислений. Некоторые примеры: функции >sin, >cos и >sqrt.
Класс >Integral – тоже числовой класс типов. Если класс >Num включает в себя все типы, в том числе действительные и целые числа, то в класс >Integral входят только целые числа. Для типов >Int и >Integer определены экземпляры данного класса.
Очень полезной функцией для работы с числами является >fromIntegral. Вот её объявление типа:
>fromIntegral :: (Num b, Integral a) => a –> b
Из этой сигнатуры мы видим, что функция принимает целое число >(Integral) и превращает его как более общее число >(Num).
ПРИМЕЧАНИЕ. Необходимо отметить, что функция >fromIntegral имеет несколько ограничений классов в своей сигнатуре. Такое вполне допустимо – несколько ограничений разделяются запятыми и заключаются в круглые скобки.
Это окажется полезно, когда потребуется, чтобы целые числа и числа с плавающей точкой могли «сработаться» вместе. Например, функция вычисления длины >length имеет объявление >length :: [a] –> Int, вместо того чтобы использовать более общий тип >(Num b) => length :: [a] –> b. (Наверное, так сложилось исторически – хотя, по-моему, какова бы ни была причина, это довольно глупо.) В любом случае, если мы попробуем вычислить длину списка и добавить к ней