Почему полиморфные значения не выводятся в 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)