Confused by the meaning of the class "Alternative" and its relation to other types of classes

I am studying Typeclassopedia to learn type classes. I'm stuck in understanding Alternative (and MonadPlus , for that matter).

The problems that I have are:

  • ā€œpedia says thatā€œ an alternative class is intended for applicative functors that also have a monoid structure. ā€I don’t understand if the alternative means something completely different from Monoid? i.e. I understood the meaning of an Alternative class as a choice between two things, while I realized that monoids are connected with the unification of things.

  • why does Alternative need a method / member empty ? I may be mistaken, but it seems that it is not used at all ... at least in the code that I could find. And that doesn't seem to fit the topic of the class - if I have two things and need to choose one, why do I need an "empty" for?

  • why does an alternative type class need an applicative restriction and why does it need * -> * ? Why not just <|> :: a -> a -> a ? All instances can still be implemented in the same way ... I think (not sure). What value does it give that Monoid does not?

  • what is the point of a class like MonadPlus ? Can't I unlock all of his kindness just by using something like Monad and Alternative ? Why not just stop him? (I'm sure I'm wrong, but I have no counterexamples)

We hope that all these issues will be agreed ...!




Bounty Update: @ The answer to the question is a great start, but Q3 is still open: what does the alternative suggest that Monoid does not? I find this answer unsatisfactory because it lacks concrete examples, as well as a specific discussion of how the higher class Alternative distinguishes it from Monoid.

If it combines applicative effects with Monoid behavior, why not just:

 liftA2 mappend 

This is even more confusing for me, because many Monoid instances are exactly the same as alternate instances.

That's why I'm looking for specific examples that show why an alternative is needed and how it differs - or means something else - from Monoid.

+54
haskell typeclass
Oct 26 '12 at 4:11
source share
5 answers

I will not consider MonadPlus, because there is a disagreement with its laws.




After trying to find impossible examples in which the applicator structure naturally leads to an alternative instance that is not consistent with its Monoid * instance, I finally came up with the following:

Alternative laws are more strict than Monoid, because the result cannot depend on the internal type. This eliminates a large number of Monoid instances from alternatives. These data types allow partial (which means that they work only for some internal types). Monoid instances that are prohibited by an additional "structure" of the type * -> * . Examples:

  • the standard Maybe instance for Monoid assumes the internal type is Monoid => not an alternative

  • ZipLists, tuples, and functions can be made by Monoids if their internal types are monoids => no alternatives

  • sequences having at least one element cannot be alternatives because there is no empty :

     data Seq a = End a | Cons a (Seq a) deriving (Show, Eq, Ord) 

On the other hand, some data types cannot be made by Alternatives, as they are * -kinded:

  • unit - ()
  • Ordering
  • numbers, booleans

My conclusion: for types having both an Alternative instance and a Monoid instance should be the same. See also this answer .




excluding Maybe that I say is not taken into account, because its standard instance should not require Monoid for the internal type, in which case it will be identical to Alternative

+5
Oct 31
source share

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 ... , , .

+68
26 . '12 6:03
source share
 import Data.Monoid import Control.Applicative 

, Monoid Alternative Maybe ZipList , , , , , , , ghci , !

 (<>) :: Monoid a => a -> a -> a (<>) = mappend -- I'll be using <> freely instead of `mappend`. 

:

 data Perhaps a = Yes a | No deriving (Eq, Show) instance Functor Perhaps where fmap f (Yes a) = Yes (fa) fmap f No = No instance Applicative Perhaps where pure a = Yes a No <*> _ = No _ <*> No = No Yes f <*> Yes x = Yes (fx) 

ZipList:

 data Zip a = Zip [a] deriving (Eq,Show) instance Functor Zip where fmap f (Zip xs) = Zip (map f xs) instance Applicative Zip where Zip fs <*> Zip xs = Zip (zipWith id fs xs) -- zip them up, applying the fs to the xs pure a = Zip (repeat a) -- infinite so that when you zip with something, lengths don't change 

1: : Monoid

,

