Dari referensi ini: Kepositifan yang ketat
Kondisi positif yang ketat mengesampingkan deklarasi seperti
data Bad : Set where
bad : (Bad → Bad) → Bad
A B C
-- A is in a negative position, B and C are OK
Mengapa A negatif? Juga Mengapa B diizinkan? Saya mengerti mengapa C diizinkan.
type-theory
inductive-datatypes
Pushpa
sumber
sumber
A
dan akhirnya meledak stack (dalam bahasa berbasis stack).Jawaban:
Pertama, penjelasan terminologis: posisi negatif dan positif datang dari logika. Mereka adalah tentang assymetry di operator logika: di yang berperilaku berbeda dari . Hal serupa terjadi dalam teori kategori, di mana kita mengatakan contravarian dan kovarian bukannya negatif dan positif, masing-masing. Dalam fisika mereka berbicara tentang jumlah yang berperilaku "kovarien" dan "juga contravarian. Jadi ini adalah fenomena yang sangat umum. Seorang programmer mungkin menganggapnya sebagai" input "dan" output ".A BA⇒B A B
Sekarang ke tipe data induktif.
Pikirkan sebuah datatype induktif sebagai semacam aljabar struktur: konstruktor adalah operasi yang mengambil unsur-unsur dari sebagai argumen dan menghasilkan unsur-unsur baru dari . Ini sangat mirip dengan aljabar biasa: penjumlahan mengambil dua angka dan menghasilkan angka.T TT T T
Dalam aljabar, biasanya suatu operasi membutuhkan jumlah argumen yang terbatas, dan dalam kebanyakan kasus dibutuhkan argumen nol (konstan), satu (unary) atau dua (binary). Lebih mudah untuk menggeneralisasi ini untuk konstruktor tipe data. Misalkan
c
adalah konstruktor untuk tipe dataT
:c
konstan kita dapat menganggapnya sebagai fungsiunit -> T
, atau setara(empty -> T) -> T
,c
unary kita dapat menganggapnya sebagai fungsiT -> T
, atau yang setara(unit -> T) -> T
,c
biner kita dapat menganggapnya sebagai fungsiT -> T -> T
, atau setaraT * T -> T
, atau setara(bool -> T) -> T
,c
yang mengambil tujuh argumen, kita bisa melihatnya sebagai fungsi di(seven -> T) -> T
manaseven
beberapa tipe yang sebelumnya didefinisikan dengan tujuh elemen.c
yang mengambil banyak argumen yang tak terhingga banyaknya, yang akan menjadi fungsi(nat -> T) -> T
.Contoh-contoh ini menunjukkan bahwa bentuk umum dari sebuah konstruktor seharusnya
di mana kita sebut
A
dengan arity daric
dan kita berpikir tentangc
sebagai konstruktor yang mengambilA
argumen -banyak tipeT
untuk menghasilkan unsurT
.Ini adalah sesuatu yang sangat penting: arities harus didefinisikan sebelum kita mendefinisikan
T
, atau kita tidak bisa mengatakan apa yang seharusnya dilakukan oleh konstruktor. Jika seseorang mencoba memiliki konstruktorlalu pertanyaan "berapa banyak argumen yang
broken
dibutuhkan?" tidak memiliki jawaban yang baik Anda mungkin mencoba menjawabnya dengan "dibutuhkanT
-banyak argumen", tetapi itu tidak akan berhasil, karenaT
belum didefinisikan. Kita mungkin mencoba keluar dari cunundrum dengan menggunakan teori titik tetap mewah untuk menemukan jenisT
dan fungsi injeksi(T -> T) -> T
, dan akan berhasil, tetapi kita juga akan melanggar prinsip induksi untukT
sepanjang jalan. Jadi, itu ide yang buruk untuk mencoba hal seperti itu.Demi kelengkapan, izinkan saya menjelaskan keseluruhan cerita. Kita perlu menggeneralisasi bentuk konstruktor di atas sedikit. Terkadang kami memiliki operasi atau konstruktor yang mengambil parameter . Sebagai contoh, perkalian skalar mengambil skalar dan vektor untuk menghasilkan vektor . Ini adalah operasi unary pada vektor, diparameterisasi oleh skalar. Kita dapat melihat perkalian skalar sebagai operasi unary yang tak terhingga banyaknya, satu untuk setiap skalar, tapi itu menjengkelkan. Jadi, bentuk umum konstruktor harus memungkinkan parameter dari beberapa tipe :v λ ⋅ vλ v λ⋅v
c
B
Memang, banyak konstruktor dapat ditulis ulang dengan cara ini, tetapi tidak semua, kita perlu satu langkah lagi, yaitu kita harus membiarkan
A
untuk bergantung padaB
:Ini adalah bentuk akhir dari konstruktor untuk tipe induktif. Ini juga tepat apa tipe-W. Bentuknya sangat umum sehingga kita hanya perlu satu konstruktor saja
c
! Memang, jika kita memiliki dua dari merekamaka kita bisa menggabungkannya menjadi satu
dimana
Ngomong-ngomong, jika kita menjelajah bentuk umum kita melihat bahwa itu setara dengan
yang lebih dekat dengan apa yang sebenarnya ditulis orang dalam asisten bukti. Asisten pembuktian memungkinkan kita untuk menuliskan konstruktor dengan cara yang mudah, tetapi itu setara dengan bentuk umum di atas (latihan!).
sumber
Kemunculan pertama
Bad
disebut 'negatif' karena mewakili argumen fungsi, yaitu terletak di sebelah kiri panah fungsi (lihat Jenis rekursif gratis oleh Philip Wadler). Saya kira asal usul istilah 'posisi negatif' bermula dari gagasan contravariance ('contra' berarti berlawanan).Tidak diperbolehkan memiliki tipe yang didefinisikan dalam posisi negatif karena seseorang dapat menulis program non-terminating menggunakannya, yaitu normalisasi yang kuat gagal di hadapannya (lebih lanjut tentang ini di bawah ini). Ngomong-ngomong, ini adalah alasan untuk nama aturan 'kepositifan ketat': kami tidak mengizinkan posisi negatif.
Kami mengizinkan kemunculan kedua
Bad
karena tidak menyebabkan non-terminasi dan kami ingin menggunakan tipe yang didefinisikan (Bad
) di beberapa titik dalam tipe data rekursif ( sebelum panah terakhir konstruktornya).Penting untuk dipahami bahwa definisi berikut tidak melanggar aturan kepositifan yang ketat.
Aturan hanya berlaku untuk argumen konstruktor (yang keduanya
Good
dalam kasus ini) dan tidak untuk konstruktor itu sendiri (lihat juga " Pemrograman Bersertifikat dengan Jenis Tanggungan " oleh Adam Chlipala ).Contoh lain yang melanggar kepositifan yang ketat:
Anda mungkin juga ingin memeriksa jawaban ini tentang posisi negatif.
Lebih lanjut tentang non-pemutusan ... Halaman yang dirujuk Anda berisi beberapa penjelasan (bersama dengan contoh di Haskell):
Berikut adalah contoh analog dalam Ocaml, yang menunjukkan bagaimana menerapkan perilaku rekursif tanpa (!) Menggunakan rekursi secara langsung:
The
nonTerminating
fungsi "membongkar" fungsi dari argumen dan apel ke argumen asli. Yang penting di sini adalah bahwa sebagian besar sistem tipe tidak mengizinkan fungsi lewat untuk diri mereka sendiri, jadi istilah sepertif f
tidak akan mengetik centang, karena tidak ada tipe untukf
memuaskan tanda ketik. Salah satu alasan sistem tipe diperkenalkan adalah untuk menonaktifkan aplikasi mandiri (lihat di sini ).Membungkus tipe data seperti yang kami perkenalkan di atas dapat digunakan untuk menghindari hambatan ini dalam perjalanan menuju ketidakkonsistenan.
Saya ingin menambahkan bahwa perhitungan non-terminasi memperkenalkan inkonsistensi pada sistem logika. Dalam kasus Agda dan Coq,
False
tipe data induktif tidak memiliki konstruktor, jadi Anda tidak akan pernah bisa membangun istilah bukti tipe False. Tetapi jika perhitungan non-terminasi diizinkan, seseorang dapat melakukannya misalnya dengan cara ini (dalam Coq):Kemudian
loop 0
akan mengetik cekloop 0 : False
, jadi di bawah korespondensi Curry-Howard itu berarti kita membuktikan proposisi yang salah.Hasilnya : aturan kepositifan yang ketat untuk definisi induktif mencegah perhitungan yang tidak berakhir yang merupakan bencana bagi logika.
sumber