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?