Mengapa Tidak Dibatasi subkelas Enum di Haskell


9

Sepertinya instance Bounded harus memiliki implementasi Enum yang waras. Saya pribadi tidak bisa memikirkan contoh tandingan, meskipun jika seseorang menemukan yang tidak patologis maka saya akan mengerti mengapa ini tidak terjadi.

Dari melakukan :ipada dua typeclasses sepertinya satu-satunya pengecualian saat ini di perpustakaan standar adalah untuk tupel, yang Dibatasi tetapi tidak Enum. Namun tuple Terikat juga harus Enumerable dengan cara yang waras, dengan hanya menambah elemen terakhir dan kemudian membungkus ketika sampai ke maxBound.

Perubahan ini mungkin juga akan melibatkan penambahan predBdan nextBatau sesuatu seperti itu ke Dibatasi untuk cara yang aman / berulang untuk melintasi melalui nilai-nilai Enum. Dalam hal ini toEnum 0 :: (...)akan sama dengan(toEnum 0, toEnum 0, ...) :: (...)


3
Tidak dapat benar-benar menjawab ini secara otoritatif tetapi pertimbangkan kisaran semua bilangan real antara 0 dan 1. Ini memiliki batas bawah dan atas yang jelas tetapi memiliki anggota yang tak terhitung jumlahnya.
Doval

@Doval itu adalah poin yang adil. Namun hal yang sama dapat dikatakan tentang semua bilangan real secara umum (anggota tak terhingga tak terhitung), tetapi Double/ Floatdan semua jenis yang sama Enumtetap menerapkan , mereka hanya membuat succ = (+ 1)dan fromEnum = truncate. Cara Haskell benar-benar masuk akal dari perspektif kepraktisan sebagaimana sebaliknya [0, 0,5 ..] dan yang serupa tidak akan berhasil, sehingga tampaknya Haskell tidak khawatir tentang kemampuan berhitung ketika datang ke Enums.
titik koma

1
Aku tidak menyadari bahwa succadalah (+1). Itu aneh, karena Doubledan Floattidak memiliki ketepatan yang tak terbatas dan karenanya dapat dihitung - succbisa saja didefinisikan sebagai +1 ULP .
Doval

2
@Doval Saya pikir alasan untuk itu adalah karena tim inti Haskell ingin [1 ..] berarti hal yang sama dengan Doubles yang artinya dengan Ints.
titik koma

@semicolon ganda dan mengapung bukan bilangan real (mis. tidak dapat menyimpan PI dalam dobel tanpa kehilangan presisi) sehingga mereka dapat dihitung
jk.

Jawaban:


8

Salah satu contoh praktis yang saya suka berasal dari dunia bahasa pemrograman: himpunan jenis dalam sistem OO dibatasi dan diskrit tetapi tidak dapat dihitung, dan dipesan sebagian tetapi tidak dipesan sepenuhnya.

