Bạn chỉ nên sử dụng hai nhà xây dựng cho hai hình thể:
data Option = NoA String | WithA String Int
Tất nhiên, bạn nên cung cấp cho chúng những cái tên tốt hơn, dựa trên những gì mà họ đại diện. Các loại Phantom chắc chắn là quá mức cần thiết ở đây và tôi khuyên bạn nên tránh Either
- Left
và Right
không phải là các tên của hàm tạo bản dựng.
Nếu nó làm cho tinh thần để giải thích cả Hoặc chi nhánh của trường b là đại diện cho cùng một dữ liệu, sau đó bạn cần xác định một chức năng phản ánh cách giải thích này:
b :: Option -> MeaningOfB
b (NoA s) = ...
b (WithA t n) = ...
Nếu bạn có các lĩnh vực mà ở lại không cùng cho dù lựa chọn là gì, bạn nên tạo một kiểu dữ liệu mới với tất cả chúng, và đưa nó vào cả hai hàm tạo. Nếu bạn làm cho mỗi hàm tạo một bản ghi, bạn có thể cung cấp cho trường chung cùng tên trong mọi hàm tạo, để bạn có thể trích xuất nó từ bất kỳ giá trị Option
nào mà không cần phải khớp mẫu trên đó.
Về cơ bản, hãy suy nghĩ về những gì nó có nghĩa là cho chuỗi không có mặt: nó thay đổi gì về các trường khác và những gì vẫn giữ nguyên? Bất cứ thay đổi nào cũng nên đi vào các nhà thầu tương ứng; bất cứ điều gì vẫn như cũ nên được nhân tố ra thành loại riêng của nó. (Đây là một nguyên tắc thiết kế tốt nói chung!)
Nếu bạn đến từ nền OOP, bạn có thể nghĩ về điều này với lý do thay vì thừa kế - nhưng cố gắng không lấy tương tự quá xa.
Tôi không nghĩ rằng Haskell 2010 có bất kỳ thứ gì cho phép điều này trong giải pháp trước đây của bạn. Tôi sẽ đề nghị đi cho 'Một trong hai String (String, Int)', hoặc một loại isomorphic như 'dữ liệu Option = OptionA String | OptionB String Int', trong đó các hàm tạo có tên hợp lý. –
Để giải đáp tốt nhất điều này, điều quan trọng là phải biết ý nghĩa * gắn liền với 'a' và' b'. Tại sao đôi khi bạn không có 'a' (ví dụ: 'Không có gì')? Tại sao OK biểu diễn 'b' như một' String' * hoặc * một 'Int'? Tại sao bạn muốn thực thi hạn chế mà bạn đang nói đến? Điều này cho tôi ấn tượng ban đầu rằng 'b' không được xác định rõ. –