Suppose that Parser x
is a parser that parses an x
. This parser probably possesses a many
combinator, that parses zero or more occurrences of something (stopping when the item parser fails).
I can see how one might implement that if Parser
forms a monad. I can't figure out how to do it if Parser
is only an Applicative Functor. There doesn't seem to be any way to check the previous result and decide what to do next (precisely the notion that monads add). What am I missing?
A conditional loop would have been used, with the necessary condition being that the user enter 'Computing Science'. There are two ways to create conditional loops. You can use a pre-test conditional loop or a post-test conditional loop.
Thank you. You can add conditions to a Looping functoid by linking the output of a Looping functoid and a Logical functoid to the same destination record. The destination records are created only when the logical condition is met. In the preceding figure, the first Equal functoid compares the Name field under FoodSurvey to "Wendy Wheeler".
It is also possible to use a post-test conditional loop, which will always run the code within the loop at least once. This is because the actual condition needed to leave the loop is not checked until the end of the loop rather than at the start.
This is because the actual condition needed to leave the loop is not checked until the end of the loop rather than at the start. Post-test conditional loops often make use of IF statements and are less efficient than pre-test conditional loops.
The Alternative
type class provides the many
combinator:
class Applicative f => Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a
many :: f a -> f [a]
some :: f a -> f [a]
some = some'
many = many'
many' a = some' a <|> pure []
some' a = (:) <$> a <*> many' a
many a
combinator means “zero or more” a
.some a
combinator means “one or more” a
.Hence:
some a
combinator returns a list of one a
followed by many a
(i.e. 1 + (0 or more)
).many a
combinator returns either some a
or an empty list (i.e. (1 or more) | 0
).The many
combinator depends upon the (<|>)
operator which can be viewed as the default operator in languages like JavaScript. For example, consider the Alternative
instance of Maybe
:
instance Alternative Maybe where
empty = Nothing
Nothing <|> r = r
l <|> _ = l
Essentially the (<|>)
should return the left hand side value if it's truthy. Otherwise it should return the right hand side value.
A Parser
is a data structure which is defined similarly to Maybe
(the idea of applicative lexer combinators and parser combinators is essentially the same):
data Lexer a = Fail | Ok (Maybe a) (Vec (Lexer a))
If parsing fails, the Fail
value is returned. Otherwise an Ok
value is returned. Since Fail <|> pure []
is pure []
, this is how the many
combinator knows when to stop and return an empty list.
It can't be done just by using what is provided by Applicative
. But Alternative
has a function that gives you power beyond Applicative
:
(<|>) :: f a -> f a -> f a
This function lets you "combine" two Alternatives
without any restriction whatsoever on the a
. But how? Something intrinsic to the particular functor f
must give you a means to do that.
Typically, Alternative
s require some notion of failure or emptiness. Like for parsers, where (<|>)
means "try to parse this, if it fails, try this other thing". But this "dependence on a previous value" is hidden in the machinery implementing (<|>)
. It is not available to the external interface, so to speak.
From (<|>)
, one can implement a zero-or-one combinator:
optional :: Alternative f => f a -> f (Maybe a)
optional v = Just <$> v <|> pure Nothing
The definitions of some
an many
are similar but they require mutually recursive functions.
Notice that there are Applicative
s that aren't Alternative
s. You can't make the Identity
functor an Alternative
, for example. How would you implement empty
?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With