Penolakan
Ini sangat informal, seperti yang Anda minta.
Tata bahasa
Dalam bahasa yang diketik secara dependen, kami memiliki pengikat di tingkat tipe serta di tingkat nilai:
Term = * | (∀ (Var : Term). Term) | (Term Term) | (λ Var. Term) | Var
Istilah yang diketik dengan baik adalah istilah dengan tipe terlampir, kami akan menulis t ∈ σatau
σ
t
untuk menunjukkan bahwa istilah tersebut tmemiliki tipe σ.
Aturan mengetik
Demi kesederhanaan, kami mengharuskan λ v. t ∈ ∀ (v : σ). τkeduanya λdan ∀mengikat variabel yang sama ( vdalam hal ini).
Aturan:
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)
Jadi, *adalah "tipe semua tipe" (1), ∀bentuk tipe dari tipe (2), abstraksi lambda memiliki tipe pi (3) dan jika vdiperkenalkan oleh ∀ (v : σ). τ, maka vmemiliki tipe σ(5).
"dalam bentuk normal" berarti kami melakukan pengurangan sebanyak mungkin menggunakan aturan pengurangan:
Aturan pengurangan "The"
(λ 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.
Atau dalam sintaks dua dimensi di mana
σ
t
berarti t ∈ σ:
(∀ (v : σ). τ) σ SUBS(τ, v, t)
~>
(λ v . b) t SUBS(b, v, t)
Ini hanya mungkin untuk menerapkan abstraksi lambda ke suatu istilah ketika istilah tersebut memiliki tipe yang sama dengan variabel dalam semua kuantifier terkait. Kemudian kita mengurangi abstraksi lambda dan kuantifikasi forall dengan cara yang sama seperti pada kalkulus lambda murni sebelumnya. Setelah mengurangi bagian level nilai, kami mendapatkan (4) aturan mengetik.
Sebuah contoh
Inilah operator aplikasi fungsi:
∀ (A : *) (B : A -> *) (f : ∀ (y : A). B y) (x : A). B x
λ A B f x . f x
(kita menyingkat ∀ (x : σ). τke σ -> τjika τtidak menyebutkan x)
fpengembalian B yuntuk semua yjenis yang disediakan A. Kami menerapkan funtuk x, yang merupakan dari jenis yang tepat A, dan pengganti yuntuk xdi ∀setelah ., sehingga f x ∈ SUBS(B y, y, x)~> f x ∈ B x.
Sekarang mari kita menyingkat operator aplikasi fungsi appdan menerapkannya sendiri:
∀ (A : *) (B : A -> *). ?
λ A B . app ? ? (app A B)
Saya menempatkan ?persyaratan yang harus kami sediakan. Pertama-tama kami secara eksplisit memperkenalkan dan membuat instantiate Adan B:
∀ (f : ∀ (y : A). B y) (x : A). B x
app A B
Sekarang kita perlu menyatukan apa yang kita miliki
∀ (f : ∀ (y : A). B y) (x : A). B x
yang sama dengan
(∀ (y : A). B y) -> ∀ (x : A). B x
dan apa yang app ? ?diterima
∀ (x : A'). B' x
Ini menghasilkan
A' ~ ∀ (y : A). B y
B' ~ λ _. ∀ (x : A). B x -- B' ignores its argument
(lihat juga Apa itu predicativity? )
Ekspresi kami (setelah diganti nama) menjadi
∀ (A : *) (B : A -> *). ?
λ A B . app (∀ (x : A). B x) (λ _. ∀ (x : A). B x) (app A B)
Karena untuk apa pun A, Bdan f(di mana f ∈ ∀ (y : A). B y)
∀ (y : A). B y
app A B f
kita bisa instantiate Adan Bmendapatkan (untuk apa pun fdengan tipe yang sesuai)
∀ (y : ∀ (x : A). B x). ∀ (x : A). B x
app (∀ (x : A). B x) (λ _. ∀ (x : A). B x) f
dan tipe tanda tangan setara dengan (∀ (x : A). B x) -> ∀ (x : A). B x.
Seluruh ekspresi itu
∀ (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)
Yaitu
∀ (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
yang setelah semua pengurangan pada level nilai memberikan appkembali yang sama .
Jadi sementara ini hanya memerlukan beberapa langkah dalam kalkulus lambda murni untuk mendapatkan appdari app app, dalam pengaturan diketik (dan terutama ketergantungan diketik) kami juga perlu peduli tentang unifikasi dan hal-hal menjadi lebih kompleks bahkan dengan beberapa kenyamanan yang tidak konsisten ( * ∈ *).
Ketik memeriksa
- Jika
tini *kemudian t ∈ *oleh (1)
- Jika
tadalah ∀ (x : σ) τ, σ ∈? *, τ ∈? *(lihat catatan tentang ∈?bawah) kemudian t ∈ *oleh (2)
- Jika
tadalah f x, f ∈ ∀ (v : σ) τuntuk beberapa σdan τ, x ∈? σkemudian t ∈ SUBS(τ, v, x)oleh (4)
- Jika
tvariabel v, vdiperkenalkan ∀ (v : σ). τsaat itu t ∈ σoleh (5)
Ini semua adalah aturan inferensi, tetapi kami tidak dapat melakukan hal yang sama untuk lambdas (inferensi tipe tidak dapat ditentukan untuk tipe dependen). Jadi untuk lambda kita periksa ( t ∈? σ) daripada menyimpulkan:
- Jika
tini λ v. bdan diperiksa terhadap ∀ (v : σ) τ, b ∈? τmakat ∈ ∀ (v : σ) τ
- Jika
tada sesuatu yang lain dan diperiksa, σmaka simpulkan jenis tpenggunaan fungsi di atas dan periksa apakah ituσ
Pemeriksaan kesetaraan untuk tipe mengharuskan mereka dalam bentuk normal, jadi untuk memutuskan apakah tmemiliki tipe, σpertama kita periksa yang σmemiliki tipe *. Jika demikian, maka σdapat dinormalisasi (modulo Girard's paradox) dan menjadi dinormalisasi (maka σmenjadi terbentuk dengan baik oleh (0)). SUBSjuga menormalkan ekspresi untuk dipertahankan (0).
Ini disebut pengecekan jenis dua arah. Dengan itu kita tidak perlu membubuhi keterangan setiap lambda dengan jenis: jika dalam f xjenis fdiketahui, maka xdiperiksa terhadap jenis argumen yang fditerima alih-alih disimpulkan dan dibandingkan untuk kesetaraan (yang juga kurang efisien). Tetapi jika flambda, itu membutuhkan penjelasan jenis eksplisit (penjelasan dihilangkan dalam tata bahasa dan di mana-mana, Anda dapat menambahkan Ann Term Termatau λ' (σ : Term) (v : Var)ke konstruktor).
Juga, lihat Simpler, Lebih Mudah! blogpost.