Perhaps String . . -,

 (<++>) :: Perhaps String -> Perhaps String -> Perhaps String Yes xs <++> Yes ys = Yes (xs ++ ys) Yes xs <++> No = Yes xs No <++> Yes ys = Yes ys No <++> No = No 

String, Maybe, No , Yes [] . liftA2 (++) . , , , ++ - Monoid then!

 (<++>) :: Monoid a => Perhaps a -> Perhaps a -> Perhaps a Yes xs <++> Yes ys = Yes (xs `mappend` ys) Yes xs <++> No = Yes xs No <++> Yes ys = Yes ys No <++> No = No 

Perhaps a . Monoid a , , a . , () .

 instance Monoid a => Monoid (Perhaps a) where mappend = (<++>) mempty = No 

a, . Set s, Ord a .

ZipList

, zipList? , ?

  Zip ["HELLO","MUM","HOW","ARE","YOU?"] <> Zip ["this", "is", "fun"] = Zip ["HELLO" ? "this", "MUM" ? "is", "HOW" ? "fun"] mempty = ["","","","",..] -- sensible zero element for zipping with ? 

? . , ++ . , (<>) = (++)

  Zip [Just 1, Nothing, Just 3, Just 4] <> Zip [Just 40, Just 70, Nothing] = Zip [Just 1 ? Just 40, Nothing ? Just 70, Just 3 ? Nothing] mempty = [Nothing, Nothing, Nothing, .....] -- sensible zero element 

? , , Monoid: <> .

 instance Monoid a => Monoid (Zip a) where Zip as `mappend` Zip bs = Zip (zipWith (<>) as bs) -- zipWith the internal mappend mempty = Zip (repeat mempty) -- repeat the internal mempty 

zip - .

, Maybe, , Haskell , Int - + * ? Monoid , Sum Product , , .

 Zip [Just (Sum 1), Nothing, Just (Sum 3), Just (Sum 4)] <> Zip [Just (Sum 40), Just (Sum 70), Nothing] = Zip [Just (Sum 41),Just (Sum 70), Just (Sum 3)] Zip [Product 5,Product 10,Product 15] <> Zip [Product 3, Product 4] = Zip [Product 15,Product 40] 

, * , Monoid a - Eq a Ord a . . Monoid .

2: :

, .

,

 (<||>) :: Perhaps String -> Perhaps String -> Perhaps String Yes xs <||> Yes ys = Yes xs -- if we can have both, choose the left one Yes xs <||> No = Yes xs No <||> Yes ys = Yes ys No <||> No = No 

- ++ - Perhaps ,

 (<||>) :: Perhaps a -> Perhaps a -> Perhaps a Yes xs <||> Yes ys = Yes xs -- if we can have both, choose the left one Yes xs <||> No = Yes xs No <||> Yes ys = Yes ys No <||> No = No 

- a , Perhaps . .

 instance Alternative Perhaps where (<|>) = (<||>) empty = No 

ZipList

ziplists?

 Zip [1,3,4] <|> Zip [10,20,30,40] = ???? 

<|> , , . empty . , , Zip [] . , ( ) <|> ,

 Zip [] <|> Zip ys = Zip ys Zip xs <|> Zip [] = Zip xs 

Zip [1,3,4] <|> Zip [10,20,30,40] :

  • Zip [1,3,4] , - Maybe
  • Zip [10,20,30,40] , - Zip []

, : pure x = Zip (repeat x) , , , . , :

 instance Alternative Zip where empty = Zip [] Zip [] <|> x = x Zip xs <|> _ = Zip xs 

, . , Monoid, , .

, , Alternative * -> * , Ord a Eq a Monoid a . , . , , , - , , , .

: ?

- , :

Monoid * . Alternative (* -> *) . Monoid , Alternative . * (* -> *) . , .

, . Monoid Perhaps String , .

Monoid Maybe - , .
Maybe - , .

Monoid Zip . Zip - .

.

?

- . . SZ, , .

, Alternative - , . , . , (IO, Parser, Input UI element,...), - .

empty ?

/? , , , , ... , , . , , - , , "" ?

