Проверка и детерминизм типа 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 с помощью .