Ta składnia, choć może wydawać się skomplikowana, jest w rzeczywistości dość prosta. Podstawowa idea pochodzi z logiki formalnej: całe wyrażenie jest implikacją, a górna połowa to założenia, a dolna połowa to wynik. Oznacza to, że jeśli wiesz, że górne wyrażenia są prawdziwe, możesz stwierdzić, że dolne wyrażenia również są prawdziwe.
Symbolika
Należy także pamiętać, że niektóre litery mają tradycyjne znaczenie; w szczególności Γ oznacza „kontekst”, w którym się znajdujesz - to znaczy, jakie są rodzaje innych rzeczy, które widziałeś. Więc coś w stylu Γ ⊢ ...
oznacza „wyrażenie, ...
gdy znasz typy każdego wyrażenia w Γ
.
Ten ⊢
symbol oznacza, że możesz coś udowodnić. Podobnie Γ ⊢ ...
jest ze stwierdzeniem: „Mogę udowodnić ...
w kontekście Γ
. Te stwierdzenia nazywane są również osądami typu.
Kolejna rzecz, o której należy pamiętać: w matematyce, podobnie jak ML i Scala, x : σ
oznacza, że x
ma typ σ
. Możesz przeczytać tak jak u Haskella x :: σ
.
Co oznacza każda reguła
Tak więc, wiedząc o tym, pierwszy wyraz staje się łatwe do zrozumienia: jeśli wiemy, że x : σ ∈ Γ
(to jest, x
ma jakiś typ σ
w pewnym kontekście Γ
), to wiemy, że Γ ⊢ x : σ
(to jest w Γ
, x
ma typ σ
). Tak naprawdę, to nie mówi ci niczego super interesującego; po prostu mówi ci, jak korzystać z kontekstu.
Inne zasady są również proste. Na przykład weź [App]
. Ta reguła ma dwa warunki: e₀
jest funkcją od pewnego typu τ
do jakiegoś typu τ'
i e₁
jest wartością typu τ
. Teraz wiesz, co wpisać dostaniesz stosując e₀
się e₁
! Mam nadzieję, że to nie jest niespodzianka :).
Następna reguła ma jeszcze nową składnię. W szczególności Γ, x : τ
oznacza tylko kontekst Γ
i osąd x : τ
. Tak więc, jeśli wiemy, że zmienna x
ma typ, τ
a wyrażenie e
ma typ τ'
, znamy również typ funkcji, która przyjmuje x
i zwraca e
. To po prostu mówi nam, co zrobić, jeśli ustaliliśmy, jaki typ funkcja przyjmuje i jaki typ zwraca, więc nie powinno to być zaskakujące.
Następny mówi po prostu, jak obsługiwać let
instrukcje. Jeśli wiesz, że jakieś wyrażenie e₁
ma typ τ
tak długo, jak x
ma typ σ
, wówczas let
wyrażenie, które lokalnie wiąże x
się z wartością typu, σ
sprawi, że będzie e₁
miało typ τ
. Naprawdę, to po prostu mówi ci, że instrukcja let pozwala zasadniczo rozszerzyć kontekst o nowe powiązanie - co dokładnie let
działa!
[Inst]
Zasada dotyczy sub-pisania. Mówi, że jeśli masz wartość typu σ'
i jest ona podtypem σ
( ⊑
reprezentuje relację częściowego uporządkowania), to wyrażenie jest również typu σ
.
Ostatnia zasada dotyczy typów uogólnionych. Krótko na bok: wolna zmienna jest zmienną, która nie jest wprowadzana przez wyrażenie let ani lambda wewnątrz jakiegoś wyrażenia; Wyrażenie to zależy teraz od wartości zmiennej wolnej od kontekstu. Reguła mówi, że jeśli istnieje jakaś zmienna, α
która nie jest „wolna” w jakimkolwiek kontekście, to można powiedzieć, że każde wyrażenie, którego typ znasz e : σ
będzie miał ten typ dla dowolnej wartości α
.
Jak korzystać z reguł
Teraz, kiedy rozumiesz symbole, co robisz z tymi zasadami? Cóż, możesz użyć tych reguł, aby dowiedzieć się, jakie są różne wartości. Aby to zrobić, spójrz na swoje wyrażenie (powiedzmy f x y
) i znajdź regułę, która ma konkluzję (dolna część) pasującą do twojego wyrażenia. Nazwijmy rzecz, którą próbujesz znaleźć, „celem”. W takim przypadku spójrz na regułę, która kończy się na e₀ e₁
. Kiedy to znajdziesz, musisz znaleźć reguły potwierdzające wszystko powyżej linii tej reguły. Te rzeczy zasadniczo odpowiadają typom podwyrażeń, więc zasadniczo rekurencyjnie powtarzasz niektóre części wyrażenia. Po prostu rób to, dopóki nie skończysz drzewa dowodu, co daje dowód rodzaju wyrażenia.
Tak więc wszystkie te reguły określają dokładnie - i w zwykłym matematycznie pedantycznym szczególe: P - jak rozróżnić rodzaje wyrażeń.
Teraz powinno to brzmieć znajomo, jeśli kiedykolwiek używałeś Prologa - w zasadzie obliczasz drzewo dowodu jak ludzki tłumacz Prolog. Istnieje powód, dla którego Prolog nazywa się „programowaniem logicznym”! Jest to również ważne, ponieważ pierwszy sposób, w jaki zapoznałem się z algorytmem wnioskowania HM, to wdrożenie go w Prologu. Jest to w rzeczywistości zaskakująco proste i wyjaśnia, co się dzieje. Z pewnością powinieneś spróbować.
Uwaga: Prawdopodobnie popełniłem kilka błędów w tym wyjaśnieniu i bardzo by mi się podobało, gdyby ktoś je wskazał. Za kilka tygodni zajmę się tym na zajęciach, więc będę bardziej pewny niż: P.