, , 0 - -, -, ? , 0 - , , , 1 , [] ( y=e^x ). do-nothing :

 sum = foldr (+) 0 concat = foldr (++) [] msum = foldr (`mappend`) mempty -- any Monoid whichEverWorksFirst = foldr (<|>) empty -- any Alternative 

MonadPlus Monad + Alternative?

MonadPlus? , - ? ? ( , , )

, !

Antal SZ, , , MonadPlus Applicative. , , , a MonadPlus ( - ) Alternative , .

, Monad MonadPlus, . , MonadPlus (), .

MonadPlus, , - MonadPlus ( Maybe). . , . ( , .)

? ?

"pedia" , " , ". , - Monoid? those. Alternative , , .

- . , , , , Alternative . , , ,

, Alternative Monoid,

, , Maybe ZipList , . , , , . , , . , ++ , , <|> ++ .

+16
01 . '12 10:03
source share

Summary

  • (, , ) Monoid , , . litvar = liftA2 mappend literal variable , <|> liftA2 mappend ; <|> , .

  • Monoid , . Alternative , , .

: Parsers

, , ,

 import Text.Parsec import Text.Parsec.String import Control.Applicative ((<$>),(<*>),liftA2,empty) import Data.Monoid import Data.Char 

, . :

 data Type = Literal String | Variable String deriving Show examples = [Literal "Int",Variable "a"] 

:

 literal :: Parser Type literal = fmap Literal $ (:) <$> upper <*> many alphaNum 

: parse a upper case character, many alphaNum eric , (:) . Literal , String Type s. , case lower :

 variable :: Parser Type variable = fmap Variable $ (:) <$> lower <*> many alphaNum 

, parseTest literal "Bool" == Literal "Bool" , .

3a: Monoid, liftA2 mappend

: Oops - <|> !

Alternative:

 types :: Parser Type types = literal <|> variable 

: parseTest types "Int" == Literal "Bool" parseTest types "a" == Variable "a" . , . , Applicative Functor, .

, :

 litvar = liftA2 mappend literal variable 

, , .

 No instance for (Monoid Type) arising from a use of `mappend' Possible fix: add an instance declaration for (Monoid Type) In the first argument of `liftA2', namely `mappend' In the expression: liftA2 mappend literal variable In an equation for `litvar': litvar = liftA2 mappend literal variable 

, ; - liftA2 mappend , - , . , , . , Parser Type * , , Parser s, Type s.

( Monoid, liftA2 mappend , <|> . Parser String , liftA2 mappend , , concatenates, <|> , , .)

3b: <|> :: fa -> fa -> fa Monoid mappend :: b -> b -> b ?

-, , Monoid.

-, , Monoid : mappend , , Alternative :

 instance Monoid (Parser a) where mempty = empty mappend = (<|>) 

Oops!

 Illegal instance declaration for `Monoid (Parser a)' (All instance types must be of the form (T t1 ... tn) where T is not a synonym. Use -XTypeSynonymInstances if you want to disable this.) In the instance declaration for `Monoid (Parser a)' 

, f , Alternative , fa , Monoid .

{-# LANGUAGE TypeSynonymInstances #-} ,

 typeParser = literal `mappend` variable 

, : parseTest typeParser "Yes" == Literal "Yes" parseTest typeParser "a" == Literal "a" .

( Parser String , ), {-# LANGUAGE FlexibleInstances #-} , , :

 data MyMaybe a = MyJust a | MyNothing deriving Show instance Monoid (MyMaybe Int) where mempty = MyNothing mappend MyNothing x = x mappend x MyNothing = x mappend (MyJust a) (MyJust b) = MyJust (a + b) 

( Maybe , .)

, , .




, . - ( ). fa -> fa -> fa , .

, :

  • Alternative /?
    . , anyA = foldr (<|>) empty .

  • MonadPlus? , - ? No. :

, Applicative Monad, MonadPlus, empty <*> m = empty , , empty >>= f = empty .

.... : . , . , → =, MonadPlus, .




. - .

+8
Oct 29 '12 2:30
source share

Alternative type , , .

, .

+ ( ), Int -> Int -> Int ( - ).

<|> , : .

+2
26 . '12 12:00
source share



All Articles