Tôi hiểu tại sao bạn muốn làm điều này, nhưng không may, nó có thể chỉ là ảo tưởng rằng các lớp Haskell dường như "mở" theo cách bạn nói. Nhiều người cảm thấy rằng khả năng làm điều này là một lỗi trong đặc tả Haskell, vì những lý do tôi sẽ giải thích bên dưới. Dù sao, nếu nó thực sự không phù hợp với trường hợp bạn cần được khai báo trong mô-đun nơi lớp được khai báo hoặc trong mô-đun nơi kiểu được khai báo, đó có thể là dấu hiệu cho thấy bạn nên sử dụng một newtype
hoặc một số trình bao bọc khác xung quanh loại của bạn.
Các lý do tại sao các thể hiện mồ côi cần phải tránh sâu xa hơn sự tiện lợi của trình biên dịch. Chủ đề này khá gây tranh cãi, như bạn có thể thấy từ các câu trả lời khác. Để cân bằng cuộc thảo luận, tôi sẽ giải thích quan điểm rằng không bao giờ nên viết các trường hợp mồ côi, mà tôi nghĩ đó là ý kiến đa số của các Haskellers có kinh nghiệm. Ý kiến riêng của tôi là ở đâu đó ở giữa, mà tôi sẽ giải thích ở phần cuối.
Vấn đề bắt nguồn từ thực tế là khi tồn tại nhiều hơn một khai báo cá thể cho cùng một lớp và kiểu, không có cơ chế nào trong Haskell tiêu chuẩn để chỉ định cái nào sẽ sử dụng. Đúng hơn, chương trình bị trình biên dịch từ chối.
Hiệu ứng đơn giản nhất của việc đó là bạn có thể có một chương trình đang hoạt động hoàn hảo đột ngột ngừng biên dịch do một người khác thực hiện thay đổi trong một số phụ thuộc xa vào mô-đun của bạn.
Thậm chí tệ hơn, có thể một chương trình đang làm việc bắt đầu gặp sự cố trong thời gian chạy vì một sự thay đổi xa. Bạn có thể đang sử dụng một phương thức mà bạn đang giả định đến từ một khai báo phiên bản nhất định và nó có thể được thay thế một cách âm thầm bằng một phiên bản khác đủ khác để khiến chương trình của bạn bắt đầu gặp sự cố không thể giải thích được.
Những người muốn đảm bảo rằng những vấn đề này sẽ không bao giờ xảy ra với họ phải tuân theo quy tắc rằng nếu bất kỳ ai, ở bất kỳ đâu, đã từng khai báo một thể hiện của một lớp nhất định cho một kiểu nhất định, thì không có trường hợp nào khác phải được khai báo lại trong bất kỳ chương trình nào được viết bởi bất cứ ai. Tất nhiên, có một cách giải quyết là sử dụng một newtype
để khai báo một phiên bản mới, nhưng đó luôn là một sự bất tiện nhỏ và đôi khi là một sự bất tiện lớn. Vì vậy, theo nghĩa này, những người cố tình viết các trường hợp mồ côi là khá bất lịch sự.
Vì vậy, những gì nên được làm cho vấn đề này? Trại chống cá thể mồ côi nói rằng cảnh báo GHC là lỗi, nó cần phải là lỗi từ chối mọi nỗ lực khai báo cá thể mồ côi. Trong khi chờ đợi, chúng ta phải thực hiện kỷ luật tự giác và tránh chúng bằng mọi giá.
Như bạn đã thấy, có những người không quá lo lắng về những vấn đề tiềm ẩn đó. Họ thực sự khuyến khích việc sử dụng các trường hợp mồ côi như một công cụ để tách các mối quan tâm, như bạn đề xuất, và nói rằng người ta chỉ nên đảm bảo trong từng trường hợp cụ thể rằng không có vấn đề gì. Tôi đã gặp nhiều bất tiện trước những trường hợp mồ côi của người khác để tin rằng thái độ này là quá ung dung.
Tôi nghĩ giải pháp phù hợp sẽ là thêm một phần mở rộng vào cơ chế nhập của Haskell để kiểm soát việc nhập các phiên bản. Điều đó sẽ không giải quyết được hoàn toàn các vấn đề, nhưng nó sẽ mang lại một số trợ giúp nhằm bảo vệ các chương trình của chúng tôi khỏi thiệt hại từ các cá thể mồ côi đã tồn tại trên thế giới. Và sau đó, theo thời gian, tôi có thể tin rằng trong một số trường hợp hạn chế nhất định, có lẽ một trường hợp mồ côi có thể không tệ như vậy. (Và chính sự cám dỗ đó là lý do khiến một số người trong trại chống trẻ mồ côi phản đối đề xuất của tôi.)
Kết luận của tôi từ tất cả những điều này là ít nhất vào lúc này, tôi thực sự khuyên bạn nên tránh khai báo bất kỳ trường hợp mồ côi nào, hãy quan tâm đến người khác nếu không vì lý do nào khác. Sử dụng a newtype
.