How do you bind an arbitrarily long series of atomic parsers using applications?

Let's say I have this parser:

newtype Parser a = Parser { runParser :: String -> Maybe (a, String) } 

And this atom analyzer block:

 satisfy :: ( Char -> Bool ) -> Parser Char satisfy g = Parser $ \stream -> case stream of (x:xs) | gx -> Just ( x, xs ) otherwise -> Nothing 

The parser implements these three interfaces:

 instance Functor Parser where fmap g ( Parser p ) = Parser $ \xs0 -> p xs0 >>= \(x,xs) -> return ( gx, xs ) instance Applicative Parser where pure a = Parser $ \xs0 -> Just ( a, xs0 ) (Parser p1) <*> (Parser p2) = Parser $ \xs0 -> do (x1, xs1) <- p1 xs0 (x2, xs2) <- p2 xs1 return ( x1 x2, xs2 ) instance Alternative Parser where empty = Parser $ const Nothing (Parser p1) <|> (Parser p2) = Parser $ \ss -> let ss1 = p1 ss in case ss1 of Nothing -> p2 ss _ -> ss1 

Now, as I understand it, now I can rise to a higher level of abstraction and build more complex parsers by combining satisfy using the applicative interface. In the example:

 -- | A parser that parses the first two chars in the stream if they are upper case uParser = satisfy isUpper parser1 = ( (:) <$> uParser ) <*> ( (\x -> [x]) <$> uParser ) runParser parser1 "HEllo" = Just ("HE","llo") runParser parser1 "Hello" = Nothing 

This is great, now if I want to structure the calculation so that the parser analyzes all the letters of the header in the stream until it encounters a lowercase letter? Use Case:

 runParser idealParser "hello" = Nothing runParser idealParser "HEllo" = Just ("HE","llo") runParser idealParser "HELLOIAMnotincaps" = Just ("HELLOIAM", "notincaps") 

How to express this concept of indefinite length?

+4
source share
1 answer

Since you have an Alternative instance, you can simply use Control.Applicative.some to match a list of one or more occurrences.

 > runParser (some uParser) "hello" Nothing > runParser (some uParser) "HEllo" Just ("HE","llo") > runParser (some uParser) "HELLOIAMnotincaps" Just ("HELLOIAM","notincaps") 

To implement it manually, you can use two mutually recursive parsers, for example

 zeroOrMore = oneOrMore <|> pure [] oneOrMore = (:) <$> uParser <*> zeroOrMore 
+7
source

All Articles