Khước từ
Điều này rất không chính thức, như bạn yêu cầu.
Ngữ pháp
Trong một ngôn ngữ được gõ phụ thuộc, chúng ta có một chất kết dính ở cấp độ loại cũng như ở cấp độ giá trị:
Term = * | (∀ (Var : Term). Term) | (Term Term) | (λ Var. Term) | Var
Thuật ngữ đánh máy tốt là một thuật ngữ có loại đính kèm, chúng tôi sẽ viết t ∈ σ
hoặc
σ
t
để chỉ ra rằng thuật ngữ t
có loại σ
.
Quy tắc đánh máy
Để đơn giản, chúng tôi yêu cầu λ v. t ∈ ∀ (v : σ). τ
cả hai λ
và ∀
liên kết cùng một biến ( v
trong trường hợp này).
Quy tắc:
t ∈ σ is well-formed if σ ∈ * and t is in normal form (0)
* ∈ * (1)
∀ (v : σ). τ ∈ * -: σ ∈ *, τ ∈ * (2)
λ v. t ∈ ∀ (v : σ). τ -: t ∈ τ (3)
f x ∈ SUBS(τ, v, x) -: f ∈ ∀ (v : σ). τ, x ∈ σ (4)
v ∈ σ -: v was introduced by ∀ (v : σ). τ (5)
Do đó, *
là "loại của tất cả các loại" (1), ∀
các dạng từ loại (2), trừu tượng lambda có loại pi (3) và nếu v
được giới thiệu bởi ∀ (v : σ). τ
, thì v
có loại σ
(5).
"Ở dạng bình thường" có nghĩa là chúng tôi thực hiện càng nhiều lần giảm càng tốt bằng cách sử dụng quy tắc giảm:
"Quy tắc giảm"
(λ v. b ∈ ∀ (v : σ). τ) (t ∈ σ) ~> SUBS(b, v, t) ∈ SUBS(τ, v, t)
where `SUBS` replaces all occurrences of `v`
by `t` in `τ` and `b`, avoiding name capture.
Hoặc theo cú pháp hai chiều trong đó
σ
t
có nghĩa là t ∈ σ
:
(∀ (v : σ). τ) σ SUBS(τ, v, t)
~>
(λ v . b) t SUBS(b, v, t)
Chỉ có thể áp dụng trừu tượng lambda cho một thuật ngữ khi thuật ngữ này có cùng loại với biến trong bộ định lượng forall liên quan. Sau đó, chúng tôi giảm cả trừu tượng lambda và định lượng forall theo cùng một cách như trong phép tính lambda thuần túy trước đây. Sau khi trừ phần cấp giá trị, chúng ta có quy tắc gõ (4).
Một ví dụ
Đây là toán tử ứng dụng chức năng:
∀ (A : *) (B : A -> *) (f : ∀ (y : A). B y) (x : A). B x
λ A B f x . f x
(chúng tôi viết tắt ∀ (x : σ). τ
để σ -> τ
nếu τ
không đề cập đến x
)
f
lợi nhuận B y
đối với bất kỳ cung cấp y
các loại A
. Chúng tôi áp dụng f
để x
, đó là của đúng loại A
, và thay thế y
cho x
trong ∀
sau .
, do đó f x ∈ SUBS(B y, y, x)
~> f x ∈ B x
.
Bây giờ chúng ta hãy viết tắt toán tử ứng dụng hàm app
và áp dụng nó cho chính nó:
∀ (A : *) (B : A -> *). ?
λ A B . app ? ? (app A B)
Tôi đặt ?
cho các điều khoản mà chúng tôi cần phải cung cấp. Đầu tiên chúng tôi giới thiệu rõ ràng và khởi tạo A
và B
:
∀ (f : ∀ (y : A). B y) (x : A). B x
app A B
Bây giờ chúng ta cần thống nhất những gì chúng ta có
∀ (f : ∀ (y : A). B y) (x : A). B x
giống như
(∀ (y : A). B y) -> ∀ (x : A). B x
và những gì app ? ?
nhận được
∀ (x : A'). B' x
Kết quả này trong
A' ~ ∀ (y : A). B y
B' ~ λ _. ∀ (x : A). B x -- B' ignores its argument
(xem thêm Dự đoán là gì? )
Biểu thức của chúng tôi (sau khi đổi tên) trở thành
∀ (A : *) (B : A -> *). ?
λ A B . app (∀ (x : A). B x) (λ _. ∀ (x : A). B x) (app A B)
Vì đối với bất kỳ A
, B
và f
(ở đâu f ∈ ∀ (y : A). B y
)
∀ (y : A). B y
app A B f
chúng ta có thể khởi tạo A
và B
nhận (đối với bất kỳ loại nào f
phù hợp)
∀ (y : ∀ (x : A). B x). ∀ (x : A). B x
app (∀ (x : A). B x) (λ _. ∀ (x : A). B x) f
và chữ ký loại tương đương với (∀ (x : A). B x) -> ∀ (x : A). B x
.
Toàn bộ biểu thức là
∀ (A : *) (B : A -> *). (∀ (x : A). B x) -> ∀ (x : A). B x
λ A B . app (∀ (x : A). B x) (λ _. ∀ (x : A). B x) (app A B)
I E
∀ (A : *) (B : A -> *) (f : ∀ (x : A). B x) (x : A). B x
λ A B f x .
app (∀ (x : A). B x) (λ _. ∀ (x : A). B x) (app A B) f x
mà sau khi tất cả các mức giảm ở mức giá trị sẽ app
trả lại như cũ .
Vì vậy, trong khi nó đòi hỏi chỉ là một vài bước trong giải tích lambda tinh khiết để có được app
từ app app
, trong một khung cảnh đánh máy (và đặc biệt là một lệ thuộc gõ), chúng tôi cũng cần phải quan tâm đến thống nhất và mọi thứ trở nên phức tạp hơn ngay cả với một số tiện không đồng nhất ( * ∈ *
).
Kiểm tra loại
- Nếu
t
là *
sau đó t ∈ *
bằng cách (1)
- Nếu
t
là ∀ (x : σ) τ
, σ ∈? *
, τ ∈? *
(xem lưu ý về ∈?
bên dưới) sau đó t ∈ *
bởi (2)
- Nếu
t
là f x
, f ∈ ∀ (v : σ) τ
đối với một số σ
và τ
, x ∈? σ
sau đó t ∈ SUBS(τ, v, x)
(4)
- Nếu
t
là một biến v
, v
được giới thiệu bởi ∀ (v : σ). τ
sau đó t ∈ σ
bởi (5)
Tất cả đều là quy tắc suy luận, nhưng chúng ta không thể làm tương tự cho lambdas (suy luận kiểu là không thể áp dụng cho các loại phụ thuộc). Vì vậy, đối với lambdas, chúng tôi kiểm tra ( t ∈? σ
) thay vì suy ra:
- Nếu
t
được λ v. b
và kiểm tra lại ∀ (v : σ) τ
, b ∈? τ
thìt ∈ ∀ (v : σ) τ
- Nếu
t
là một cái gì đó khác và được kiểm tra lại σ
thì hãy suy ra kiểu t
sử dụng hàm trên và kiểm tra xem nó có phải làσ
Kiểm tra sự bằng nhau cho các loại yêu cầu chúng phải ở dạng bình thường, vì vậy để quyết định xem t
có loại nào σ
trước tiên chúng ta kiểm tra σ
loại đó không *
. Nếu vậy, thì σ
có thể bình thường hóa (nghịch lý của modulo Girard) và nó được chuẩn hóa (do đó σ
trở nên được hình thành tốt bởi (0)). SUBS
cũng bình thường hóa các biểu thức để bảo toàn (0).
Điều này được gọi là kiểm tra loại hai chiều. Với nó, chúng ta không cần chú thích mỗi lambda với một loại: nếu trong f x
loại f
được biết, thì x
sẽ được kiểm tra đối với loại đối số f
nhận được thay vì được suy ra và so sánh cho sự bình đẳng (cũng kém hiệu quả hơn). Nhưng nếu f
là lambda, nó yêu cầu chú thích loại rõ ràng (chú thích được bỏ qua trong ngữ pháp và ở mọi nơi, bạn có thể thêm Ann Term Term
hoặc λ' (σ : Term) (v : Var)
vào các hàm tạo).
Ngoài ra, hãy xem đơn giản hơn, dễ dàng hơn! bài viết trên blog.