Давайте переименуем:
f :: Integer -> Integer
g :: (Integral n) => n -> n
Мне нравится следовать довольно распространенной практике добавления скобок в раздел ограничений подписи.Это помогает ему выделиться как отличающийся.
f :: Integer -> Integer
прост, он принимает целое число и возвращает другое целое число.
Что касается g :: (Integral n) => n -> n
: Integral
не является самим типом,скорее это больше похоже на предикат.Некоторые типы Integral
, другие нет.Например, Int
- это тип Integral
, Double
- нет.
Здесь n
- это переменная типа , и она может относиться к любому типу.(Integral n)
- это ограничение на переменную типа, которое ограничивает типы, на которые она может ссылаться.Таким образом, вы можете прочитать это так:
g
принимает значение любого типа n
и возвращает значение того же типа ,при условии, что это тип Integral
.
Если мы рассмотрим класс типов Integral
:
ghci> :info Integral
class (Real a, Enum a) => Integral a where
quot :: a -> a -> a
rem :: a -> a -> a
div :: a -> a -> a
mod :: a -> a -> a
quotRem :: a -> a -> (a, a)
divMod :: a -> a -> (a, a)
toInteger :: a -> Integer
{-# MINIMAL quotRem, toInteger #-}
-- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
Мы можем увидеть 3 встроенных типа Integral
.Это означает, что g
одновременно имеет три различных типа, в зависимости от того, как он используется.
g :: Word -> Word
g :: Integer -> Integer
g :: Int -> Int
(И если вы определите другой тип Integral
в будущем, g
будет автоматически работать и с этим)
Вариант Word -> Word
является хорошим примером, поскольку Word
s не может быть отрицательным.g
, когда ему дано положительное число машинного размера, возвращает другое положительное число машинного размера, тогда как f
может вернуть любое целое число, включая отрицательные или гигантские.
Integral
довольно специфичноучебный класс.Это проще увидеть с Num
, который имеет меньше методов и, следовательно, может представлять больше типов:
h :: (Num a) => a -> a
Это также обобщение f
, то есть вы можете использовать h
, где что-тос типом f
ожидается.Но h
также может принимать комплексное число, и тогда оно возвращает комплексное число.
Ключ с такими сигнатурами, как g
и h
, заключается в том, что они работают с несколькими типами, если тип возвращаемого значения совпадает с типом ввода.