Tại sao không bị ràng buộc một lớp con của Enum trong Haskell


9

Có vẻ như bất kỳ trường hợp Bounded nào cũng nên thực hiện Enum. Cá nhân tôi không thể nghĩ ra một ví dụ, mặc dù nếu ai đó nghĩ ra một thứ không bệnh hoạn thì tôi sẽ hiểu tại sao không phải như vậy.

Từ việc thực hiện :itrên hai kiểu chữ, có vẻ như ngoại lệ duy nhất hiện tại trong thư viện tiêu chuẩn là dành cho các bộ dữ liệu, đó là Bounded nhưng không phải là Enums. Tuy nhiên, bất kỳ bộ giới hạn nào cũng phải là Vô số theo cách lành mạnh, chỉ bằng cách tăng phần tử cuối cùng và sau đó gói xung quanh khi nó đạt đến maxBound.

Thay đổi này có thể cũng liên quan đến việc thêm predBnextBhoặc một cái gì đó tương tự vào Bounded để có cách an toàn / lặp để đi qua các giá trị Enum. Trong trường hợp này toEnum 0 :: (...)sẽ bằng(toEnum 0, toEnum 0, ...) :: (...)


3
Không thể thực sự trả lời điều này một cách có thẩm quyền nhưng hãy xem xét phạm vi của tất cả các số thực từ 0 đến 1. Nó có giới hạn dưới và trên rõ ràng nhưng nó có vô số thành viên vô hạn.
Doval

@Doval đó là một điểm công bằng. Tuy nhiên, điều tương tự cũng có thể nói về tất cả các số thực nói chung (vô số thành viên vô hạn), nhưng Double/ Floatvà tất cả các loại tương tự đều thực hiện bằng Enummọi cách, chúng chỉ thực hiện succ = (+ 1)fromEnum = truncate. Cách của Haskell thực sự có ý nghĩa từ góc độ thực tiễn vì nếu không [0, 0,5 ..] và tương tự sẽ không hoạt động, vì vậy có vẻ như Haskell không lo lắng về tính có thể đếm được khi nói đến Enums.
dấu chấm phẩy

1
Tôi đã không biết đó succ(+1). Điều đó thật lạ, bởi vì DoubleFloatkhông có độ chính xác vô hạn và do đó là vô số - succcó thể được định nghĩa là +1 ULP .
Doval

2
@Doval Tôi nghĩ lý do cho điều đó là vì nhóm nòng cốt Haskell muốn [1 ..] có nghĩa tương tự với Nhân đôi mà nó có nghĩa với Ints.
dấu chấm phẩy

@semicolon nhân đôi và số float không phải là số thực (ví dụ: không thể lưu trữ PI thành một đôi mà không mất một số độ chính xác) vì vậy chúng là vô số
jk.

Câu trả lời:


8

Một ví dụ thực tế tôi thích đến từ thế giới ngôn ngữ lập trình: tập hợp các loại trong hệ thống OO bị ràng buộc và rời rạc nhưng không thể đếm được, và được đặt hàng một phần nhưng không được sắp xếp hoàn toàn.

