примеры - полиморфизм haskell




Что такое предикативность? (2)

Главный вопрос этих систем типов: «Можете ли вы заменить полиморфный тип на переменную типа?». Системы предикативного типа - это бессмысленный школьный вопрос, «АБСОЛЮТНО НЕ», в то время как системы нечистоплотного типа - ваш беззаботный приятель, который думает, что это звучит как забавная идея и что может пойти не так?

Теперь, Хаскелл немного обсуждает обсуждение, потому что считает, что полиморфизм должен быть полезным, но невидимым. Поэтому для остальной части этого поста я буду писать на диалекте Haskell, где использование forall не только разрешено, но и требуется. Таким образом, мы можем различать тип a , который является мономорфным типом, который извлекает свое значение из среды ввода, которую мы можем определить позже, и типа forall a. a forall a. a , который является одним из самых сложных полиморфных типов обитателей. Мы также разрешаем делать все в любом месте в любом типе - как мы увидим, GHC ограничивает свой синтаксис своего типа как механизм «с ошибкой», а не как техническое требование.

Предположим, что мы сказали id :: forall a. a -> a компилятора id :: forall a. a -> a id :: forall a. a -> a . Можем ли мы позже попросить использовать id как если бы он имел тип (forall b. b) -> (forall b. b) ? Системы импрессивного типа в порядке, потому что мы можем создать квантификатор в типе id для forall b. b forall b. b , и заменить на все forall b. b forall b. b для всюду в результате. Системы с предикативным типом немного более осторожны: допускаются только мономорфные типы. (Так что если бы у нас был определенный b , мы могли бы написать id :: b -> b .)

Есть аналогичная история о [] :: forall a. [a] [] :: forall a. [a] и (:) :: forall a. a -> [a] -> [a] (:) :: forall a. a -> [a] -> [a] . Хотя ваш беззаботный приятель может быть в порядке с [] :: [forall b. b] [] :: [forall b. b] и (:) :: (forall b. b) -> [forall b. b] -> [forall b. b] (:) :: (forall b. b) -> [forall b. b] -> [forall b. b] (:) :: (forall b. b) -> [forall b. b] -> [forall b. b] , предикативной школьной школы не так много. Фактически, как вы можете видеть только из двух конструкторов списков, нет возможности создавать списки, содержащие полиморфные значения, без создания экземпляра переменной в своих конструкторах до полиморфного значения. Поэтому, хотя тип [forall b. b] [forall b. b] разрешено на нашем диалекте Haskell, это не очень разумно - нет (завершающих) терминов этого типа. Это мотивирует решение GHC жаловаться, если вы даже думаете о таком типе - это способ компилятора сказать вам «не беспокойтесь». *

Ну, что делает школьную школу настолько строгой? Как обычно, ответ заключается в том, чтобы сохранить проверку типов и сделать вывод типа. Типовой вывод для недискриминационных типов справедлив. Проверка типа кажется, что это возможно , но это чертовски сложно, и никто не хочет этого поддерживать.

С другой стороны, некоторые могут возразить, что GHC совершенно доволен некоторыми типами, которые, по-видимому, требуют непротиворечивости:

> :set -Rank2Types
> :t id :: (forall b. b) -> (forall b. b)
{- no complaint, but very chatty -}

Оказывается, что некоторые слегка ограниченные версии непротиворечивости не так уж плохи: в частности, типы проверки типов более высокого ранга (которые позволяют заменять переменные типа полиморфными типами, когда они являются только аргументами для (->) ), относительно просты , Вы теряете тип вывода выше ранга-2, а основные типы выше ранга-1, но иногда более высокие типы рангов - это то, что заказывал доктор.

Впрочем, не знаю об этимологии слова!


* Вы можете задаться вопросом, можете ли вы сделать что-то вроде этого:

data FooTy a where
     FooTm :: FooTy (forall a. a)

Тогда вы получили бы термин ( FooTm ), у которого тип имел что-то полиморфное как аргумент чему-то другому, чем (->) (а именно FooTy ), вам не нужно пересекать FooTy , чтобы сделать это, и поэтому Non (->) материал для полиморфных типов не полезен, потому что вы не можете их сделать ", будет признан недействительным. GHC не позволяет вам писать FooTy , и я признаю, что я не уверен, есть ли принципиальная причина для ограничения или нет.

(Быстрое обновление через несколько лет: есть хорошая, принципиальная причина, по которой FooTm все еще не в порядке. А именно, что GADT реализуются в GHC через равенства типов, поэтому расширенный тип FooTm является фактически FooTm :: forall a. (a ~ forall b. b) => FooTy (forall b. b) . Следовательно, чтобы фактически использовать FooTm , действительно нужно было бы создать экземпляр переменной типа с полиморфным типом. Благодаря Стефани Вейрих, указав это мне.)

У меня довольно приличная интуиция о типах, которые Haskell запрещает как «impredicative»: именно те, где forall появляется в аргументе конструктору типа, отличному от -> . Но что такое предикативность? Что делает его важным? Как это относится к слову «предикат»?


Позвольте мне просто добавить пункт, касающийся проблемы «этимологии», поскольку другой ответ от @DanielWagner охватывает большую часть технической базы.

Предикат на чем-то вроде a -> Bool . Теперь логика предикатов - это та, которая может в каком-то смысле рассуждать о предикатах, поэтому, если у нас есть некоторый предикат P и мы можем говорить о том, что для данного a , P(a) , теперь в «предикатной логике» (например, в первом -разрядная логика), мы можем также сказать ∀a. P(a) ∀a. P(a) . Таким образом, мы можем количественно определять переменные и обсуждать поведение предикатов по таким вещам.

Теперь, в свою очередь, мы говорим, что утверждение является предикативным, если все вещи, к которым применяется предикат, вводятся до него. Поэтому утверждения «основываются» на вещах, которые уже существуют. В свою очередь, утверждение непротиворечиво, если оно может в некотором смысле ссылаться на него своими «бутстрапами».

Таким образом, в случае, например, примера id выше, мы обнаруживаем, что мы можем указать тип id таким образом, что он требует что-то типа id для чего-то другого типа id . Итак, теперь мы можем дать функции тип, в котором квантифицированная переменная (введенная forall a. ) Может «расширяться» так же, как и для всей самой функции!

Следовательно, непредсказуемость вводит возможность определенной «самореференции». Но подождите, можно сказать, не приведет ли такое к противоречию? Ответ: «ну, иногда». В частности, «Система F», которая является полиморфным лямбда-исчислением и существенным «ядром» «основного» языка GHC, допускает форму непроизводительности, которая, тем не менее, имеет два уровня - уровень ценности и уровень типа, который разрешен количественно над собой. В этом двухуровневом расслоении мы можем иметь непротиворечивость, а не противоречие / парадокс.

Хотя обратите внимание, что этот аккуратный трюк очень деликатный и легкий в использовании, добавив больше возможностей, поскольку в этом сборнике статей Олег указывает: http://okmij.org/ftp/Haskell/impredicativity-bites.html





type-theory