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 t
memiliki tipe σ
.
Aturan mengetik
Demi kesederhanaan, kami mengharuskan λ v. t ∈ ∀ (v : σ). τ
keduanya λ
dan ∀
mengikat variabel yang sama ( v
dalam 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 v
diperkenalkan oleh ∀ (v : σ). τ
, maka v
memiliki 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
)
f
pengembalian B y
untuk semua y
jenis yang disediakan A
. Kami menerapkan f
untuk x
, yang merupakan dari jenis yang tepat A
, dan pengganti y
untuk x
di ∀
setelah .
, sehingga f x ∈ SUBS(B y, y, x)
~> f x ∈ B x
.
Sekarang mari kita menyingkat operator aplikasi fungsi app
dan 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 A
dan 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
, B
dan f
(di mana f ∈ ∀ (y : A). B y
)
∀ (y : A). B y
app A B f
kita bisa instantiate A
dan B
mendapatkan (untuk apa pun f
dengan 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 app
kembali yang sama .
Jadi sementara ini hanya memerlukan beberapa langkah dalam kalkulus lambda murni untuk mendapatkan app
dari 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
t
ini *
kemudian t ∈ *
oleh (1)
- Jika
t
adalah ∀ (x : σ) τ
, σ ∈? *
, τ ∈? *
(lihat catatan tentang ∈?
bawah) kemudian t ∈ *
oleh (2)
- Jika
t
adalah f x
, f ∈ ∀ (v : σ) τ
untuk beberapa σ
dan τ
, x ∈? σ
kemudian t ∈ SUBS(τ, v, x)
oleh (4)
- Jika
t
variabel v
, v
diperkenalkan ∀ (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
t
ini λ v. b
dan diperiksa terhadap ∀ (v : σ) τ
, b ∈? τ
makat ∈ ∀ (v : σ) τ
- Jika
t
ada sesuatu yang lain dan diperiksa, σ
maka simpulkan jenis t
penggunaan fungsi di atas dan periksa apakah ituσ
Pemeriksaan kesetaraan untuk tipe mengharuskan mereka dalam bentuk normal, jadi untuk memutuskan apakah t
memiliki 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)). SUBS
juga 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 x
jenis f
diketahui, maka x
diperiksa terhadap jenis argumen yang f
diterima alih-alih disimpulkan dan dibandingkan untuk kesetaraan (yang juga kurang efisien). Tetapi jika f
lambda, itu membutuhkan penjelasan jenis eksplisit (penjelasan dihilangkan dalam tata bahasa dan di mana-mana, Anda dapat menambahkan Ann Term Term
atau λ' (σ : Term) (v : Var)
ke konstruktor).
Juga, lihat Simpler, Lebih Mudah! blogpost.