Как haskell определяет порядок переменных типа в неявных поисках? - PullRequest
0 голосов
/ 20 октября 2018

Итак, я только недавно узнал и начал использовать TypeApplications, и мне было интересно, как мы вообще можем знать, какие переменные типа мы назначаем. В документации по TypeApplications я обнаружил упоминания:

Какой порядок используется для создания экземпляров переменных типа?

Порядок типов слева направопеременные, появляющиеся в файлахЭто наиболее логичный порядок, который возникает, когда создание экземпляра выполняется на уровне переменной типа.Вложенные поля работают немного по-другому, но в одном месте пакета с несколькими переменными имеет место порядок слева направо.(См. Ниже о вложенных запросах).

Однако я не нашел упоминания о том, как определяется порядок переменных типа в неявных запросах.Я попытался просмотреть различные примеры с -fprint-explicit-foralls, чтобы увидеть, был ли простой шаблон, но я получаю разные результаты в разных версиях ghci.: /

В версии 8.0.2 ghci я получаю:

> :t (,,)
(,,) :: forall {c} {b} {a}. a -> b -> c -> (a, b, c)

, а в версии 8.4.3 ghci я получаю:

> :t (,,)
(,,) :: forall {a} {b} {c}. a -> b -> c -> (a, b, c)

Затем сноваможет быть, это просто ошибка в том, как печатались сообщения в 8.0.2, потому что в противном случае приложения типов, похоже, выполняются справа налево с переменными forall, в отличие от того, что говорится в документации:

> :t (,,) @Bool
(,,) @Bool :: forall {c} {b}. Bool -> b -> c -> (Bool, b, c)

Значит, переменные типа помещаются в неявные поля всегда в том порядке, в котором они появляются слева направо в теле типа (включая ограничения)?

1 Ответ

0 голосов
/ 20 октября 2018

TL; DR: порядок переменных типа определяется первым столкновением слева направо.В случае сомнений используйте :type +v.

Не используйте :type

Использование :type вводит в заблуждение здесь.:type выводит тип целого выражения.Поэтому, когда вы пишете :t (,), средство проверки типов просматривает

(,) :: forall a b. a -> b -> (a, b)

и создает экземпляры всех файлов с новыми переменными типа

(,) :: a1 -> b1 -> (a1, b1)

, что необходимо, если вы примените (,),Увы, вы этого не сделаете, поэтому вывод типа почти сделан, и он обобщает все свободные переменные, и вы получаете, например,

(,) :: forall {b} {a}. a -> b -> (a, b)

Этот шаг не дает никаких гарантий относительно порядка свободной переменной, и компилятор может свободно меняться.

Также обратите внимание, что он пишет forall {a} вместо forall a, что означает, что вы не можете использовать приложение видимого типа здесь.

Use :type +v

Но, конечно, вы можете использовать (,) @Bool - но здесь средство проверки типов обрабатывает первое выражение по-разному и не выполняет этот шаг создания экземпляра / обобщения.

И вы можете получить этоповедение в GHCi также - передача +v в :type:

:type +v (,)
(,) :: forall a b. a -> b -> (a, b)
:type +v (,) @Bool
(,) @Bool :: forall b. Bool -> b -> (Bool, b)

Смотрите, нет {…} вокруг переменных типа!

Где этот порядоквзято из?

В разделе руководства пользователя GHC по приложению видимого типа указано:

Если сигнатура типа идентификатора не содержит явного запроса, типпеременные аргументы отображаются слева направопорядок, в котором переменные появляются в типе.Таким образом, переменные типа foo :: Monad m => ab -> m (ac) будут иметь порядок m, a, b, c.

Это относится только к вещам, которые имеют явныйТип подписи.Не существует гарантированного порядка для переменных в выведенных типах, но вы также не можете использовать выражения с выведенными типами с VisibleTypeApplication.

...