Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

x = longCalculation 42

main = print $ x + x

Ответ 2

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

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

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

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

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

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

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

default (Int, Rational)