2013-04-04 46 views
8

Giả sử tôi có lớp sau:Haskell lớp kế thừa kiểu

class P a where 
    nameOf :: a -> String 

Tôi muốn tuyên bố rằng tất cả các trường của lớp này sẽ được tự động trường hợp của Show. Nỗ lực đầu tiên của tôi sẽ là như sau:

instance P a => Show a where 
    show = nameOf 

nỗ lực đầu tiên của tôi để đi theo con đường này ngày hôm qua dẫn đến một warren thỏ các phần mở rộng ngôn ngữ: trường tôi lần đầu tiên được biết đến bật trường hợp linh hoạt, các trường hợp sau đó undecidable, sau đó chồng chéo, và cuối cùng nhận được lỗi về khai báo cá thể chồng chéo. Tôi đã từ bỏ và quay trở lại để lặp lại mã. Tuy nhiên, điều này về cơ bản có vẻ giống như một nhu cầu rất đơn giản, và một trong đó phải dễ dàng hài lòng.

Vì vậy, hai câu hỏi:

  1. Có cách nào trivially dễ dàng để làm điều này mà tôi vừa bỏ lỡ?
  2. Tại sao tôi gặp sự cố chồng chéo? Tôi có thể thấy lý do tại sao tôi có thể cần UndecidableInstances, vì tôi dường như vi phạm điều kiện Paterson, nhưng không có trường hợp trùng lặp nào ở đây: không có trường hợp nào của P, kể cả. Tại sao người đánh máy lại tin rằng có nhiều trường hợp cho Show Double (như trường hợp trong ví dụ đồ chơi này)?
+3

Sự chồng chéo (và độ phân giải quá tải) được xác định bởi chỉ phần đầu thể hiện 'Hiển thị a', vì vậy nó thực sự trùng lặp với mỗi thể hiện' Hiển thị' khác. – augustss

+1

Giả sử bạn khai báo cá thể của 'P Int' và bạn đã có một cá thể cho' Hiển thị Int' để điều này sẽ dẫn đến các trường hợp chồng chéo cho Hiện. – Satvik

+0

@Satvik Chắc chắn, ngoại trừ việc tôi không có một phiên bản 'P Int' xung quanh. Tôi sẽ mong đợi một lỗi nếu tôi cố gắng tạo một 'P Int', nhưng không phải bằng cách tuyên bố rằng nó có thể tồn tại. – Impredicative

Trả lời

5

Bạn nhận được các trường hợp lỗi chồng chéo vì một số trường hợp lại P có thể có trường hợp khác của Show và sau đó trình biên dịch sẽ không thể để quyết định những người sử dụng. Nếu bạn có một phiên bản P cho Double thì bạn sẽ nhận được hai phiên bản Show cho Double: một cái chung của bạn và cái đã được khai báo trong thư viện cơ sở của Haskell. Cách lỗi này được kích hoạt được tuyên bố chính xác bởi @augustss trong các nhận xét đối với câu hỏi của bạn. Để biết thêm thông tin, hãy xem the specs.

Như bạn đã biết, không có cách nào để đạt được những gì bạn đang thử mà không cần UndecidableInstances. Khi bạn bật cờ đó, bạn phải hiểu rằng bạn đang chịu trách nhiệm của trình biên dịch để đảm bảo rằng sẽ không có bất kỳ trường hợp xung đột nào. Điều này có nghĩa là, tất nhiên, không được có bất kỳ trường hợp nào khác của Show được tạo trong thư viện của bạn. Điều này cũng có nghĩa là thư viện của bạn sẽ không xuất khẩu lớp P, điều này sẽ xóa khả năng người dùng của thư viện khai báo các trường hợp xung đột.

Nếu trường hợp của bạn bằng cách nào đó xung đột với những điều đã nói ở trên, đó là một dấu hiệu đáng tin cậy rằng phải có điều gì đó sai trái với nó. Và trên thực tế, có ...


Những gì bạn đang cố gắng đạt được là không chính xác trên tất cả. Bạn đang thiếu một số điểm quan trọng về Show typeclass, phân biệt nó từ cấu trúc như một phương pháp toString ngôn ngữ OO phổ biến:

  1. Từ Show's haddock:

    Kết quả của chương trình là một biểu Haskell đúng cú pháp chỉ chứa các hằng số, với các khai báo cố định có hiệu lực tại điểm mà kiểu được khai báo. Nó chỉ chứa các tên hàm dựng được định nghĩa trong kiểu dữ liệu, dấu ngoặc đơn và dấu cách.Khi sử dụng các trường xây dựng có gắn nhãn, dấu ngoặc, dấu phẩy, tên trường và dấu bằng cũng được sử dụng.

    Nói cách khác, việc khai báo một thể hiện của Show, không tạo ra biểu thức Haskell hợp lệ, là không chính xác.

  2. Với điều trên, bạn chỉ cần khai báo một thể hiện tùy chỉnh là Show khi loại cho phép chỉ đơn giản là lấy được nó.

  3. Khi loại không cho phép lấy được nó (ví dụ: GADT), nói chung bạn sẽ vẫn phải tuân theo các trường hợp loại cụ thể để tạo kết quả chính xác.

Vì vậy, nếu bạn cần hàm đại diện tùy chỉnh, bạn không nên sử dụng Show cho điều đó. Chỉ cần khai báo một lớp tùy chỉnh, ví dụ:

class Repr a where 
    repr :: a -> String 

và tiếp cận khai báo cá thể một cách có trách nhiệm.

+0

Tôi rất thận trọng khi chấp nhận câu trả lời này bởi vì tôi cảm thấy nó sai về mặt kỹ thuật một phần. Vấn đề không phải là một số trường hợp 'P' có các trường hợp khác của' Hiển thị': như đã lưu ý, có * là * không có trường hợp 'P'. 'augustss' đã giải thích vấn đề thực sự, liên quan đến cách chồng chéo được đánh giá. Nếu bạn sửa chữa nó, tôi sẽ rất vui khi được chấp nhận; Tôi lấy ý kiến ​​của bạn về việc sử dụng 'show'. – Impredicative

+0

@Impredicative Có lẽ tôi đã không làm cho bản thân mình rõ ràng, tôi đã cập nhật đoạn đầu tiên. –

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