MonadPlusvà Monoidphục vụ các mục đích khác nhau.
A Monoidđược tham số hóa trên một kiểu loại *.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
và do đó, nó có thể được khởi tạo cho hầu hết mọi kiểu mà có toán tử hiển nhiên là liên kết và có đơn vị.
Tuy nhiên, MonadPluskhông chỉ chỉ định rằng bạn có cấu trúc đơn nguyên, mà cấu trúc đó còn liên quan đến cách Monadhoạt động và cấu trúc đó không quan tâm đến giá trị chứa trong đơn nguyên, điều này (một phần) được chỉ ra bởi thực tế rằng MonadPluscó một đối số của loại hình * -> *.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
Ngoài các luật đơn nguyên, chúng ta có hai bộ luật tiềm năng mà chúng ta có thể áp dụng MonadPlus. Đáng buồn thay, cộng đồng không đồng ý về những gì họ nên là.
Ít nhất chúng ta biết
mzero >>= k = mzero
nhưng có hai phần mở rộng cạnh tranh khác, luật phân phối bên trái (sic)
mplus a b >>= k = mplus (a >>= k) (b >>= k)
và luật bắt trái
mplus (return a) b = return a
Vì vậy, bất kỳ trường hợp nào của MonadPlusphải đáp ứng một hoặc cả hai luật bổ sung này.
Vậy thì Alternativesao?
Applicativeđược định nghĩa sau Monad, và về mặt logic thuộc về một lớp cha của Monad, nhưng phần lớn là do những áp lực khác nhau đối với các nhà thiết kế trong Haskell 98, thậm chí Functorkhông phải là lớp cha Monadcho đến năm 2015. Giờ đây, cuối cùng chúng ta đã có Applicativedưới dạng lớp cha của MonadGHC (nếu không chưa theo tiêu chuẩn ngôn ngữ.)
Hiệu quả, Alternativelà Applicativenhững gì MonadPlusphải làm Monad.
Đối với những điều này, chúng tôi sẽ nhận được
empty <*> m = empty
tương tự như những gì chúng tôi có MonadPlusvà tồn tại các thuộc tính phân phối và bắt tương tự, ít nhất một trong số đó bạn nên đáp ứng.
Thật không may, ngay cả empty <*> m = emptyluật pháp cũng là một yêu sách quá mạnh. Nó không giữ cho BackwardVí dụ, !
Khi chúng ta nhìn vào MonadPlus, định luật rỗng >> = f = rỗng gần như bị ép buộc đối với chúng ta. Cấu trúc trống không thể có bất kỳ 'a's nào trong đó để gọi hàm fbằng mọi cách.
Tuy nhiên, vì Applicativelà không một lớp cha của Monadvà Alternativelà không một lớp cha của MonadPlus, chúng tôi gió lên xác định cả hai trường hợp riêng biệt.
Hơn nữa, ngay cả khi Applicativelà một lớp cha Monad, bạn vẫn cần đến MonadPluslớp đó, bởi vì ngay cả khi chúng ta tuân theo
empty <*> m = empty
điều đó không đủ nghiêm ngặt để chứng minh rằng
empty >>= f = empty
Vì vậy, tuyên bố rằng một cái gì đó là a MonadPlusmạnh hơn tuyên bố nó là Alternative.
Bây giờ, theo quy ước, MonadPlusvà Alternativeđối với một loại nhất định phải đồng ý, nhưng Monoidcó thể hoàn toàn khác.
Ví dụ MonadPlusvà Alternativecho Maybelàm điều rõ ràng:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
nhưng Monoidtrường hợp nâng một nhóm bán thành một Monoid. Đáng buồn là vì không tồn tại một Semigrouplớp vào thời điểm đó trong Haskell 98, nó làm như vậy bằng Monoidcách sử dụng a , nhưng không sử dụng đơn vị của nó. ಠ_ಠ
instance Monoid a => Monoid (Maybe a) where
mempty = Nothing
mappend (Just a) (Just b) = Just (mappend a b)
mappend Nothing x = x
mappend x Nothing = x
mappend Nothing Nothing = Nothing
TL; DR MonadPlus là một xác nhận quyền sở hữu mạnh hơn Alternative, ngược lại là một xác nhận quyền sở hữu mạnh hơn Monoid, và trong khi các MonadPlusvà các Alternativetrường hợp của một loại phải có liên quan với nhau, thì Monoidcó thể (và đôi khi là) một cái gì đó hoàn toàn khác.
ApplicativevàMonadPlusdường như hoàn toàn giống nhau (ràng buộc siêu lớp modulo).