2011-08-26 18 views
27

Một số chiếc nhẫn có thể được trang bị với một chức năng tiêu chuẩn:Haskell Hạn chế là không nhỏ hơn so với đầu dụ

class (Ring.C a) => EuclideanDomain a where 
    norm :: a -> Integer 

Với chức năng này, chiếc nhẫn có thể được sắp xếp theo một cách rõ ràng:

compare x y = compare (norm x) (norm y) 

Nhưng tôi không chắc chắn làm thế nào để chỉ ra điều này. Tôi cố gắng để làm

instance (EuclideanDomain a, Eq a) => Ord a where 

nhưng điều này mang lại cho tôi một số cảnh báo, và khi tôi cho phép cờ biên dịch có liên quan nó nói với tôi "Hạn chế là không nhỏ hơn so với đầu dụ" - nếu tôi bật UndecidableInstances tất cả mọi thứ đi vào địa ngục.

Có cách nào để làm những gì tôi muốn không?

Trả lời

23

Để tránh các vòng lặp vô hạn, trình biên dịch thường yêu cầu các ràng buộc của một cá thể là "nhỏ hơn" so với bản thân cá thể, do đó thuật toán sẽ chấm dứt. Ví dụ của bạn không làm cho a bất kỳ nhỏ hơn nào trong các ràng buộc, do đó, đó là những gì trình biên dịch phàn nàn.

Việc mở rộng UndecidableInstances sẽ hạn chế hạn chế này, tùy thuộc vào bạn để chứng minh rằng nó sẽ chấm dứt. Do đó, có thể gửi trình biên dịch vào một vòng lặp vô hạn khi sử dụng phần mở rộng này.

Các giải pháp chung cho điều này là thêm một newtype:

newtype ByNorm a = ByNorm a 

instance (EuclideanDomain a, Eq a) => Ord (ByNorm a) where 
    compare (ByNorm x) (ByNorm y) = compare (norm x) (norm y) 

Bây giờ những hạn chế nhỏ hơn đầu Ví dụ, khi chúng lột các newtype. Không cần gia hạn.

+1

Có nghĩa là gì đối với các ràng buộc nhỏ hơn? Chắc chắn có ít 'EuclideanDomain a' sau đó có 'a' s? – Xodarap

+4

@Xodarap: Nhỏ hơn như trong "được bao bọc trong các trình tạo kiểu ít hơn", không giống như "ít giá trị của loại này" hơn. – hammar

+0

Tôi hiểu. Khi tôi thử những gì bạn đặt ở đây và sau đó 'f :: EuclideanDomain a => a -> Thứ tự',' f x = so sánh x x' nó không biên dịch. Tôi đang thiếu gì? – Xodarap

27

hammar đã cung cấp giải pháp; Tôi muốn chỉ ra một vấn đề khác với ví dụ này. Những gì bạn muốn thể hiện là "Bất cứ khi nào một loại là một thể hiện của EqEuclideanDomain, hãy sử dụng quy tắc này để tạo một phiên bản cho Ord". Nhưng điều này là không thể diễn tả trong Haskell. Dòng

instance (EuclideanDomain a, Eq a) => Ord a where 

thực sự có nghĩa là, "Sử dụng quy tắc này để tạo một thể hiện Ord cho bất kỳ loại. Đây là một lỗi nếu trường hợp của EuclideanDomainEq đang không ở trong phạm vi". Điều đó không tốt, bởi vì quy tắc này sẽ chồng lấp với mọi cá thể Ord khác.

Về cơ bản bất kỳ lúc nào bạn muốn viết một thể hiện Class typevar, bạn sẽ cần một kiểu mới.

+1

Cảm ơn! Điều này làm cho nó rõ ràng hơn vấn đề là gì. – Xodarap

Các vấn đề liên quan