Urutan parsial yang dimaksud adalah hubungan subtyping <:. Batas atas kemudian akan menjadi tipe atas (yang panggilan C # objectdan panggilan Scala Any), dan batas bawah akan menjadi tipe bawah (Scala Nothing; C # / Java tidak memiliki setara dengan berbicara tentang).

Namun, tidak ada cara untuk menghitung semua tipe dalam sistem tipe, jadi Anda tidak dapat menulis instance Enum Type. Ini harus jelas: pengguna dapat menulis tipe mereka sendiri sehingga tidak ada cara untuk mengetahui apa yang akan mereka lakukan sebelumnya. Anda dapat menghitung semua jenis dalam program apa pun, tetapi tidak di seluruh sistem.

Demikian juga, (menurut definisi subtipe tertentu yang masuk akal), <:bersifat refleksif, transitif, dan antisimetris tetapi tidak total . Ada pasangan jenis yang tidak terkait oleh <:. ( Catdan Dogkeduanya merupakan subtipe dari Animal, tetapi tidak ada subtipe yang lain.)


Misalkan kita sedang menulis kompiler untuk bahasa OO sederhana. Inilah representasi tipe dalam sistem kami:

data Type = Bottom | Class { name :: String, parent :: Type } | Top

Dan definisi hubungan subtyping:

(<:) :: Type -> Type -> Bool
Bottom <: _ = True
Class _ _ <: Bottom = False
Class n t <: s@(Class m _)
    | n == m = True  -- you can't have different classes with the same name in this hypothetical language
    | otherwise = t <: s  -- try to find s in the parents of this class
Class _ _ <: Top = True
Top <: Top = True
Top <: _ = False

Ini juga memberi kita hubungan supertyping.

(>:) :: Type -> Type -> Bool
t >: s = s <: t

Anda juga dapat menemukan batas paling atas dari dua jenis,

lub :: Type -> Type -> Type
lub Bottom s = s
lub t Bottom = t
lub t@(Class _ p) s@(Class _ q) =
    | t >: s = t
    | t <: s = s
    | p >: s = p
    | t <: q = q
    | otherwise = lub p q
lub Top _ = Top
lub _ Top = Top

Latihan: menunjukkan bahwa Typemembentuk poset lengkap yang dibatasi dua cara, di bawah <:dan di bawah >:.


Keren terima kasih! Itu menjawab pertanyaan saya sepenuhnya dan juga menjawab pertanyaan tindak lanjut saya tentang Ord. Apakah Persamaan memiliki masalah serupa? Di mana tipe yang tidak setara mungkin memiliki maxBound atau minBound. Dalam hal ini haruskah Cat == Dog mengembalikan false, karena mereka adalah kelas yang berbeda, atau akankah itu diputuskan karena posisi pohon meletakkan tidak di atas atau di bawah yang lain?
titik koma

Pemesanan menyiratkan kesetaraan - hanya mendefinisikan x == y = x <= y && y <= x. Jika saya mendesain sebuah Posetkelas, saya akan melakukannya class Eq a => Poset a. Google cepat mengkonfirmasi bahwa orang lain memiliki ide yang sama .
Benjamin Hodgson

Maaf pertanyaan saya ambigu. Yang saya maksudkan adalah apakah Bounded menyiratkan Persamaan bahkan jika itu tidak menyiratkan Ord.
titik koma

@semicolon Sekali lagi tidak ada hubungan antara dua kelas. Pertimbangkan data Bound a = Min | Val a | Maxyang menambah tipe adengan +∞dan -∞elemen. Dengan konstruksi Bound aselalu dapat dibuat contoh Boundedtapi itu hanya akan setara jika tipe yang mendasarinya aadalah
Benjamin Hodgson

cukup adil. Saya kira salah satu contoh bisa menjadi fungsi yang mengambil dan kembali nilai-nilai dari jenis Double, di mana const (1/0)adalah maxBounddan const (negate 1/0)adalah minBoundtetapi \x -> 1 - xdan \x -> x - 1tak tertandingi.
titik koma

4

Itu karena operasinya independen, jadi mengikatnya bersama dengan hubungan subkelas tidak benar-benar membelikanmu apa-apa. Katakanlah Anda ingin membuat jenis kustom yang diterapkan Bounded, mungkin Doublesdibatasi antara maks dan min, tetapi Anda tidak perlu melakukan Enumoperasi apa pun . Jika Boundedsubkelas, Anda harus mengimplementasikan semua Enumfungsi, hanya untuk membuatnya dikompilasi.

Tidak masalah jika ada implementasi yang masuk akal untuk Enum, atau jumlah typeclasses lainnya. Jika Anda tidak benar-benar membutuhkannya, Anda tidak harus dipaksa untuk mengimplementasikannya.

Bandingkan dengan katakanlah, Orddan Eq. Di sana, Ordoperasi tergantung pada Eqyang, jadi masuk akal untuk meminta subclass untuk menghindari duplikasi dan memastikan konsistensi.


1
Dalam kasus itu, itu adalah bagian dari definisi. Semua monad juga merupakan aplikasi dan fungsi berdasarkan definisi, sehingga Anda tidak dapat memenuhi "kontrak" monad tanpa memenuhi yang lain. Saya tidak cukup akrab dengan matematika untuk mengetahui apakah itu hubungan mendasar atau definisi yang dipaksakan, tetapi bagaimanapun, kita terjebak dengan itu sekarang.
Karl Bielefeldt

6
@semicolon Dokumentasi untukBounded mengatakan "Ord bukan superclass of Bounded karena tipe yang tidak sepenuhnya dipesan mungkin juga memiliki batas atas dan bawah."
Benjamin Hodgson

1
@BenjaminHodgson Bahkan tidak memikirkan jenis yang dipesan sebagian. +1 untuk contoh non-patologis dan untuk mengutip dokumentasi.
Doval

1
@semicolon Contoh pemesanan sebagian dari dunia komputer mungkin berupa subtyping dalam bahasa OO. Menulis <:untuk adalah subtipe dari , ∀ T S. T <: S ∨ S <: Ttidak berlaku (misalnya, int !<: bool ∧ bool !<: int). Anda mungkin akan mengalami hal ini jika Anda sedang menulis kompiler.
Benjamin Hodgson

1
@BenjaminHodgson ah ok. Jadi misalnya jika A adalah superclass dari B dan C, dan D adalah subkelas dari B dan C, maka B dan C tidak ada bandingannya, tetapi A dan D adalah maks / mnt?
titik koma
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.