Tôi sẽ sử dụng một mô tả không biết ngôn ngữ của các đơn nguyên như thế này, đầu tiên mô tả các đơn sắc:
Một monoid là (đại khái) một tập hợp các hàm lấy một số loại làm tham số và trả về cùng loại.
Một đơn nguyên là (đại khái) một tập hợp các hàm lấy một loại trình bao bọc làm tham số và trả về cùng một loại trình bao bọc.
Lưu ý đó là những mô tả, không phải định nghĩa. Hãy tấn công mô tả đó!
Vì vậy, trong ngôn ngữ OO, một đơn vị cho phép các tác phẩm hoạt động như:
Flier<Duck> m = new Flier<Duck>(duck).takeOff().flyAround().land()
Lưu ý rằng đơn nguyên xác định và kiểm soát ngữ nghĩa của các hoạt động đó, chứ không phải là lớp chứa.
Theo truyền thống, trong ngôn ngữ OO, chúng tôi sẽ sử dụng hệ thống phân cấp & kế thừa lớp để cung cấp các ngữ nghĩa đó. Vì vậy, chúng tôi muốn có một Bird
lớp học với phương pháp takeOff()
, flyAround()
và land()
, và vịt sẽ kế thừa những.
Nhưng sau đó chúng tôi gặp rắc rối với những con chim không biết bay, vì penguin.takeOff()
thất bại. Chúng tôi phải dùng đến ngoại lệ ném và xử lý.
Ngoài ra, một khi chúng ta nói rằng Penguin là một Bird
, chúng ta gặp vấn đề với nhiều kế thừa, ví dụ nếu chúng ta cũng có một hệ thống phân cấp Swimmer
.
Về cơ bản, chúng tôi đang cố gắng đưa các lớp vào các danh mục (với lời xin lỗi đến các Lý thuyết Danh mục) và xác định ngữ nghĩa theo danh mục thay vì trong các lớp riêng lẻ. Nhưng các đơn vị dường như là một cơ chế rõ ràng hơn nhiều để làm điều đó hơn là hệ thống phân cấp.
Vì vậy, trong trường hợp này, chúng ta sẽ có một Flier<T>
đơn nguyên như ví dụ trên:
Flier<Duck> m = new Flier<Duck>(duck).takeOff().flyAround().land()
... và chúng tôi sẽ không bao giờ khởi tạo a Flier<Penguin>
. Chúng tôi thậm chí có thể sử dụng kiểu gõ tĩnh để ngăn điều đó xảy ra, có thể với giao diện đánh dấu. Hoặc kiểm tra khả năng thời gian chạy để bảo lãnh. Nhưng thực sự, một lập trình viên không bao giờ nên đặt Penguin vào Flier, theo nghĩa tương tự họ không bao giờ nên chia cho số không.
Ngoài ra, nó thường được áp dụng. Một phi công không phải là một con chim. Ví dụ Flier<Pterodactyl>
, hoặc Flier<Squirrel>
, không thay đổi ngữ nghĩa của các loại riêng lẻ đó.
Khi chúng tôi phân loại ngữ nghĩa theo các hàm có thể kết hợp trên một thùng chứa - thay vì theo phân cấp kiểu - nó sẽ giải quyết các vấn đề cũ với các lớp "loại làm, loại không" phù hợp với hệ thống phân cấp cụ thể. Nó cũng dễ dàng & rõ ràng cho phép nhiều ngữ nghĩa cho một lớp, Flier<Duck>
cũng như Swimmer<Duck>
. Có vẻ như chúng tôi đã phải vật lộn với sự không phù hợp trở kháng bằng cách phân loại hành vi với hệ thống phân cấp lớp. Monads xử lý nó một cách thanh lịch.
Vì vậy, câu hỏi của tôi là, giống như cách chúng ta đến để ủng hộ sáng tác hơn thừa kế, nó cũng có ý nghĩa để ủng hộ các đơn vị hơn thừa kế?
(BTW Tôi không chắc liệu điều này nên ở đây hay trong Comp Sci, nhưng điều này có vẻ giống như một vấn đề mô hình thực tế. Nhưng có lẽ nó tốt hơn ở đó.)