Давайте кровавая. Мы должны количественно определить все и дать область количественной оценки. Значения имеют типы; вещи типа уровня имеют виды; виды живут в BOX
.
f1 :: forall (k :: BOX).
(forall (a :: k) (m :: k -> *). m a -> Int)
-> Int
f2 :: (forall (k :: BOX) (a :: k) (m :: k -> *). m a -> Int)
-> Int
Теперь ни в одном примере типа k
количественно явно, так GHC решает, где поставить этот forall (k :: BOX)
, в зависимости от того, где и k
упоминается. Я не совсем уверен, что понимаю или готов отстаивать политику, как указано.
Ørjan дает хороший пример различия на практике. Давайте тоже будем оскорблены. Я напишу /\ (a :: k). t
, чтобы сделать явным абстракцию, соответствующую forall
, и f @ type
для соответствующего приложения. Игра состоит в том, что мы можем выбрать аргументы @
, но мы должны быть готовы мириться с любыми /\
аргументами, которые может выбрать дьявол.
Мы
x :: forall (a :: *) (m :: * -> *). m a -> Int
и, соответственно, может обнаружить, что f1 x
действительно
f1 @ * (/\ (a :: *) (m :: * -> *). x @ a @ m)
Однако, если мы попытаемся дать f2 x
такое же лечение, мы видим
f2 (/\ (k :: BOX) (a :: k) (m :: k -> *). x @ ?m0 @ ?a0)
?m0 :: *
?a0 :: * -> *
where m a = m0 a0
Система типа Haskell рассматривает применение типа как чисто синтаксическое, так что единственный способ, что уравнение можно решить это путем определения функций и определения аргументов
(?m0 :: * -> *) = (m :: k -> *)
(?a0 :: *) = (a :: k)
, но эти уравнения не даже хорошо kinded, потому что k
не волен выбирать: это время /\
не -ed @
-ed.
Как правило, чтобы справиться с этими uber-полиморфными типами, хорошо написать все кванторы, а затем выяснить, как это превращается в вашу игру против дьявола. Кто выбирает то, что и в каком порядке. Перемещение forall
внутри типа аргумента изменяет его выборку и часто может делать разницу между победой и поражением.
Что именно 'k' есть? переменная 'k' любая специальная вещь, как' * '? – Sibi
@Sibi 'k' является переменной вида,' * 'является одним из возможных значений. В типах Haskell типы имеют то же самое, что и значения типов, хотя вам нужны расширения, чтобы использовать больше встроенных фиксированных типов, таких как '*' и '* -> *'. –