To begin with, let me offer short answers to each of these questions. Then I will analyze each in a more detailed answer, but these short ones, we hope, will help in navigating through them.
No, Alternative and Monoid do not mean different things; Alternative for types that have both Applicative and Monoid . āGatheringā and āunificationā are two different intuitions for the same broader concept.
Alternative contains empty , as well as <|> because the designers thought it would be useful, and because it leads to a monoid. As for the choice, empty corresponds to the impossible choice.
We need both Alternative and Monoid , because the former obeys (or should) more laws than the latter; these laws connect the monoidal and applicative structure of the type constructor. In addition, Alternative does not depend on the internal type, but on Monoid .
MonadPlus slightly stronger than Alternative , as it must obey more laws; these laws link the monoidal structure with the monadic structure in addition to the applicative structure. If you have instances of both, they must match.
Does Alternative mean something completely different from Monoid ?
Not really! Part of the reason for your confusion is that the Haskell Monoid class uses pretty good (well, not enough generic) names. So a mathematician would define a monoid (being very explicit in it):
Definition A monoid is a set M equipped with a marked element ε ā M and a binary operator: M Ć M ā M, denoted by a map, so the following two conditions are true:
- ε is the identity: for all m ā M, mε = εm = m.
- Ā· Is associative: for all mā, mā, mā ā M, (māmā) mā = mā (māmā).
Here it is. Haskell ε writes mempty and · writes mappend (or, these days, <> ), and the set M is a type M in instance Monoid M where ...
Looking at this definition, we see that he does not say anything about āunificationā (or about ācollectionā, for that matter). He talks about things and about ε, but it is. Now, it is certainly true that combining things works well with this structure: ε corresponds to the absence of things, and māmā says that if I swallow mā and mās together, I can get a new thing containing all their things. But heres an alternative intuition: ε does not correspond to any choices, and māmā corresponds to the choice between mā and mā. This is a āgatheringā intuition. Note that both obey monoid laws:
- Having nothing and having no choice, they are identical.
- If I donāt have the material and smooth it along with some things, I get the same thing again.
- If I have a choice between a choice at all (something impossible) and some other choice, I have to choose another (possible) choice.
- Joint collection and selection are both associative.
- If I have three collections of things, it does not matter if I glom the first two together, then the third, or the last two together, and then the first; anyway, I get the same general collection.
- If I have a choice between three things, it does not matter if I (a) first choose between the first and second and third, and then, if I need, between the first and second or (b) first choose between the first and second or third and then, if necessary, between the second and third. In any case, I can choose what I want.
(Note: Im plays quickly and freely here, thatās why his intuition is. For example, itās important to remember that Ā· does not have to be commutative, which is higher than this gloss: it is possible that m mā ā māmā.)
Well, both of these kinds of things (and many others) - this is the multiplication of numbers that really "combine" or "gather"?) Obey the same rules. The presence of intuition is important for the development of understanding, but its rules and definitions that determine what actually happens.
And most importantly, both of these intuitions can be interpreted by the same carrier! Let M be some set of sets (and not the set of all sets!) Containing an empty set, let ε be an empty set ā
, and let be a union āŖ be given. It is easy to see that ā
is an identity for āŖ and that āŖ is associative, so we can conclude that (M, ā
, āŖ) is a monoid. Now:
- If we think of sets as collections of things, then āŖ corresponds to their volume in order to get more things - a ācombination" of intuition.
- If we think of sets as possible actions, then āŖ corresponds to an increase in your pool of possible actions to choose from the āintuitionā of choice.
And this is exactly what happens with [] in Haskell: [a] is Monoid for all a , and [] as an applied functor (and monad) is used to represent non-determinism. Both the combination and the collecting intuition coincide in one type: mempty = empty = [] and mappend = (<|>) = (++) .
Thus, the Alternative class is designed to represent objects that (a) are applicative functors, and (b) when creating an instance in a type, they also have a binary function that follows certain rules. What are the rules? Monoid rules. What for? Because it turns out to be useful :-)
Why does Alternative need an empty method / member?
Well, the snarky answer is "because Alternative represents a monoid structure." But the real question is: why is the monoid structure? Why not just a semigroup, a monoid without ε? One of them is to argue that monoids are more useful. I think many people (but maybe not Edward Kemt ) would agree with this; almost all the time, if you have a reasonable (<|>) / mappend / ·, you can define a reasonable empty / mempty / ε. On the other hand, the presence of additional commonality is pleasant, since it allows you to place more things under the umbrella.
You also want to know how this relates to āgatheringā intuition. Bearing in mind that in a sense, the correct answer is āI know when to abandonā collecting intuition, āI think you can combine them. Consider [] , the applicative functor for non-determinism. If I combine two values āāof type [a] with (<|>) , which corresponds to a non-deterministic choice of either an action on the left or an action on the right. But sometimes you will not have any possible actions on the one hand - and this is fine. Similarly, if we consider parsers, (<|>) is a parser which analyzes either that on the left, or something on the right (it āchooses.ā) And if you have a parser that always fails, it becomes a person: if you select it, you will immediately reject this choice and try another.
All of this said, remember that it is entirely possible to have a class that is almost similar to Alternative but not empty . That would be entirely believable - it could even be an Alternative superclass, but not the way Haskell did. Presumably, this is unaware of what is useful.
Why does an Alternative class need Applicative constraint and why does it need * -> * ? ... Why not just [use] liftA2 mappend ?
Well, consider each of these three proposed changes: getting rid of the Applicative constraint for Alternative ; changing the type of the argument Alternative s; and using liftA2 mappend instead of <|> and pure mempty instead of empty . Take a good look at this third change at first, as it is very different. Suppose we completely got rid of Alternative and replaced the class with two simple functions:
fempty :: (Applicative f, Monoid a) => fa fempty = pure mempty (>|<) :: (Applicative f, Monoid a) => fa -> fa -> fa (>|<) = liftA2 mappend
We could even keep the definitions of some and many . And this gives us a monoid structure, its truth. But it looks like it gives us the wrong one. Should Just fst >|< Just snd fail because (a,a) -> a not an instance of Monoid ? No, but this is what would lead to the code above. The monoid instance we want is one that is agnostic of the internal type (to use the terminology of Matthew Farkas-Dyck in a very related discussion on haskell-cafe , which asks some very similar questions); The Alternative structure is a monoid defined by the structure of f s rather than the structure of the argument f s.
Now that we think that we want to leave Alternative as a kind of type class, consider the two proposed ways to change it. If we change the view, we need to get rid of the Applicative constraint; Applicative only talks about things of the genus * -> * , and therefore theres no way to refer to it. This leaves two possible changes; The first, more minor change is to get rid of the Applicative constraint, but leave only one:
class Alternative' f where empty' :: fa (<||>) :: fa -> fa -> fa
Another, bigger change is to get rid of the Applicative constraint and change the look:
class Alternative'' a where empty'' :: a (<|||>) :: a -> a -> a
In both cases, we need to get rid of some / many , but that's OK; we can define them as autonomous functions with the type (Applicative f, Alternative' f) => fa -> f [a] or (Applicative f, Alternative'' (f [a])) => fa -> f [a] .
Now, in the second case, when we change the type of a variable of type, we see that our class is exactly the same as Monoid (or if you still want to remove empty'' , Semigroup ), so they have no advantage of having a separate class. And in fact, even if you leave only a view variable, but remove the Applicative constraint, Alternative will simply become forall a. Monoid (fa) forall a. Monoid (fa) , although we cannot write these quantitative restrictions in Haskell, not even with all the fantastic GHC extensions. (Note that this expresses the agnosticism of the internal type mentioned above). Thus, if we can make one of these changes, then we have no reason to keep Alternative (except for the possibility of expressing this quantitative restriction, but this hardly seems convincing).
So the question boils down to "is there a connection between the Alternative and Applicative parts of f , which is an instance of both?" And while there is nothing in the documentation, Iām going to get up and say yes, or at least it should be. I think Alternative should be subject to some Applicative laws (in addition to monoid laws); in particular, I think these laws are similar to
- Correct distribution (
<*> ): (f <|> g) <*> a = (f <*> a) <|> (g <*> a) - Correct absorption (for
<*> ): empty <*> a = empty - Left distribution (
fmap ): f <$> (a <|> b) = (f <$> a) <|> (f <$> b) - Left absorption (for
fmap ): f <$> empty = empty
These laws are true for [] and Maybe , and (pretending that its instance of MonadPlus is an instance of Alternative ) IO , but I did not do any evidence or exhaustive testing. (For example, I initially believed that left-handed distribution is supported for <*> , but it "performs effects" in the wrong order for [] .) However, by analogy, it is true that MonadPlus is expected to obey similar laws (although there are, apparently , some kind of ambiguity about which ). I originally wanted to demand a third law that seems natural:
- Left absorption (for
<*> ): a <*> empty = empty
However, although I believe that [] and Maybe are subject to this law, IO doesnt, and I think (for reasons that will become apparent in the following paragraphs), it is best not to require this.
Indeed, it seems that Edward Kmett has several slides where he has a similar opinion; To understand this, you need to take a brief digression, which involves even more mathematical jargon. The final slide āI want more structureā says that āthe monoid refers to the applicative, like the right sevenfold, to the alternativeā and āIf you throw away the argument of the applicative, you will get the monoid, if you throw away the argument of the Alternative you get RightSemiNearRing.
Right sevens? "How did the right testicles enter into it?" I hear you cry. Well,
Definition . The right-angled semiring (also right semantiping, but the former seems to be used more by Google) is a quadruple (R, +, Ā·, 0), where (R, +, 0) is a monoid, (R, Ā·) is a semigroup and the following two conditions:
- Ā· Is a right distribution over +: for all r, s, t ā R, (s + t) r = sr + tr.
- 0 is the right absorption for :: for all r ā R, 0r = 0.
The left half-published is defined similarly.
Now this does not work, because <*> not really an associative or binary operator - the types do not match. I think this is what Edward Kmett is referring to when he speaks of "rejection of the argument." Another option would be to say (Im unsure, if that's right) that we really want ( fa , <|> , <*> , empty ) to form a right half-moon, where the suffix "-oid" indicates that binary operators can only be applied to specific pairs of elements (Ć la groupoids ). And wed also want to say that ( fa , <|> , <$> , empty ) was left almost semi-realistic, although it would probably follow from a combination of Applicative laws and right-hand short-range order, semi-realistic structure. But now I am above my head, and this does not really matter much.
In any case, these laws, being stronger than the monoid laws, mean that perfectly valid Monoid instances become invalid Alternative instances. There are (at least) two examples in the standard library: Monoid a => (a,) and Maybe . Let's look at each of them quickly.
Given any two monoids, their product is a monoid; therefore, tuples can be made in the obvious way of a Monoid instance (reformatting the source of the base packages ):
instance (Monoid a, Monoid b) => Monoid (a,b) where mempty = (mempty, mempty) (a1,b1) `mappend` (a2,b2) = (a1 `mappend` a2, b1 `mappend` b2)
Similarly, we can create tuples whose first component is a monoid element in an Applicative instance by accumulating monoid elements (reformatting the base source packages ):
instance Monoid a => Applicative ((,) a) where pure x = (mempty, x) (u, f) <*> (v, x) = (u `mappend` v, fx)
However, tuples are an instance of Alternative , because they cannot be: the monoidal structure over Monoid a => (a,b) not present for all types of b , and the monoidal structure of Alternative must be an agnostic of internal type. It is not necessary b be a monad to express (f <> g) <*> a , we need to use a Monoid instance for functions, which for functions of the form Monoid b => a -> b . And even in the case when we have all the necessary monoidal structure, it violates all four Alternative laws. To verify this, let ssf n = (Sum n, (<> Sum n)) and let ssn = (Sum n, Sum n) . Then, typing (<>) for mappend , we get the following results (which can be checked in GHCi with random type annotation):
- Proper distribution:
(ssf 1 <> ssf 1) <*> ssn 1 = (Sum 3, Sum 4)(ssf 1 <*> ssn 1) <> (ssf 1 <*> ssn 1) = (Sum 4, Sum 4)
- Proper absorption:
mempty <*> ssn 1 = (Sum 1, Sum 0)mempty = (Sum 0, Sum 0)
- Left distribution:
(<> Sum 1) <$> (ssn 1 <> ssn 1) = (Sum 2, Sum 3)((<> Sum 1) <$> ssn 1) <> ((<> Sum 1) <$> ssn 1) = (Sum 2, Sum 4)
- Left suction:
(<> Sum 1) <$> mempty = (Sum 0, Sum 1)mempty = (Sum 1, Sum 1)
Then consider Maybe . Be that as it may, Maybe s Monoid and Alternative instances disagree. ( haskell-cafe , , theres a Option newtype , .) Monoid , Maybe , Nothing ; , , ( ):
instance Monoid a => Monoid (Maybe a) where mempty = Nothing Nothing `mappend` m = m m `mappend` Nothing = m Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)
, Alternative , Maybe , ( ):
instance Alternative Maybe where empty = Nothing Nothing <|> r = r l <|> _ = l
, Alternative . Monoid , (,) s; <*> , - Monoid , ( ) , , ( ), , <*> Alternative , Monoid , fmap . fmap Alternative :
f <$> (Nothing <|> b) = f <$> b by the definition of (<|>) = Nothing <|> (f <$> b) by the definition of (<|>) = (f <$> Nothing) <|> (f <$> b) by the definition of (<$>) f <$> (Just a <|> b) = f <$> Just a by the definition of (<|>) = Just (fa) by the definition of (<$>) = Just (fa) <|> (f <$> b) by the definition of (<|>) = (f <$> Just a) <|> (f <$> b) by the definition of (<$>)
Monoid ; (<>) mappend , :
(<> Sum 1) <$> (Just (Sum 0) <> Just (Sum 0)) = Just (Sum 1)((<> Sum 1) <$> Just (Sum 0)) <> ((<> Sum 1) <$> Just (Sum 0)) = Just (Sum 2)
. Alternative <*> , <$> , Maybe . , , <$> , , ; , -, .
, , a Alternative , a Monoid , . Monoid Applicative , ; , . ( , Id .) , , .
MonadPlus ?
MonadPlus , Alternative , Monoid , Monad Applicative . " MonadPlus , Alternative Monoid ?" , MonadPlus , Alternative : , empty <*> a , empty >>= f . AndrewC : Maybe . , MonadPlus . , MonadPlus mplus mempty , , mempty >>= f = mempty . Hhowever, MonadPlus ses , mplus ab >>= f = mplus (a >>= f) (b >>= f) ; , mplus (return a) b = return a . (, / MonadPlus / Alternative ; (<*>) (=<<) (>>=) .) , , "", MonadPlus , , Maybe , Alternative , MonadPlus . , newtype Maybe , Alternative : a <|> Just b = Just b . , , Alternative .
, , MonadPlus , , Alternative ( , , , ap (<*>) Monad , Applicative s), MonadPlus
class (Monad m, Alternative m) => MonadPlus' m
; , empty (<|>) . Haskell, ; , lattices , , lattice - , , .
, Alternative , , Alternative Monoid , - .
class (Applicative f, forall a. Monoid (fa)) => Alternative''' f
( ) GHC Haskell .
, , Alternative MonadPlus , Applicative Monad , , . , WrappedMonad newtype, Monad Applicative ; theres instance MonadPlus m => Alternative (WrappedMonad m) where ... , , .