The absurd
fungsi dalam Data.Void
memiliki tanda tangan berikut, di mana Void
adalah jenis logis berpenghuni diekspor oleh paket yang:
-- | Since 'Void' values logically don't exist, this witnesses the logical
-- reasoning tool of \"ex falso quodlibet\".
absurd :: Void -> a
Saya benar-benar tahu logika yang cukup untuk mendapatkan catatan dokumentasi bahwa ini sesuai, dengan korespondensi proposisi-sebagai-tipe, dengan rumus yang valid ⊥ → a
.
Yang membuat saya bingung dan penasaran adalah: dalam masalah pemrograman praktis apa fungsi ini berguna? Saya berpikir bahwa mungkin ini berguna dalam beberapa kasus sebagai cara yang aman untuk menangani kasus "tidak dapat terjadi" secara menyeluruh, tetapi saya tidak cukup tahu tentang penggunaan praktis Curry-Howard untuk mengetahui apakah gagasan itu ada di jalur yang benar sama sekali.
EDIT: Contoh sebaiknya di Haskell, tetapi jika ada yang ingin menggunakan bahasa yang diketik secara dependen, saya tidak akan mengeluh ...
sumber
absurd
fungsi tersebut telah digunakan dalam artikel ini yang berhubungan denganCont
monad: haskellforall.com/2012/12/the-continuation-monad.htmlabsurd
sebagai salah satu arah isomorfisme antaraVoid
danforall a. a
.Jawaban:
Hidup ini agak sulit, karena Haskell tidak ketat. Kasus penggunaan umum adalah untuk menangani jalur yang tidak mungkin. Sebagai contoh
Ini ternyata agak berguna. Pertimbangkan tipe sederhana untuk
Pipes
ini adalah versi tipe pipa standar yang disederhanakan dan disederhanakan dari
Pipes
perpustakaan Gabriel Gonzales . Sekarang, kita dapat menyandikan pipa yang tidak pernah menghasilkan (yaitu, konsumen) sebagaiini benar-benar tidak pernah membuahkan hasil. Implikasinya adalah bahwa aturan lipatan yang tepat untuk a
Consumer
adalahatau sebagai alternatif, Anda dapat mengabaikan kasus hasil saat berhadapan dengan konsumen. Ini adalah versi umum dari pola desain ini: gunakan tipe data polimorfik dan
Void
untuk menyingkirkan kemungkinan saat Anda membutuhkannya.Mungkin penggunaan paling klasik
Void
ada di CPS.artinya, a
Continuation
adalah fungsi yang tidak pernah kembali.Continuation
adalah jenis versi "tidak". Dari sini kita mendapatkan monad CPS (sesuai dengan logika klasik)karena Haskell murni, kita tidak bisa mendapatkan apapun dari tipe ini.
sumber
Void
tidak berpenghuni. Di Haskell, itu berisi_|_
. Dalam bahasa yang ketat, konstruktor data yang mengambil argumen bertipeVoid
tidak akan pernah bisa diterapkan, sehingga sisi kanan dari pola yang cocok tidak dapat dijangkau. Di Haskell, Anda perlu menggunakan a!
untuk memberlakukannya, dan GHC mungkin tidak akan menyadari bahwa jalur tersebut tidak dapat dijangkau._|_
? dan apakah itu menderita dari batasan yang sama?Pertimbangkan representasi ini untuk istilah lambda yang diparameterisasi oleh variabel bebasnya. (Lihat makalah oleh Bellegarde dan Hook 1994, Bird dan Paterson 1999, Altenkirch dan Reus 1999.)
Anda pasti bisa membuat ini menjadi
Functor
, menangkap gagasan penggantian nama, danMonad
menangkap gagasan substitusi.Sekarang pertimbangkan istilah tertutup : ini adalah penghuni
Tm Void
. Anda harus dapat menyematkan istilah tertutup ke dalam istilah dengan variabel bebas arbitrer. Bagaimana?Tangkapannya, tentu saja, adalah bahwa fungsi ini akan melintasi istilah tanpa melakukan apa pun. Tapi itu sentuhan yang lebih jujur daripada
unsafeCoerce
. Dan itulah mengapavacuous
ditambahkan keData.Void
...Atau tulis seorang evaluator. Berikut adalah nilai dengan variabel bebas di
b
.Saya baru saja mewakili lambda sebagai penutup. Evaluator diparameterisasi oleh lingkungan yang memetakan variabel bebas
a
ke nilai di atasb
.Anda dapat menebaknya. Untuk mengevaluasi istilah tertutup pada target apa pun
Lebih umum,
Void
jarang digunakan sendiri, tetapi berguna ketika Anda ingin membuat contoh parameter tipe dengan cara yang menunjukkan semacam ketidakmungkinan (misalnya, di sini, menggunakan variabel bebas dalam istilah tertutup). Seringkali tipe parametrized ini hadir dengan operasi pengangkatan fungsi tingkat tinggi pada parameter ke operasi pada keseluruhan tipe (misalnya, di sini,fmap
,>>=
,eval
). Jadi Anda lulusabsurd
sebagai operasi tujuan umumVoid
.Untuk contoh lain, bayangkan menggunakan
Either e v
untuk menangkap komputasi yang diharapkan memberi Andav
tetapi mungkin menimbulkan pengecualian jenise
. Anda mungkin menggunakan pendekatan ini untuk mendokumentasikan risiko perilaku buruk secara seragam. Untuk sempurna berperilaku baik perhitungan dalam pengaturan ini, mengambile
menjadiVoid
, maka penggunaanuntuk berlari dengan aman atau
untuk menanamkan komponen yang aman di dunia yang tidak aman.
Oh, dan hore terakhir, menangani "tidak bisa terjadi". Ini muncul dalam konstruksi ritsleting umum, di mana pun kursor tidak bisa berada.
Saya memutuskan untuk tidak menghapus sisanya, meskipun itu tidak terlalu relevan.
Sebenarnya, mungkin itu relevan. Jika Anda suka berpetualang, artikel yang belum selesai ini menunjukkan cara menggunakan
Void
untuk mengompresi representasi istilah dengan variabel bebasdalam sintaks yang dihasilkan secara bebas dari a
Differentiable
danTraversable
functorf
. Kami menggunakanTerm f Void
untuk merepresentasikan kawasan tanpa variabel bebas, dan[D f (Term f Void)]
untuk merepresentasikan saluran tabung melalui kawasan tanpa variabel bebas baik ke variabel bebas yang terisolasi, atau ke persimpangan di jalur ke dua atau lebih variabel bebas. Harus menyelesaikan artikel itu kapan-kapan.Untuk tipe tanpa nilai (atau setidaknya, tidak ada yang layak dibicarakan dengan teman yang sopan),
Void
sangat berguna. Danabsurd
bagaimana Anda menggunakannya.sumber
forall f. vacuous f = unsafeCoerce f
aturan penulisan ulang GHC yang valid?Functor
Instance palsu bisa jadi GADT yang sebenarnya bukan berfungsi seperti functor.Functor
s tidak melanggarfmap id = id
aturan? Ataukah itu yang Anda maksud dengan "palsu" di sini?Ini memang benar.
Bisa dibilang itu
absurd
tidak lebih berguna dariconst (error "Impossible")
. Namun, ini adalah tipe yang dibatasi, sehingga input satu-satunya dapat berupa sesuatu yang bertipeVoid
, tipe data yang sengaja dibiarkan tak berpenghuni. Ini berarti tidak ada nilai aktual yang dapat Anda berikanabsurd
. Jika Anda pernah berakhir di cabang kode di mana pemeriksa tipe berpikir bahwa Anda memiliki akses ke sesuatu yang bertipeVoid
, maka, Anda berada dalam situasi yang tidak masuk akal . Jadiabsurd
pada dasarnya Anda hanya menggunakan untuk menandai bahwa cabang kode ini tidak boleh dijangkau."Ex falso quodlibet" secara harfiah berarti "dari [a] salah [proposisi], apapun mengikuti". Jadi, ketika Anda menemukan bahwa Anda memegang sepotong data yang tipenya adalah
Void
, Anda tahu Anda memiliki bukti palsu di tangan Anda. Oleh karena itu, Anda dapat mengisi lubang apa pun yang Anda inginkan (melaluiabsurd
), karena dari proposisi yang salah, apa pun mengikuti.Saya menulis posting blog tentang ide di balik Conduit yang memiliki contoh penggunaan
absurd
.http://unknownparallel.wordpress.com/2012/07/30/pipes-to-conduits-part-6-leftovers/#running-a-pipeline
sumber
Umumnya, Anda dapat menggunakannya untuk menghindari kecocokan pola yang tampaknya sebagian. Misalnya, mengambil perkiraan deklarasi tipe data dari jawaban ini :
Kemudian Anda bisa menggunakan
absurd
seperti ini, misalnya:sumber
Ada berbagai cara untuk merepresentasikan tipe data kosong . Salah satunya adalah tipe data aljabar kosong. Cara lainnya adalah dengan membuatnya menjadi alias untuk ∀α.α atau
di Haskell - ini adalah cara kita dapat menyandikannya di Sistem F (lihat Bab 11 tentang Bukti dan Jenis ). Kedua deskripsi ini tentu saja isomorfik dan isomorfisme disaksikan oleh
\x -> x :: (forall a.a) -> Void
dan olehabsurd :: Void -> a
.Dalam beberapa kasus, kami lebih memilih varian eksplisit, biasanya jika tipe data kosong muncul dalam argumen suatu fungsi, atau dalam tipe data yang lebih kompleks, seperti di Data.Conduit :
Dalam beberapa kasus, kami lebih suka varian polimorfik, biasanya tipe data kosong terlibat dalam tipe kembalian suatu fungsi.
absurd
muncul saat kita mengkonversi antara dua representasi ini.Misalnya,
callcc :: ((a -> m b) -> m a) -> m a
use (implisit)forall b
. Bisa juga jenisnya((a -> m Void) -> m a) -> m a
, karena panggilan ke kontinuitas tidak benar-benar kembali, ia mentransfer kontrol ke titik lain. Jika kami ingin bekerja dengan kelanjutan, kami dapat menentukan(Kita bisa menggunakan
type Continuation' r a = forall b . a -> Cont r b
tapi itu membutuhkan tipe peringkat 2.) Dan kemudian,vacuousM
ubah iniCont r Void
menjadiCont r b
.(Perhatikan juga bahwa Anda dapat menggunakan haskellers.com untuk mencari penggunaan (ketergantungan terbalik) dari paket tertentu, seperti untuk melihat siapa dan bagaimana menggunakan paket void .)
sumber
TypeApplications
dapat digunakan untuk lebih eksplisit tentang rincianproof :: (forall a. a) -> Void
:proof fls = fls @Void
.Dalam bahasa dengan tipe dependen seperti Idris, ini mungkin lebih berguna daripada di Haskell. Biasanya, dalam fungsi total saat pola Anda cocok dengan nilai yang sebenarnya tidak dapat dimasukkan ke dalam fungsi, Anda kemudian akan membuat nilai dengan tipe tak berpenghuni dan digunakan
absurd
untuk menyelesaikan definisi kasus.Misalnya, fungsi ini menghapus elemen dari daftar dengan tipe-cat costraint yang ada di sana:
Di mana kasus kedua mengatakan bahwa ada elemen tertentu dalam daftar kosong, yang sangat tidak masuk akal. Secara umum, bagaimanapun, kompilator tidak mengetahui hal ini dan kami sering harus eksplisit. Kemudian kompilator dapat memeriksa bahwa definisi fungsi tidak parsial dan kami memperoleh jaminan waktu kompilasi yang lebih kuat.
Melalui sudut pandang Curry-Howard, di mana proposisinya, maka
absurd
semacam QED yang dibuktikan dengan kontradiksi.sumber