Почему полиморфные значения не выводятся в Haskell?

Числовые литералы имеют полиморфный тип:

*Main> :t 3
3 :: (Num t) => t

Но если я связываю переменную с таким литералом, полиморфизм теряется:

x = 3
...
*Main> :t x
x :: Integer

Если я определяю функцию, с другой стороны, она, конечно, полиморфна:

f x = 3
...
*Main> :t f
f :: (Num t1) => t -> t1

Я мог бы предоставить подпись типа, чтобы обеспечить x остается полиморфным:

x :: Num a => a
x = 3
...
*Main> :t x
x :: (Num a) => a

Но зачем это нужно? Почему не выводится полиморфный тип?

2 ответа

Решение

Это ограничение мономорфизма, которое говорит, что все значения, которые определены без параметров и не имеют явной аннотации типа, должны иметь мономорфный тип. Это ограничение можно отключить в ghc и ghci, используя -XNoMonomorphismRestriction,

Причина ограничения заключается в том, что без этого ограничения long_calculation 42 будет оцениваться дважды, в то время как большинство людей, вероятно, ожидают / хотят, чтобы оно оценивалось только один раз:

longCalculation :: Num a => a -> a
longCalculation = ...

x = longCalculation 42

main = print $ x + x

Чтобы немного расширить ответ sepp2k: если вы попытаетесь скомпилировать следующее (или загрузить его в GHCi), вы получите ошибку:

import Data.List (sort)
f = head . sort

Это нарушение ограничения мономорфизма, потому что у нас есть ограничение класса (введено sort) но без явных аргументов: нам (несколько загадочно) сказали, что у нас есть Ambiguous type variable в ограничении Ord a,

Ваш пример (let x = 3) имеет аналогично неоднозначную переменную типа, но она не выдает такую ​​же ошибку, потому что она сохранена по правилам "по умолчанию" Haskell:

Любые переменные мономорфного типа, которые остаются, когда вывод типа для всего модуля завершен, считаются неоднозначными и разрешаются к определенным типам с использованием правил по умолчанию (раздел 4.3.4).

См. Этот ответ для получения дополнительной информации о правилах по умолчанию - важно то, что они работают только для определенных числовых классов, поэтому x = 3 хорошо в то время как f = sort нет.

В качестве примечания: если вы предпочитаете x = 3 в конечном итоге Int вместо Integer, а также y = 3.0 быть Rational вместо DoubleВы можете использовать "декларацию по умолчанию", чтобы переопределить правила по умолчанию:

default (Int, Rational)
Другие вопросы по тегам