Created
March 13, 2018 10:09
-
-
Save CarstenKoenig/9bbf8e76302a6418ab20ad0102798016 to your computer and use it in GitHub Desktop.
Revisions
-
CarstenKoenig created this gist
Mar 13, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,128 @@ {-# LANGUAGE LambdaCase #-} module Parser ( Parser , parse , Parser.fail , succeed , choose , char , digit , optional , many , many1 , choice , chainl1 , chainl , between , whitespace ) where import Control.Applicative (Alternative (..)) import Data.Char (isDigit) import Data.Semigroup (Semigroup (..), (<>)) newtype Parser a = Parser { runParser :: String -> Maybe (a, String) } parse :: Parser a -> String -> Maybe a parse pa = fmap fst . runParser pa fail :: Parser a fail = Parser $ const Nothing succeed :: a -> Parser a succeed x = Parser $ \s -> Just (x, s) choose :: (Char -> Bool) -> Parser Char choose praed = Parser $ \case (c:s) | praed c -> Just (c, s) _ -> Nothing char :: Char -> Parser Char char c = choose (== c) digit :: Parser Char digit = choose isDigit instance Functor Parser where fmap f pa = Parser $ fmap (\(a, r) -> (f a, r)) . runParser pa optional :: Parser a -> Parser (Maybe a) optional pa = Parser $ \s -> case runParser pa s of Nothing -> Just (Nothing, s) Just (a, s') -> Just (Just a, s') instance Applicative Parser where pure = succeed pf <*> pa = Parser $ \s -> do (f, s') <- runParser pf s (x, s'') <- runParser pa s' return (f x, s'') instance Alternative Parser where empty = Parser.fail p1 <|> p2 = Parser $ \s -> case runParser p1 s of ok@(Just _) -> ok Nothing -> runParser p2 s many1 :: Parser a -> Parser [a] many1 = some choice :: [Parser a] -> Parser a choice = foldr (<|>) empty instance Semigroup a => Semigroup (Parser a) where p1 <> p2 = (<>) <$> p1 <*> p2 instance Monoid a => Monoid (Parser a) where mempty = succeed mempty p1 `mappend` p2 = mappend <$> p1 <*> p2 instance Monad Parser where return = pure pa >>= fpb = Parser $ \s -> do (a, s') <- runParser pa s runParser (fpb a) s' chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a chainl1 pa pop = pa >>= cont where cont a = do op <- pop a' <- pa cont (a `op` a') <|> succeed a chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a chainl pa pop va = chainl1 pa pop <|> succeed va between :: Parser l -> Parser r -> Parser a -> Parser a between pl pr pa = pl *> pa <* pr whitespace :: Parser () whitespace = return () <* many (choice [ char ' ', char '\n', char '\t', char '\r' ])