MonadPlus
và Monoid
phụ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, MonadPlus
khô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 Monad
hoạ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 MonadPlus
có 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 MonadPlus
phải đáp ứng một hoặc cả hai luật bổ sung này.
Vậy thì Alternative
sao?
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í Functor
không phải là lớp cha Monad
cho đến năm 2015. Giờ đây, cuối cùng chúng ta đã có Applicative
dưới dạng lớp cha của Monad
GHC (nếu không chưa theo tiêu chuẩn ngôn ngữ.)
Hiệu quả, Alternative
là Applicative
những gì MonadPlus
phả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ó MonadPlus
và 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 = empty
luậ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 f
bằng mọi cách.
Tuy nhiên, vì Applicative
là không một lớp cha của Monad
và Alternative
là 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 Applicative
là một lớp cha Monad
, bạn vẫn cần đến MonadPlus
lớ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 MonadPlus
mạnh hơn tuyên bố nó là Alternative
.
Bây giờ, theo quy ước, MonadPlus
và Alternative
đối với một loại nhất định phải đồng ý, nhưng Monoid
có thể hoàn toàn khác.
Ví dụ MonadPlus
và Alternative
cho Maybe
làm điều rõ ràng:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
nhưng Monoid
trườ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 Semigroup
lớp vào thời điểm đó trong Haskell 98, nó làm như vậy bằng Monoid
cá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 MonadPlus
và các Alternative
trường hợp của một loại phải có liên quan với nhau, thì Monoid
có thể (và đôi khi là) một cái gì đó hoàn toàn khác.
Applicative
vàMonadPlus
dường như hoàn toàn giống nhau (ràng buộc siêu lớp modulo).