Почему полиморфные значения не выводятся в Haskell? - PullRequest
21 голосов
/ 14 ноября 2010

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

*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 ]

23 голосов
/ 14 ноября 2010

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

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

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

x = longCalculation 42

main = print $ x + x
19 голосов
/ 15 ноября 2010

Чтобы немного расширить ответ 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)
...