Teori tipe dependen dan fungsi tipe 'arbitrer'
Jawaban pertama saya untuk pertanyaan ini adalah tinggi pada konsep dan rendah pada rincian dan tercermin pada pertanyaan, 'apa yang terjadi?'; jawaban ini akan sama tetapi terfokus pada subquestion, 'bisakah kita mendapatkan fungsi tipe sewenang-wenang?'.
Salah satu ekstensi untuk operasi aljabar jumlah dan produk adalah apa yang disebut 'operator besar', yang mewakili jumlah dan produk dari suatu urutan (atau lebih umum, jumlah dan produk dari suatu fungsi melalui suatu domain) biasanya ditulis Σ
dan Π
masing - masing. Lihat Notasi Sigma .
Jadi jumlahnya
a₀ + a₁X + a₂X² + ...
mungkin ditulis
Σ[i ∈ ℕ]aᵢXⁱ
di mana a
ada beberapa urutan bilangan real, misalnya. Produk akan diwakili serupa dengan Π
bukan Σ
.
Ketika Anda melihat dari jauh, ungkapan semacam ini sangat mirip dengan fungsi 'arbitrer' X
; kami terbatas tentu saja untuk seri ekspresif, dan fungsi analitik yang terkait. Apakah ini kandidat untuk representasi dalam teori tipe? Pastinya!
Kelas teori tipe yang memiliki representasi langsung dari ekspresi ini adalah kelas teori tipe 'dependen': teori dengan tipe dependen. Secara alami kami memiliki istilah yang tergantung pada istilah, dan dalam bahasa seperti Haskell dengan fungsi tipe dan tipe kuantifikasi, istilah dan tipe tergantung pada tipe. Dalam pengaturan dependen, kami juga memiliki jenis tergantung pada istilah. Haskell bukanlah bahasa yang diketik secara dependen, meskipun banyak fitur tipe dependen dapat disimulasikan dengan sedikit menyiksa bahasa .
Kari-Howard dan tipe tergantung
'Curry-Howard isomorphism' memulai kehidupan sebagai pengamatan bahwa istilah dan aturan penilaian tipe kalkulus lambda yang diketikkan sesuai dengan deduksi alami (seperti yang diformulasikan oleh Gentzen) diterapkan pada logika proposisional intuitionistic, dengan tipe yang menggantikan proposisi. , dan persyaratan menggantikan bukti, meskipun keduanya secara independen ditemukan / ditemukan. Sejak itu, ia telah menjadi sumber inspirasi bagi para ahli teori tipe. Salah satu hal yang paling jelas untuk dipertimbangkan adalah apakah, dan bagaimana, korespondensi ini untuk logika proposisional dapat diperluas ke predikat atau logika tingkat tinggi. Teori tipe dependen awalnya muncul dari jalan eksplorasi ini.
Untuk pengantar isomorfisma Curry-Howard untuk kalkulus lambda yang diketik sederhana, lihat di sini . Sebagai contoh, jika kita ingin membuktikan A ∧ B
kita harus membuktikan A
dan membuktikan B
; bukti gabungan hanyalah sepasang bukti: satu untuk masing-masing konjungt.
Dalam deduksi alami:
Γ ⊢ A Γ ⊢ B
Γ ⊢ A ∧ B
dan dalam kalkulus lambda yang diketik sederhana:
Γ ⊢ a : A Γ ⊢ b : B
Γ ⊢ (a, b) : A × B
Korespondensi serupa ada untuk ∨
dan menjumlahkan jenis, →
dan jenis fungsi, dan berbagai aturan eliminasi.
Proposisi yang tidak dapat dibuktikan (salah secara intuitif) berhubungan dengan tipe yang tidak berpenghuni.
Dengan analogi tipe sebagai proposisi logis dalam pikiran, kita dapat mulai mempertimbangkan bagaimana memodelkan predikat di dunia tipe. Ada banyak cara di mana ini telah diformalkan (lihat pengantar untuk Teori Tipe Intuitionistik Martin-Löf untuk standar yang banyak digunakan) tetapi pendekatan abstrak biasanya mengamati bahwa suatu predikat seperti proposisi dengan variabel-variabel istilah bebas, atau, sebagai alternatif, suatu fungsi mengambil istilah untuk proposisi. Jika kita membiarkan ekspresi tipe mengandung istilah, maka perawatan dengan gaya kalkulus lambda segera muncul sebagai kemungkinan!
Mengingat hanya bukti konstruktif, apa yang merupakan bukti ∀x ∈ X.P(x)
? Kita dapat menganggapnya sebagai fungsi bukti, mengambil istilah ( x
) menjadi bukti proposisi yang sesuai ( P(x)
). Jadi anggota (bukti) dari jenis (proposisi) ∀x : X.P(x)
adalah 'tergantung fungsi', yang untuk setiap x
di X
beri istilah tipe P(x)
.
Bagaimana dengan ∃x ∈ X.P(x)
? Kita perlu setiap anggota X
, x
bersama dengan bukti P(x)
. Jadi anggota (bukti) dari jenis (proposisi) ∃x : X.P(x)
adalah 'tergantung pasang': istilah dibedakan x
dalam X
, bersama-sama dengan istilah jenis P(x)
.
Notasi: Saya akan gunakan
∀x ∈ X...
untuk pernyataan aktual tentang anggota kelas X
, dan
∀x : X...
untuk ekspresi tipe yang sesuai dengan kuantifikasi universal atas tipe X
. Demikian juga untuk ∃
.
Pertimbangan kombinasi: produk dan jumlah
Seperti halnya korespondensi Curry-Howard dengan proposisi, kami memiliki korespondensi kombinatorial dari tipe aljabar dengan angka dan fungsi, yang merupakan poin utama dari pertanyaan ini. Untungnya, ini dapat diperluas ke tipe dependen yang diuraikan di atas!
Saya akan menggunakan notasi modulus
|A|
untuk mewakili 'ukuran' suatu jenis A
, untuk membuat eksplisit korespondensi yang dijabarkan dalam pertanyaan, antara jenis dan angka. Perhatikan bahwa ini adalah konsep di luar teori; Saya tidak mengklaim bahwa perlu ada operator semacam itu dalam bahasa tersebut.
Mari kita hitung anggota tipe yang mungkin (dikurangi sepenuhnya, kanonik)
∀x : X.P(x)
yang merupakan jenis fungsi dependen yang mengambil istilah x
tipe X
ke istilah tipe P(x)
. Setiap fungsi tersebut harus memiliki output untuk setiap jangka waktu X
, dan output ini harus dari tipe tertentu. Untuk setiap x
di X
, kemudian, ini memberikan |P(x)|
'pilihan' output.
Bagian lucunya adalah
|∀x : X.P(x)| = Π[x : X]|P(x)|
yang tentu saja tidak masuk akal jika X
itu IO ()
, tetapi berlaku untuk jenis aljabar.
Demikian pula dengan istilah tipe
∃x : X.P(x)
adalah jenis pasangan (x, p)
dengan p : P(x)
, sehingga diberi x
di X
kita dapat membangun sebuah pasangan yang sesuai dengan setiap anggota P(x)
, memberikan |P(x)|
'pilihan'.
Karenanya,
|∃x : X.P(x)| = Σ[x : X]|P(x)|
dengan peringatan yang sama.
Ini membenarkan notasi umum untuk tipe dependen dalam teori menggunakan simbol Π
dan Σ
, dan memang banyak teori mengaburkan perbedaan antara 'untuk semua' dan 'produk' dan antara 'ada' dan 'jumlah', karena korespondensi yang disebutkan di atas.
Kami semakin dekat!
Vektor: mewakili tupel dependen
Bisakah kita sekarang menyandikan ekspresi numerik seperti
Σ[n ∈ ℕ]Xⁿ
sebagai jenis ekspresi?
Tidak terlalu. Meskipun kita dapat secara informal mempertimbangkan makna ekspresi seperti Xⁿ
di Haskell, di mana X
ada jenis dan n
bilangan alami, ini merupakan penyalahgunaan notasi; ini adalah tipe ekspresi yang mengandung angka: jelas bukan ekspresi yang valid.
Di sisi lain, dengan tipe dependen dalam gambar, tipe yang mengandung angka justru intinya; pada kenyataannya, tupel dependen atau 'vektor' adalah contoh yang sangat sering dikutip tentang bagaimana tipe dependen dapat memberikan keamanan tingkat-tipe pragmatis untuk operasi seperti akses daftar . Vektor hanyalah daftar beserta informasi tingkat-jenis mengenai panjangnya: seperti apa yang kita inginkan untuk ekspresi tipe Xⁿ
.
Untuk durasi jawaban ini, biarkan
Vec X n
menjadi jenis n
vektor-panjang dari X
nilai -type.
Secara teknis di n
sini, bukan bilangan asli yang sebenarnya , representasi dalam sistem bilangan alami. Kita dapat merepresentasikan bilangan asli ( Nat
) dalam gaya Peano sebagai nol ( 0
) atau penggantinya ( S
) dari bilangan alami lain, dan bagi n ∈ ℕ
saya menulis ˻n˼
berarti istilah Nat
yang diwakilinya n
. Sebagai contoh, ˻3˼
adalah S (S (S 0))
.
Lalu kita punya
|Vec X ˻n˼| = |X|ⁿ
untuk apa saja n ∈ ℕ
.
Jenis Nat: mempromosikan istilah ℕ ke tipe
Sekarang kita bisa menyandikan ekspresi seperti
Σ[n ∈ ℕ]Xⁿ
sebagai tipe. Ungkapan khusus ini akan memunculkan suatu tipe yang tentu saja isomorfis terhadap tipe daftar X
, sebagaimana diidentifikasi dalam pertanyaan. (Tidak hanya itu, tetapi dari sudut pandang kategori-teoretis, fungsi tipe - yang merupakan functor - mengambil X
ke tipe di atas secara alami isomorfik ke Daftar functor.)
Salah satu bagian terakhir dari teka-teki untuk fungsi 'sewenang-wenang' adalah cara menyandikan, untuk
f : ℕ → ℕ
ekspresi suka
Σ[n ∈ ℕ]f(n)Xⁿ
sehingga kita dapat menerapkan koefisien arbitrer ke seri daya.
Kami sudah memahami korespondensi tipe aljabar dengan angka, memungkinkan kami memetakan dari tipe ke angka dan mengetik fungsi ke fungsi numerik. Kita juga bisa pergi ke arah lain! - mengambil bilangan alami, jelas ada tipe aljabar yang dapat didefinisikan dengan banyak anggota istilah, apakah kita memiliki tipe dependen atau tidak. Kita dapat dengan mudah membuktikan ini di luar teori tipe dengan induksi. Yang kita butuhkan adalah cara untuk memetakan dari bilangan asli ke tipe, di dalam sistem.
Kesadaran yang menyenangkan adalah bahwa, begitu kita memiliki tipe dependen, bukti melalui induksi dan konstruksi oleh rekursi menjadi sangat mirip - memang mereka adalah hal yang sama dalam banyak teori. Karena kita dapat membuktikan dengan induksi bahwa ada jenis yang memenuhi kebutuhan kita, haruskah kita tidak dapat membangunnya?
Ada beberapa cara untuk merepresentasikan tipe pada level term. Di sini saya akan menggunakan notasi Haskellish imajiner *
untuk alam semesta tipe, itu sendiri biasanya dianggap sebagai tipe dalam pengaturan dependen. 1
Demikian juga, ada juga paling tidak banyak cara untuk memberi notasi ' ℕ
-memasuki' karena ada teori tipe dependen. Saya akan menggunakan notasi pencocokan pola Haskellish.
Kami membutuhkan pemetaan, α
dari Nat
ke *
, dengan properti
∀n ∈ ℕ.|α ˻n˼| = n.
Pseudodefinition berikut sudah mencukupi.
data Zero -- empty type
data Successor a = Z | Suc a -- Successor ≅ Maybe
α : Nat -> *
α 0 = Zero
α (S n) = Successor (α n)
Jadi kita melihat bahwa tindakan α
mencerminkan perilaku penerus S
, menjadikannya semacam homomorfisme. Successor
adalah fungsi tipe yang 'menambah satu' ke jumlah anggota tipe; yaitu, |Successor a| = 1 + |a|
untuk apa pun a
dengan ukuran yang ditentukan.
Misalnya α ˻4˼
(yang α (S (S (S (S 0))))
), adalah
Successor (Successor (Successor (Successor Zero)))
dan ketentuan dari jenis ini adalah
Z
Suc Z
Suc (Suc Z)
Suc (Suc (Suc Z))
memberikan kita tepat empat elemen: |α ˻4˼| = 4
.
Demikian juga, untuk apa pun n ∈ ℕ
, yang kita miliki
|α ˻n˼| = n
seperti yang dipersyaratkan.
- Banyak teori mensyaratkan bahwa anggota
*
hanyalah perwakilan dari jenis, dan operasi disediakan sebagai pemetaan eksplisit dari segi jenis *
ke jenis terkait. Teori-teori lain memungkinkan tipe literal itu sendiri untuk menjadi entitas tingkat-tingkat.
Fungsi 'sewenang-wenang'?
Sekarang kita memiliki alat untuk mengekspresikan rangkaian daya sepenuhnya umum sebagai tipe!
Seri
Σ[n ∈ ℕ]f(n)Xⁿ
menjadi tipenya
∃n : Nat.α (˻f˼ n) × (Vec X n)
di mana ˻f˼ : Nat → Nat
ada beberapa representasi yang sesuai dalam bahasa fungsi f
. Kita bisa melihat ini sebagai berikut.
|∃n : Nat.α (˻f˼ n) × (Vec X n)|
= Σ[n : Nat]|α (˻f˼ n) × (Vec X n)| (property of ∃ types)
= Σ[n ∈ ℕ]|α (˻f˼ ˻n˼) × (Vec X ˻n˼)| (switching Nat for ℕ)
= Σ[n ∈ ℕ]|α ˻f(n)˼ × (Vec X ˻n˼)| (applying ˻f˼ to ˻n˼)
= Σ[n ∈ ℕ]|α ˻f(n)˼||Vec X ˻n˼| (splitting product)
= Σ[n ∈ ℕ]f(n)|X|ⁿ (properties of α and Vec)
Seberapa 'sewenang-wenang' ini? Kami dibatasi tidak hanya untuk koefisien integer dengan metode ini, tetapi untuk bilangan asli. Selain itu, f
dapat berupa apa saja, mengingat bahasa Turing Lengkap dengan tipe dependen, kita dapat mewakili fungsi analitik apa pun dengan koefisien bilangan alami.
Saya belum menyelidiki interaksi ini dengan, misalnya, kasus yang disediakan dalam pertanyaan List X ≅ 1/(1 - X)
atau apa yang mungkin dirasakan 'tipe' negatif dan non-integer dalam konteks ini.
Semoga jawaban ini bisa mengeksplorasi seberapa jauh kita bisa pergi dengan fungsi tipe sewenang-wenang.