Salah satu sifat mendefinisikan dari ⊥ atau jenis kosong adalah bahwa ada fungsi ⊥ → A untuk setiap jenis SEBUAH . Bahkan, ada fungsi yang unik . Oleh karena itu, cukup masuk akal untuk fungsi ini disediakan sebagai bagian dari perpustakaan standar. Seringkali disebut sesuatu seperti absurd
. (Dalam sistem dengan subtyping, ini mungkin ditangani hanya dengan memiliki ⊥ menjadi subtipe dari setiap jenis. Kemudian konversi implisit absurd
. Pendekatan lain yang terkait adalah untuk menentukan ⊥ sebagai ∀ α . α yang hanya dapat dipakai untuk semua jenis.)
Anda pasti ingin memiliki fungsi seperti itu atau yang sederajat karena itulah yang memungkinkan Anda memanfaatkan fungsi yang menghasilkan ⊥ . Sebagai contoh, katakanlah saya diberi sejumlah tipe E+ A . Saya melakukan analisis kasus di atasnya dan dalam kasus E saya akan melempar pengecualian menggunakan throw:E→⊥ . Dalam A kasus, saya akan menggunakan f:A→B . Secara keseluruhan, saya ingin nilai dari tipe B sehingga saya perlu melakukan sesuatu untuk mengubah ⊥ menjadi B . Itu yang absurd
akan saya lakukan.
Yang mengatakan, tidak ada seluruh banyak alasan untuk menentukan fungsi Anda sendiri ⊥→A . Menurut definisi, mereka akan menjadi contoh absurd
. Namun, Anda mungkin melakukannya jika absurd
tidak disediakan oleh perpustakaan standar, atau Anda menginginkan jenis versi khusus untuk membantu pemeriksaan / inferensi tipe. Anda bisa, bagaimanapun, dengan mudah menghasilkan fungsi yang akan berakhir dipakai untuk tipe seperti ⊥→A .
Meskipun tidak ada banyak alasan untuk menulis fungsi seperti itu, umumnya harus tetap diizinkan . Salah satu alasannya adalah karena menyederhanakan alat / makro pembuatan kode.
Derek Elkins meninggalkan SE
sumber
(x ? 3 : throw new Exception())
diganti untuk keperluan analisis dengan sesuatu yang lebih seperti(x ? 3 : absurd(throw new Exception()))
?absurd
absurd
throw
Untuk menambah apa yang telah dikatakan tentang fungsi,
absurd: ⊥ -> a
saya memiliki contoh konkret tentang di mana fungsi ini sebenarnya berguna.Pertimbangkan tipe data Haskell
Free f a
yang mewakili struktur pohon umum denganf
node dan daun berbentuk yang mengandunga
s:data Free f a = Op (f (Free f a)) | Var a
Pohon-pohon ini dapat dilipat dengan fungsi sebagai berikut:
Secara singkat, operasi ini ditempatkan
alg
pada node dangen
daun.Sekarang ke intinya: semua struktur data rekursif dapat direpresentasikan menggunakan tipe data titik tetap. Dalam Haskell ini
Fix f
dan itu dapat didefinisikan sebagaitype Fix f = Free f ⊥
(yaitu Pohon denganf
node -shaped dan tidak ada daun di luar functorf
). Secara tradisional struktur ini memiliki lipatan juga, yang disebutcata
:Yang memberikan penggunaan absurd yang cukup rapi: karena pohon tidak dapat memiliki daun (karena ⊥ tidak memiliki penghuni selain
undefined
), tidak mungkin menggunakangen
untuk lipatan ini danabsurd
menggambarkannya!sumber
Tipe bawah adalah subtipe dari setiap tipe lainnya, yang bisa sangat berguna dalam praktiknya. Misalnya, tipe
NULL
dalam versi teoretis tipe-aman C harus berupa subtipe dari setiap tipe pointer lainnya, jika tidak Anda tidak dapat, mis., Kembali keNULL
tempat yangchar*
diharapkan; sama halnya, tipeundefined
dalam JavaScript tipe-aman teoretis harus merupakan subtipe dari setiap tipe lain dalam bahasa.exit()
throw()
Int
Int
exit()
sumber
NULL
apakah tipe unit bukan, berbeda dari ⊥ yang merupakan tipe kosong?void*
, Anda akan memerlukan jenis tertentu untuk itu yang dapat digunakan untuk semua jenis pointer.<:
Ada satu kegunaan yang bisa saya pikirkan, dan itu adalah sesuatu yang telah dianggap sebagai peningkatan bahasa pemrograman Swift.
Swift memiliki
maybe
Monad, diejaOptional<T>
atauT?
. Ada banyak cara untuk berinteraksi dengannya.Anda dapat menggunakan suka membuka bersyarat seperti
Anda dapat menggunakan
map
,flatMap
untuk mengubah nilai!
, tipe(T?) -> T
) untuk secara paksa membuka bungkusan konten, jika tidak memicu kerusakanOperator nil-penggabungan (
??
, tipe(T?, T) -> T
) untuk mengambil nilainya atau menggunakan nilai default:Sayangnya, tidak ada cara ringkas untuk mengatakan "membuka atau membuang kesalahan" atau "membuka atau crash dengan pesan kesalahan khusus". Sesuatu seperti
tidak mengkompilasi, karena
fatalError
memiliki tipe() -> Never
(()
adalahVoid
, Swift' jenis unit,Never
adalah jenis bawah Swift). Memanggilnya menghasilkanNever
, yang tidak kompatibel dengan yangT
diharapkan sebagai operan yang tepat??
.Dalam upaya untuk memperbaiki ini, Proposal Swift Evolution
SE-0217
- Operator "Unwrap or Die" diajukan. Itu pada akhirnya ditolak , tetapi itu membangkitkan minat dalam membuatNever
menjadi subtipe dari semua jenis.Jika
Never
dibuat menjadi subtipe dari semua jenis, maka contoh sebelumnya akan dapat dikompilasi:karena situs panggilan
??
memiliki tipe(T?, Never) -> T
, yang akan kompatibel dengan(T?, T) -> T
tanda tangan??
.sumber
Swift memiliki tipe "Never" yang tampaknya sangat seperti tipe bawah: Sebuah fungsi yang dinyatakan untuk kembali Tidak pernah bisa kembali, fungsi dengan parameter tipe Never tidak pernah bisa dipanggil.
Ini berguna sehubungan dengan protokol, di mana mungkin ada pembatasan karena jenis sistem bahasa bahwa suatu kelas harus memiliki fungsi tertentu, tetapi tanpa persyaratan bahwa fungsi ini harus pernah dipanggil, dan tidak ada persyaratan apa jenis argumen akan menjadi.
Untuk perincian, Anda harus melihat pada posting yang lebih baru di milis swift-evolution.
sumber