content: module AParser (Parser, runParser, satisfy, char, posInt) where
  
  import           Control.Applicative
  import           Data.Char
  
  newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }
  
  satisfy :: (Char -> Bool) -> Parser Char
  satisfy p = Parser f
    where
      f [] = Nothing
      f (x:xs)
          | p x       = Just (x, xs)
          | otherwise = Nothing
  
  char :: Char -> Parser Char
  char c = satisfy (== c)
  
  posInt :: Parser Integer
  posInt = Parser f
    where
      f xs
        | null ns   = Nothing
        | otherwise = Just (read ns, rest)
        where (ns, rest) = span isDigit xs
  
  inParser f = Parser . f . runParser
  
  first :: (a -> b) -> (a,c) -> (b,c)
  first f (x,y) = (f x, y)
  
  instance Functor Parser where
    fmap = inParser . fmap . fmap . first
  
  instance Applicative Parser where
    pure a = Parser (\s -> Just (a, s))
    (Parser fp) <*> xp = Parser $ \s ->
      case fp s of
        Nothing     -> Nothing
        Just (f,s') -> runParser (f <$> xp) s'
  
  instance Alternative Parser where
    empty = Parser (const Nothing)
    Parser p1 <|> Parser p2 = Parser $ liftA2 (<|>) p1 p2
  