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ữ tcó 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 ( vtrong 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ì vcó 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)
flợi nhuận B yđối với bất kỳ cung cấp ycác loại A. Chúng tôi áp dụng fđể x, đó là của đúng loại A, và thay thế ycho xtrong ∀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 appvà á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 Avà 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, Bvà f(ở đâu f ∈ ∀ (y : A). B y)
∀ (y : A). B y
app A B f
chúng ta có thể khởi tạo Avà Bnhận (đối với bất kỳ loại nào fphù 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ẽ apptrả 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 apptừ 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
tlà *sau đó t ∈ *bằng cách (1)
- Nếu
tlà ∀ (x : σ) τ, σ ∈? *, τ ∈? *(xem lưu ý về ∈?bên dưới) sau đó t ∈ *bởi (2)
- Nếu
tlà f x, f ∈ ∀ (v : σ) τđối với một số σvà τ, x ∈? σsau đó t ∈ SUBS(τ, v, x)(4)
- Nếu
tlà 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. bvà kiểm tra lại ∀ (v : σ) τ, b ∈? τthìt ∈ ∀ (v : σ) τ
- Nếu
tlà một cái gì đó khác và được kiểm tra lại σthì hãy suy ra kiểu tsử 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 tcó 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)). SUBScũ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 xloại fđược biết, thì xsẽ được kiểm tra đối với loại đối số fnhậ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 flà 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 Termhoặ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.