22

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

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

+0

Не имеет значения? (Я действительно не знаю, хотя подозреваю, что нет) – delnan

+3

Это действительно имеет значение; Я хочу, чтобы тип оставался как можно более общим. –

+0

Приходите еще? Независимо от того, является ли 'x'' Integer' или 'Num a => a', вы можете передать его любой функции, которая ожидает' Num'. Функции должны быть общими, значения нет. – delnan

ответ

24

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

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

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

x = longCalculation 42 

main = print $ x + x 
+0

Ах да, страшное ограничение мономорфизма ... Я слышал об этом, но никогда не смотрел, что именно. Благодаря! –

+0

Если бы я добавил явные сигнатуры типа к этому, будет ли он по-прежнему оцениваться дважды, с расширением ограничения мономорфизма? –

+0

@JustinL Если у него полиморфный тип, он будет оцениваться дважды. Если он имеет мономорфный тип, он не будет. Ограничение мономорфизма влияет только на то, получит ли он мономорфный или полиморфный тип без аннотаций. Если вы добавляете аннотации, ограничение мономорфизма не имеет значения. – sepp2k

20

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

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

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

Вашего примера (let x = 3) имеет переменный так же неоднозначный тип, но он не дает ту же ошибку, потому что она спасена Haskell's "defaulting" rules:

Any monomorphic type variables that remain when type inference for an entire module is complete, are considered ambiguous, and are resolved to particular types using the defaulting rules (Section 4.3.4).

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

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

default (Int, Rational) 
+0

+1, отлично дополнение к ответе sepp2k –

+1

Когда я помещаю 'f = head. sort' в файл и пытаюсь загрузить его, я получаю сообщение об ошибке, но когда я набираю' let f = head. sort' в GHCi, я не получаю ошибки, и результирующая привязка имеет этот тип: 'f :: [()] ->()'. Что случилось с этим? –

+2

@pelotom: Это из-за [расширенных правил по умолчанию GHCi] (http://www.haskell.org/ GHC/документы/6.12.2/html/users_guide/интерактивно-evaluation.html # продлен по умолчанию-правила). –

Смежные вопросы