Skip to content

Instantly share code, notes, and snippets.

@Garciat
Last active October 28, 2015 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Garciat/afef2465bf8456521c03 to your computer and use it in GitHub Desktop.
Save Garciat/afef2465bf8456521c03 to your computer and use it in GitHub Desktop.
module Parser where
import Control.Applicative
import Control.Monad
------------------------------------------------------------------------------
-- Definition
------------------------------------------------------------------------------
newtype Parser s a = Parser { runParser :: s -> [(a, s)] }
------------------------------------------------------------------------------
-- Instances
------------------------------------------------------------------------------
instance Functor (Parser s) where
fmap f px = Parser $ \s -> do { (x, s') <- runParser px s
; return (f x, s')
}
instance Applicative (Parser s) where
pure x = Parser $ \s -> [(x, s)]
pf <*> px = Parser $ \s -> do { (f, s') <- runParser pf s
; (x, s'') <- runParser px s'
; return (f x, s'')
}
instance Monad (Parser s) where
px >>= fp = Parser $ \s -> do { (x, s') <- runParser px s
; runParser (fp x) s'
}
instance Alternative (Parser s) where
empty = Parser $ \_ -> []
px <|> py = Parser $ \s -> case runParser px s of
[] -> runParser py s
res -> res
------------------------------------------------------------------------------
-- Combinators
------------------------------------------------------------------------------
choice :: [Parser s a] -> Parser s a
choice ps = foldr (<|>) empty ps
many1 :: Parser s a -> Parser s [a]
many1 p = (:) <$> p <*> many p
count :: Int -> Parser s a -> Parser s [a]
count n p = sequenceA (replicate n p)
option :: a -> Parser s a -> Parser s a
option x p = p <|> pure x
skipMany :: Parser s a -> Parser s ()
skipMany p = void $ many p
skipMany1 :: Parser s a -> Parser s ()
skipMany1 p = void $ many1 p
sepBy :: Parser s a -> Parser s sep -> Parser s [a]
sepBy px ps = sepBy1 px ps <|> pure []
sepBy1 :: Parser s a -> Parser s sep -> Parser s [a]
sepBy1 px ps = (:) <$> px <*> many (ps *> px)
------------------------------------------------------------------------------
-- Basic parsers
------------------------------------------------------------------------------
top :: Parser [a] a
top = Parser $ \s -> case s of
(c:cs) -> [(c, cs)]
otherwise -> []
satisfy :: (a -> Bool) -> Parser [a] a
satisfy p = top >>= \c -> if p c then
return c
else
empty
item :: Eq a => a -> Parser [a] a
item c = satisfy (== c)
oneOf :: Eq a => [a] -> Parser [a] a
oneOf xs = satisfy (`elem` xs)
string :: Eq a => [a] -> Parser [a] [a]
string cs = sequenceA (map item cs)
------------------------------------------------------------------------------
-- Char parsers
------------------------------------------------------------------------------
digit :: Parser [Char] Char
digit = oneOf ['0'..'9']
integer :: Parser [Char] Integer
integer = read <$> many1 digit
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment