Проверка и детерминизм типа Haskell

по словам Haskell 2010 language report, его тип проверки основан на Хиндли-Милнера. Поэтому рассмотрим функцию f такого типа

f :: forall a. [a] -> Int

это может быть функция длины, например. По словам Хиндли-Милнера, f [] проверяет типа Int. Мы можем доказать это, создав экземпляр типа f to [Int] -> Int, типа [] to [Int], то сделать вывод, что приложение ([Int] -> Int) [Int] тип Int.

в этом доказательстве я решил создать экземпляры типов forall a. [a] -> Int и forall a. [a] путем замены Int to a. Я могу заменить Bool вместо этого доказательство тоже работает. Не странно ли в Хиндли-Милнере, что мы можем применить полиморфный тип к другому, не уточняя, какие экземпляры мы используем ?

более конкретно, что в Haskell мешает мне использовать тип a при осуществлении f ? Я мог себе это представить!--1--> функция это равно 18 любой [Bool], и равняется обычной функции длины на всех других типах списков. В этом случае, будет f [] быть 18 или 0 ? В отчете Haskell говорится: "ядро формально не указано", поэтому трудно сказать.

2 ответов


во время вывода типа такие переменные типа действительно могут быть созданы для любого типа. Это можно рассматривать как в высшей степени недетерминированный шаг.

GHC, для чего он стоит, использует внутренний Any тип в таких случаях. Например, компиляция

{-# NOINLINE myLength #-}
myLength :: [a] -> Int
myLength = length

test :: Int
test = myLength []

результаты в следующем ядре:

-- RHS size: {terms: 3, types: 4, coercions: 0}
myLength [InlPrag=NOINLINE] :: forall a_aw2. [a_aw2] -> Int
[GblId, Str=DmdType]
myLength =
  \ (@ a_aP5) -> length @ [] Data.Foldable.$fFoldable[] @ a_aP5

-- RHS size: {terms: 2, types: 6, coercions: 0}
test :: Int
[GblId, Str=DmdType]
test = myLength @ GHC.Prim.Any (GHC.Types.[] @ GHC.Prim.Any)

здесь GHC.Prim.Any возникает в последней строке.

теперь, это действительно не детерминировано? Ну, это включает в себя своего рода недетерминированный шаг" посередине " алгоритма, но конечный результирующий (наиболее общий) тип -Int, и поэтому детерминировано. Не имеет значения, какой тип мы выбираем для a, мы всегда получаем типа Int в конце.

конечно, получение одного и того же типа недостаточно: мы также хотим получить то же самое Int значение. Я предполагаю, что это можно доказать, учитывая

f :: forall a. T a
g :: forall a. T a -> U

затем

g @ V (f @ V) :: U

это одно и то же значение независимо от типа V есть. Это должно быть следствие parametricity применяется к этим полиморфным типам.


чтобы следить за ответом Чи, вот доказательство того, что f [] не может зависеть от экземпляров типа f и []. По теоремам бесплатно (последняя статья здесь), для любых типов a,a' и любую функцию g :: a -> a', потом

f_a = f_a' . map g

здесь f_a является конкретизация f по типу a, например в Haskell

f_Bool :: [Bool] -> Int
f_Bool = f

тогда, если вы оцениваете предыдущее равенство на []_a, это дает f_a []_a = f_a' []_a'. В случай первоначального вопроса,f_Int []_Int = f_Bool []_Bool.

некоторые ссылки на параметричность в Haskell также были бы полезны, потому что Haskell выглядит сильнее, чем полиморфное лямбда-исчисление, описанное в статье Уолдера. В частности, это страница wiki говорит parametricity может быть нарушена в Haskell с помощью .