Saat menyusun aplikasi Haskell saya dengan -Wall
opsi tersebut, GHC mengeluh tentang instans yatim piatu, misalnya:
Publisher.hs:45:9:
Warning: orphan instance: instance ToSElem Result
Jenis kelas ToSElem
bukan milik saya, ini ditentukan oleh HStringTemplate .
Sekarang saya tahu cara memperbaikinya (pindahkan deklarasi instance ke modul tempat Hasil dideklarasikan), dan saya tahu mengapa GHC lebih memilih untuk menghindari instance yatim piatu , tetapi saya masih percaya bahwa cara saya lebih baik. Saya tidak peduli jika kompilernya merepotkan - daripada saya.
Alasan saya ingin mendeklarasikan ToSElem
instance saya di modul Publisher adalah karena modul Publisherlah yang bergantung pada HStringTemplate, bukan modul lainnya. Saya mencoba untuk menjaga pemisahan kekhawatiran dan menghindari setiap modul bergantung pada HStringTemplate.
Saya pikir salah satu keuntungan kelas tipe Haskell, jika dibandingkan misalnya dengan antarmuka Java, adalah mereka terbuka daripada tertutup dan oleh karena itu instance tidak harus dideklarasikan di tempat yang sama dengan tipe datanya. Saran GHC adalah mengabaikan hal ini.
Jadi, yang saya cari adalah beberapa validasi bahwa pemikiran saya sehat dan bahwa saya akan dibenarkan untuk mengabaikan / menekan peringatan ini, atau argumen yang lebih meyakinkan untuk tidak melakukan sesuatu dengan cara saya.
Jawaban:
Saya mengerti mengapa Anda ingin melakukan ini, tetapi sayangnya, ini mungkin hanya ilusi bahwa kelas Haskell tampak "terbuka" dengan cara yang Anda katakan. Banyak orang merasa bahwa kemungkinan melakukan ini adalah bug dalam spesifikasi Haskell, untuk alasan yang akan saya jelaskan di bawah. Bagaimanapun, jika itu benar-benar tidak sesuai untuk instance Anda perlu dideklarasikan baik di modul tempat kelas dideklarasikan atau di modul tempat tipe dideklarasikan, itu mungkin merupakan tanda bahwa Anda harus menggunakan a
newtype
atau pembungkus lain di sekitar tipe Anda.Alasan mengapa instance orphan perlu dihindari berjalan jauh lebih dalam daripada kenyamanan kompilator. Topik ini agak kontroversial, seperti yang Anda lihat dari jawaban lain. Untuk menyeimbangkan diskusi, saya akan menjelaskan sudut pandang bahwa seseorang tidak boleh, pernah, menulis contoh yatim piatu, yang menurut saya merupakan pendapat mayoritas di antara Haskeller yang berpengalaman. Pendapat saya sendiri ada di tengah-tengah, yang akan saya jelaskan di akhir.
Masalahnya berasal dari fakta bahwa ketika lebih dari satu deklarasi instance ada untuk kelas dan tipe yang sama, tidak ada mekanisme dalam Haskell standar untuk menentukan mana yang akan digunakan. Sebaliknya, program tersebut ditolak oleh kompilator.
Efek paling sederhana dari itu adalah bahwa Anda dapat memiliki program yang bekerja dengan sempurna yang tiba-tiba akan berhenti mengkompilasi karena perubahan yang dibuat orang lain dalam ketergantungan modul Anda yang jauh.
Lebih buruk lagi, mungkin saja program kerja mulai mogok saat runtime karena perubahan yang jauh. Anda bisa menggunakan metode yang Anda asumsikan berasal dari deklarasi instance tertentu, dan metode itu bisa diganti secara diam-diam dengan instance lain yang hanya cukup berbeda untuk menyebabkan program Anda mulai mogok tanpa alasan.
Orang yang menginginkan jaminan bahwa masalah ini tidak akan pernah terjadi pada mereka harus mengikuti aturan bahwa jika ada orang, di mana pun, pernah mendeklarasikan instance dari kelas tertentu untuk jenis tertentu, tidak ada contoh lain yang harus dideklarasikan lagi dalam program apa pun yang ditulis. oleh siapapun. Tentu saja, ada solusi untuk menggunakan a
newtype
untuk mendeklarasikan instance baru, tetapi itu setidaknya selalu merupakan ketidaknyamanan kecil, dan terkadang yang besar. Jadi dalam pengertian ini, mereka yang menulis contoh yatim piatu dengan sengaja menjadi kurang sopan.Jadi apa yang harus dilakukan tentang masalah ini? Kamp anti-orphan-instance mengatakan bahwa peringatan GHC adalah bug, itu harus berupa kesalahan yang menolak upaya apa pun untuk mendeklarasikan instance orphan. Sementara itu, kita harus menjalankan disiplin diri dan menghindarinya dengan cara apa pun.
Seperti yang Anda lihat, ada orang yang tidak terlalu mengkhawatirkan masalah potensial tersebut. Mereka benar-benar mendorong penggunaan contoh yatim piatu sebagai alat untuk pemisahan masalah, seperti yang Anda sarankan, dan mengatakan bahwa seseorang harus memastikan berdasarkan kasus per kasus bahwa tidak ada masalah. Saya telah cukup sering direpotkan oleh contoh yatim piatu orang lain untuk diyakinkan bahwa sikap ini terlalu angkuh.
Saya pikir solusi yang tepat adalah menambahkan ekstensi ke mekanisme impor Haskell yang akan mengontrol impor instance. Itu tidak akan menyelesaikan masalah sepenuhnya, tapi itu akan memberikan bantuan untuk melindungi program kami dari kerusakan dari kasus yatim piatu yang sudah ada di dunia. Dan kemudian, seiring berjalannya waktu, saya mungkin menjadi yakin bahwa dalam kasus tertentu yang terbatas, mungkin seorang anak yatim piatu mungkin tidak seburuk itu. (Dan godaan itu adalah alasan mengapa beberapa orang di kamp anti-yatim piatu menentang lamaran saya.)
Kesimpulan saya dari semua ini adalah bahwa setidaknya untuk saat ini, saya akan sangat menyarankan agar Anda menghindari mendeklarasikan kasus yatim piatu, untuk mempertimbangkan orang lain jika tidak ada alasan lain. Gunakan a
newtype
.sumber
Silakan tekan peringatan ini!
Anda berada di perusahaan yang baik. Conal melakukannya di "TypeCompose". "chp-mtl" dan "chp-transformers" melakukannya, "control-monad-exception-mtl" dan "control-monad-exception-monadsfd" melakukannya, dll.
btw Anda mungkin sudah tahu ini, tetapi bagi mereka yang tidak dan tersandung pertanyaan Anda pada pencarian:
{-# OPTIONS_GHC -fno-warn-orphans #-}
Edit:
Saya mengakui masalah yang disebutkan Yitz dalam jawabannya sebagai masalah nyata. Namun saya melihat tidak menggunakan contoh yatim piatu sebagai masalah juga, dan saya mencoba untuk memilih "paling sedikit dari semua kejahatan", yang merupakan cara yang bijaksana untuk menggunakan contoh yatim piatu.
Saya hanya menggunakan tanda seru dalam jawaban singkat saya karena pertanyaan Anda menunjukkan bahwa Anda sudah sangat menyadari masalah tersebut. Kalau tidak, saya akan kurang antusias :)
Sedikit pengalihan, tapi yang saya yakini adalah solusi sempurna di dunia yang sempurna tanpa kompromi:
Saya percaya bahwa masalah yang disebutkan Yitz (tidak mengetahui contoh mana yang dipilih) dapat diselesaikan dalam sistem pemrograman "holistik" di mana:
Kembali dari dunia fantasi (atau semoga masa depan), sekarang: Saya sarankan mencoba menghindari kejadian yatim piatu sambil tetap menggunakannya saat Anda "benar-benar perlu"
sumber
Anak yatim piatu memang mengganggu, tapi menurut saya terkadang diperlukan. Saya sering menggabungkan perpustakaan di mana sebuah tipe berasal dari satu perpustakaan dan kelas berasal dari perpustakaan lain. Tentu saja penulis pustaka ini tidak dapat diharapkan untuk memberikan contoh untuk setiap kombinasi tipe dan kelas yang memungkinkan. Jadi saya harus menyediakannya, jadi mereka yatim piatu.
Gagasan bahwa Anda harus membungkus tipe dalam tipe baru ketika Anda perlu memberikan contoh adalah ide dengan manfaat teoritis, tetapi itu terlalu membosankan dalam banyak keadaan; Ini adalah jenis ide yang diajukan oleh orang-orang yang tidak menulis kode Haskell untuk mencari nafkah. :)
Jadi lanjutkan dan berikan contoh yatim piatu. Mereka tidak berbahaya.
Jika Anda dapat merusak ghc dengan instance orphan maka itu adalah bug dan harus dilaporkan seperti itu. (Bug yang dimiliki / dimiliki ghc tentang tidak mendeteksi banyak instance tidaklah sulit untuk diperbaiki.)
Tetapi ketahuilah bahwa suatu saat di masa mendatang, orang lain mungkin menambahkan beberapa contoh seperti yang sudah Anda miliki, dan Anda mungkin mendapatkan kesalahan (waktu kompilasi).
sumber
(Ord k, Arbitrary k, Arbitrary v) ⇒ Arbitrary (Map k v)
saat menggunakan QuickCheck.Dalam hal ini, menurut saya penggunaan orphan instance baik-baik saja. Aturan umum bagi saya adalah - Anda dapat mendefinisikan sebuah instance jika Anda "memiliki" kelas tipe atau jika Anda "memiliki" tipe datanya (atau beberapa komponen darinya - misalnya, instance untuk Maybe MyData juga baik-baik saja, setidaknya terkadang). Dalam batasan tersebut, di mana Anda memutuskan untuk meletakkan contoh adalah urusan Anda sendiri.
Ada satu pengecualian lebih lanjut - jika Anda tidak memiliki kelas tipe atau tipe datanya, tetapi menghasilkan biner dan bukan pustaka, maka tidak masalah juga.
sumber
(Saya tahu saya terlambat ke pesta tetapi ini mungkin masih berguna untuk orang lain)
Anda dapat menyimpan instance orphan dalam modul mereka sendiri, lalu jika ada yang mengimpor modul itu secara khusus karena mereka membutuhkannya dan mereka dapat menghindari mengimpornya jika menyebabkan masalah.
sumber
Sejalan dengan ini, saya memahami perpustakaan WRT posisi kamp instans anti-yatim piatu, tetapi untuk target yang dapat dieksekusi, bukankah instans yatim piatu baik-baik saja?
sumber