Разница в типизации функций в Haskell - PullRequest
0 голосов
/ 08 октября 2018

Я играл с базовыми функциями в Haskell, и меня немного смущает разница между следующими объявлениями типов для функции f

f :: Integer -> Integer

против

f :: Integral n => n -> n

До сих пор я рассматривал оба из них как идентичные, но я уверен, что это не так.В чем разница?

Редактировать: В качестве ответа на первый ответ, я хочу предложить аналогичный пример, который больше соответствует моему вопросу.

Рассмотрим следующие декларации

f :: Num n => n -> n

или

f :: Num -> Num

Какие функции предлагает каждая из них?

Ответы [ 4 ]

0 голосов
/ 09 октября 2018

TL; DR

f :: Integer -> Integer работает для одного типа: Integer.

f :: Integral n => n -> n работает для Integer, Int, Word, Int32, Int64, Word8 и любые произвольные определяемые пользователем типы, которые реализуют класс типов Integral.

Это сокращенная версия.Если вы заботитесь только об одном типе, его проще проверить и эффективнее выполнить, если указать этот тип.Если вы хотите нескольких типов, то, вероятно, вам нужен второй способ.

0 голосов
/ 08 октября 2018

Давайте переименуем:

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, заключается в том, что они работают с несколькими типами, если тип возвращаемого значения совпадает с типом ввода.

0 голосов
/ 08 октября 2018
f :: Integer -> Integer

f - это функция от целых чисел произвольного размера до целых чисел произвольного размера.

f' :: Integral n => n -> n

f' - это полиморфная функция от типа n до типаn.Любой тип n, который является членом класса Integral, разрешен.Примерами типов в Integral являются Integer и Int (целочисленный тип с фиксированной точностью).

f'' :: Num n => n -> n

f'' также является полиморфной функцией, но этовремя для класса Num.Num - это более общий тип чисел, в котором больше членов, чем Integral, но все типы в Integral также содержатся в Num.Для f'' n также может быть Double.

0 голосов
/ 08 октября 2018

Согласно этой ссылке стандартными экземплярами класса Integral являются Integer и Int.Integer является примитивным типом и действует как неограниченное математическое целое число.Итак, учитывая:

f :: Integral n => n -> n

n может быть Int или Integer, или любой другой «пользовательский» тип, который вы определили как instance из Integral.Использование классов типов допускает полиморфизм типов.

f :: Num -> Num НЕ СОБИРАЕТСЯ , поскольку Num является , а не типом.Num имеет вид * -> Constraint и, таким образом, является конструктором типа , тогда как f требует обычного типа или монотипа , который имеет вид *, такойкак Int или Integer (также известный как примитивы системы типов).См. Вики на haskell для краткого ознакомления / точки отсчета о разновидностях .Haskell имеет богатую систему типов с типами более высокого порядка, при правильном использовании это может быть чрезвычайно мощный инструмент, то есть полиморфизм типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...