Этот синтаксис, хотя и может показаться сложным, на самом деле довольно прост. Основная идея исходит из формальной логики: все выражение является следствием, причем верхняя половина - это предположения, а нижняя - результат. То есть, если вы знаете, что верхние выражения верны, вы можете сделать вывод, что нижние выражения также верны.
Символы
Следует также помнить, что некоторые буквы имеют традиционное значение; в частности, Γ представляет «контекст», в котором вы находитесь, то есть типы других вещей, которые вы видели. Итак, что-то вроде Γ ⊢ ...
означает «выражение, ...
когда вы знаете типы каждого выражения в Γ
.
⊢
Символ по существу означает , что вы можете что - то доказать. Так Γ ⊢ ...
же как и утверждение «Я могу доказать ...
в контексте Γ
. Эти утверждения также называются суждениями типа».
Следует иметь в виду еще одну вещь: в математике, как и в ML и Scala, x : σ
подразумевается, что у x
нее есть тип σ
. Вы можете прочитать это так же, как у Хаскелла x :: σ
.
Что означает каждое правило
Итак, зная это, первое выражение становится легко понять: если мы знаем, что x : σ ∈ Γ
(то есть, x
имеет некоторый тип σ
в некотором контексте Γ
), то мы знаем, что Γ ⊢ x : σ
(то есть Γ
, x
имеет тип σ
). Так что на самом деле, это не говорит вам ничего супер-интересного; это просто говорит вам, как использовать ваш контекст.
Другие правила также просты. Например, взять [App]
. Это правило имеет два условия: e₀
это функция от некоторого типа τ
к некоторому типу τ'
и e₁
значение типа τ
. Теперь вы знаете, какой тип вы получите, обратившись e₀
к e₁
! Надеюсь, это не удивительно :).
Следующее правило имеет еще один новый синтаксис. В частности, Γ, x : τ
просто означает контекст Γ
и суждение x : τ
. Итак, если мы знаем, что переменная x
имеет тип, τ
а выражение e
имеет тип τ'
, мы также знаем тип функции, которая принимает x
и возвращает e
. Это просто говорит нам, что делать, если мы выяснили, какой тип принимает функция и какой тип она возвращает, поэтому это тоже не должно удивлять.
Следующий просто говорит вам, как обрабатывать let
заявления. Если вы знаете, что какое-то выражение e₁
имеет тип τ
до тех пор, пока оно x
имеет тип σ
, то let
выражение, которое локально связывается x
со значением типа, σ
будет e₁
иметь тип τ
. На самом деле, это просто говорит вам, что оператор let по сути позволяет вам расширять контекст с помощью новой привязки, что и let
делает!
[Inst]
Правило касается суб-печати. Это говорит о том, что если у вас есть значение типа σ'
и оно является подтипом σ
( ⊑
представляет отношение частичного упорядочения), то это выражение также имеет тип σ
.
Последнее правило касается обобщающих типов. Небольшое отступление: свободная переменная - это переменная, которая не вводится оператором let или лямбда-выражением внутри некоторого выражения; это выражение теперь зависит от значения свободной переменной из ее контекста. Правило гласит, что если есть некоторая переменная, α
которая не является «свободной» ни в чем в вашем контексте, то можно с уверенностью сказать, что любое выражение, тип которого вы знаете, e : σ
будет иметь этот тип для любого значения α
.
Как пользоваться правилами
Итак, теперь, когда вы понимаете символы, что вы делаете с этими правилами? Ну, вы можете использовать эти правила, чтобы выяснить тип различных значений. Чтобы сделать это, посмотрите на свое выражение (скажем f x y
) и найдите правило, в котором есть заключение (нижняя часть), соответствующее вашему утверждению. Давайте назовем то, что вы пытаетесь найти своей «целью». В этом случае вы бы посмотрели на правило, которое заканчивается e₀ e₁
. Когда вы нашли это, теперь вы должны найти правила, доказывающие все, что находится выше линии этого правила. Эти вещи, как правило, соответствуют типам подвыражений, так что вы по существу повторяете части выражения. Вы просто делаете это, пока не закончите свое дерево доказательств, которое дает вам подтверждение типа вашего выражения.
Таким образом, все эти правила указывают точно - и в обычной математически педантичной детали: P - как выяснить типы выражений.
Теперь, это должно звучать знакомо, если вы когда-либо использовали Пролог - вы по сути вычисляете дерево доказательств, как человеческий интерпретатор Пролога. Есть причина, по которой Пролог называют «логическим программированием»! Это также важно, так как я впервые познакомился с алгоритмом вывода HM, реализовав его в Прологе. Это на самом деле удивительно просто и проясняет то, что происходит. Вы должны обязательно попробовать это.
Примечание: я, вероятно, допустил некоторые ошибки в этом объяснении и был бы рад, если бы кто-то на них указал. На самом деле я расскажу об этом в классе через пару недель, поэтому я буду более уверенным в этом: P.