Thứ tự một phần trong câu hỏi là mối quan hệ phụ <:. Giới hạn trên sau đó sẽ là loại trên cùng (mà C # gọi objectvà Scala gọi Any) và giới hạn dưới sẽ là loại dưới cùng (Scala's Nothing; C # / Java không có nghĩa tương đương để nói về).

Tuy nhiên, không có cách nào để liệt kê tất cả các loại trong hệ thống loại, vì vậy bạn không thể viết một instance Enum Type. Điều này cần phải rõ ràng: người dùng có thể viết các loại của riêng họ để không có cách nào biết trước họ sẽ làm gì. Bạn có thể liệt kê tất cả các loại trong bất kỳ chương trình nào, nhưng không phải trong toàn bộ hệ thống.

Tương tự như vậy, (theo một định nghĩa hợp lý nhất định của phân nhóm,) <:là phản xạ, bắc cầu và đối xứng nhưng không phải là tổng số . Có những cặp loại không liên quan đến nhau <:. ( CatDoglà cả hai kiểu con của Animal, nhưng không phải là kiểu con của cái kia.)


Giả sử rằng chúng ta đang viết một trình biên dịch cho một ngôn ngữ OO đơn giản. Đây là đại diện của các loại trong hệ thống của chúng tôi:

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

Và định nghĩa của mối quan hệ phụ:

(<:) :: 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

Điều này cũng cho chúng ta một mối quan hệ siêu.

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

Bạn cũng có thể tìm thấy giới hạn trên ít nhất của hai loại,

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

Bài tập: chỉ ra rằng Typehình thành một tư thế hoàn chỉnh giới hạn theo hai cách, dưới <:và dưới >:.


Thật sự cảm ơn! Điều đó trả lời hoàn toàn câu hỏi của tôi và cũng trả lời câu hỏi tiếp theo của tôi về Ord. Eq sẽ có vấn đề tương tự? Trong đó loại không tương đương có thể có maxBound hoặc minBound. Trong trường hợp này, Cat == Dog chỉ trả về false, vì chúng là các lớp khác nhau, hoặc sẽ không thể xác định được do vị trí của cây không đặt bên trên hoặc bên dưới cái kia?
dấu chấm phẩy

Một trật tự ngụ ý một sự bình đẳng - chỉ cần xác định x == y = x <= y && y <= x. Nếu tôi đang thiết kế một Posetlớp học tôi sẽ có class Eq a => Poset a. Google nhanh chóng xác nhận rằng những người khác cũng có ý tưởng tương tự .
Benjamin Hodgson

Xin lỗi câu hỏi của tôi là mơ hồ. Ý tôi là liệu Bounded có ngụ ý Eq ngay cả khi nó không ngụ ý Ord.
dấu chấm phẩy

@semicolon Một lần nữa không có mối quan hệ giữa hai lớp. Xem xét data Bound a = Min | Val a | Maxnhững gì tăng một loại avới +∞-∞các yếu tố. Bằng cách xây dựng Bound aluôn có thể được tạo thành một ví dụ Boundednhưng nó chỉ có thể tương đương nếu loại cơ bản a
Benjamin Hodgson

đủ công bằng Tôi đoán là một ví dụ có thể là chức năng mà mất và các giá trị trở lại của loại Double, nơi const (1/0)maxBoundconst (negate 1/0)minBoundnhưng \x -> 1 - x\x -> x - 1không thể so sánh.
dấu chấm phẩy

4

Đó là bởi vì các hoạt động là độc lập, do đó, buộc chúng cùng với một mối quan hệ lớp con không thực sự mua cho bạn bất cứ thứ gì. Giả sử bạn muốn tạo một loại tùy chỉnh đã triển khai Bounded, có thể Doublesbị ràng buộc giữa tối đa và tối thiểu, nhưng bạn không cần bất kỳ Enumthao tác nào. Nếu Boundedlà một lớp con, dù sao bạn cũng sẽ phải thực hiện tất cả các Enumhàm, chỉ để biên dịch nó.

Sẽ không có vấn đề gì nếu việc triển khai hợp lý cho Enumbất kỳ số lượng máy chữ nào khác. Nếu bạn không thực sự cần nó, bạn không nên bị buộc phải thực hiện nó.

Tương phản điều này với nói, OrdEq. Ở đó, các Ordhoạt động phụ thuộc vào các hoạt động Eq, vì vậy sẽ hợp lý khi yêu cầu lớp con để tránh trùng lặp và đảm bảo tính nhất quán.


1
Trong những trường hợp đó, đó là một phần của định nghĩa. Theo định nghĩa, tất cả các đơn nguyên cũng là người nộp đơn và functor, vì vậy bạn không thể thực hiện "hợp đồng" đơn nguyên mà không hoàn thành các đơn vị khác. Tôi không đủ quen thuộc với toán học để biết đó là mối quan hệ cơ bản hay định nghĩa áp đặt, nhưng dù sao đi nữa, chúng ta đang bị mắc kẹt với nó.
Karl Bielefeldt

6
@semicolon Tài liệu choBounded biết "Ord không phải là siêu lớp của Giới hạn vì các loại không hoàn toàn được đặt hàng cũng có thể có giới hạn trên và dưới."
Benjamin Hodgson

1
@BenjaminHodgson Thậm chí không nghĩ về các loại được đặt hàng một phần. +1 cho một ví dụ không bệnh lý và trích dẫn tài liệu.
Doval

1
@semicolon Một ví dụ về thứ tự một phần từ thế giới máy tính có thể được phân nhóm theo ngôn ngữ OO. Viết <:cho là một kiểu con của , ∀ T S. T <: S ∨ S <: Tkhông giữ (ví dụ int !<: bool ∧ bool !<: int:). Bạn có thể gặp phải điều này nếu bạn đang viết một trình biên dịch.
Benjamin Hodgson

1
@BenjaminHodgson ah ok. Vì vậy, ví dụ nếu A là siêu lớp của B và C, và D là lớp con của B và C, thì B và C không thể so sánh được nhưng A và D là max / min?
dấu chấm phẩy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.