Ответ 1
tl; dr: В документации говорится, что она говорит, потому что старая реализация скопированных типизированных переменных в GHC была другой, а новая документация (более) подчеркивает контраст между старым поведением и новым поведением. Фактически, скопированные типизированные переменные, которые вы используете с расширением ScopedTypeVariables
на месте, являются просто старыми (жесткими) переменными типа, и это те же переменные типа, которые вы использовали в обычных подписях типа Haskell без определения области охвата (даже если вы не использовали " я понял, что они "жесткие"). Верно, что переменные типа с областью не просто "стоят для типов", но обычные переменные типа без пробелов не просто "стоят для типов".
Более длинный ответ:
Во-первых, отменив проблему переменных типа области, рассмотрите следующее:
pluralize :: [a] -> [a]
pluralize x = x ++ "s"
Если a
, как переменная типа, просто "стояла за тип", это было бы хорошо. GHC определит, что a
обозначает тип Char
, а результирующая сигнатура [Char] → [Char]
будет определена как правильный тип pluralize
, поэтому проблем не возникнет. Фактически, если бы мы вывели тип:
pluralize x = x ++ "s"
в простой старой системе типа Hindley-Milner (HM), это, вероятно, именно то, что произойдет. В качестве промежуточного шага при вводе приложения (++)
средство проверки типов присваивало бы x
типу [a]
для "новой" переменной типа HM a
и pluralize
бы pluralize
типа [a] → [a]
до объединение [a]
с типом "s" :: [Char]
для объединения a
и Char
.
Вместо этого это отклоняется с помощью проверки типа GHC, потому a
в этом типе подпись не является переменной типа типа HM и поэтому не просто обозначает тип. Вместо этого это жесткая (т.е. Заданная пользователем) переменная типа Haskell, и средство проверки типов не позволяет такой переменной объединяться с чем-то другим, кроме самого себя, при определении pluralize
.
Аналогично, отклоняется следующее:
pairlist :: a -> b -> [a]
pairlist x y = [x,y]
хотя, если a
и b
просто стояли для типов, это было бы хорошо (поскольку оно работает для любых a
и b
вида *
при условии, что a
и b
являются a
и тем же типом). Вместо этого он отвергается с помощью проверки типа, потому что две жесткие переменные типа Haskell a
и b
не могут объединяться.
Теперь вы можете попытаться доказать, что проблема не в том, что переменные типа являются "жесткими" и не могут объединяться с конкретными типами (например, Char
) или друг с другом, а скорее, что в сигнатурах типа Haskell имеется неявное количественное выражение, так что подпись для pluralize
на самом деле:
pluralize :: forall a . [a] -> [a]
и поэтому, когда a
определяется "стоять за" Char
, это противоречие с этим forall a
всей количественной оценки, которая вызывает ошибку. Проблема с этим аргументом состоит в том, что оба объяснения на самом деле более или менее эквивалентны. Это связано с тем, что переменные типа Haskell являются жесткими (т.е. Поскольку сигнатуры типов в Haskell неявно определяются количественно), что типы не могут объединяться (т.е. Унификация противоречит количественной оценке). Однако выясняется, что объяснение "жестких типов" ближе к тому, что на самом деле происходит в контролерах типа GHC, чем объяснение "неявного количественного определения". Поэтому сообщения об ошибках, генерируемые вышеуказанными определениями, относятся к неспособности сопоставлять переменные жесткого типа, а не с противоречиями с количественными количественными переменными универсального типа.
Теперь вернемся к вопросу о переменных типа области. В -fscoped-type-variables
времена -fscoped-type-variables
GHC -fscoped-type-variables
было реализовано совершенно по-другому. В частности, для подписей типа шаблона вам было разрешено писать такие вещи, как следующее (взято из документации для GHC 6.0):
f :: [Int] -> Int -> Int
f (xs::[a]) (y::a) = (head xs + y) :: a
и в документации продолжалось:
Подписи типа шаблона в левой части
f
выражают тот факт, чтоxs
должен быть списком вещей некоторого типаa
; и чтоy
должен иметь тот же тип. Подписи типа в выражении(head xs)
[sic] указывает, что это выражение должно иметь один и тот же типa
. Нет требования, чтобы тип, названный "a
", фактически является переменной типа. Действительно, в этом случае тип, названный "a
", являетсяInt
. (Это небольшая либерализация из оригинальных довольно сложных правил, в которых указано, что переменная типа с привязкой к шаблону должна быть количественно определена.)
Далее были приведены некоторые дополнительные примеры использования переменных типа области, таких как:
g (x::a) (y::b) = [x,y] -- a unifies with b
k (x::a) True = ... -- a unifies with Int
k (x::Int) False = ...
В 2006 году Саймон Пейтон-Джонс сделал большую фиксацию ( ac10f840
), чтобы добавить непредсказуемость в систему типов, которая также существенно изменила реализацию переменных типа с лексическим охватом. Текст фиксации содержит подробное объяснение изменения, включая требования к новому дизайну.
Ключевым вариантом выбора было то, что лексические переменные типа теперь называются жесткими (то есть, заданными пользователем полиморфными) переменными типа Haskell, а не скорее похожими на переменные типа HM, которые просто стояли за тип и подлежали унификации.
Это сделало приведенные выше примеры (f
, g
и k
) незаконными, так как переменные типа с переменными в шаблонах теперь ведут себя скорее как обычные жесткие переменные типа.
Soooo... старый дизайн, вероятно, был странным хаком, который делал переменные типа типа более похожими на переменные типа HM и настолько сильно отличался от "обычных" переменных типа Haskell, и новая система приводила их в соответствие с тем, как ведут себя переменные типа непечатаемого типа.
Однако, усложняя ситуацию, ссылка @duplode в комментариях ссылается на предложение частично "отменить" это "ограничение" в контексте подписей в шаблонах. Я считаю, что было бы справедливо сказать, что старый дизайн, который обрабатывал переменные типа с широким диапазоном, как частный случай, уступал новому дизайну, который лучше унифицировал обработку переменных типа scoped и unscoped, и нет желания возвращаться к старой реализации. Однако новая, более простая реализация имела побочный эффект от излишнего ограничения для сигнатур шаблонов, которые, возможно, следует рассматривать как частный случай, когда допустимы нежесткие переменные типа.