[Haskell-beginners] parse block comments
mike h
mike_k_houghton at yahoo.co.uk
Sat Mar 18 21:11:20 UTC 2017
Hi,
Below is code I’m building up for simple monadic and applicative parsers from first principles.
I’ve just added code for single line Haskell style comments.
-- comment being '--'
comment :: Parser ()
comment = do
string "--"
many (sat ( /='\n') )
return ()
— or as applicative
comment' = string "--" *> many (sat (/='\n') )
I’d really appreciate help on writing a function for multi line comments! “{-“ and end with “-}”
I know I need some sort of look ahead but can’t quite get the feel of how!
Thanks
Mike
======================================
import Control.Applicative
import Data.Char
newtype Parser a = P (String -> [(a,String)])
parse :: Parser a -> String -> [(a,String)]
parse (P p) = p
item :: Parser Char
item = P (\s -> case s of
[] -> []
(x:xs) -> [(x, xs)])
instance Functor Parser where
-- fmap :: (a -> b) -> f a -> f b
fmap g p = P (\inp -> case parse p inp of
[] -> []
[(x, xs)] -> [(g x, xs)])
instance Applicative Parser where
-- pure :: a -> Parser a
-- (<*>) :: Parser (a -> b) -> Parser a -> Parser b
pure x = P (\inp -> [(x, inp)])
pab <*> pa = P (\inp -> case parse pab inp of
[] -> []
[(aTob, out)] -> parse (fmap aTob pa) out)
three :: Parser (Char, Char)
three = pure g <*> item <*> item <*> item
where g x y z = (x, z)
instance Monad Parser where
-- return :: a -> Parser a
return x = P (\inp -> [(x, inp)])
-- (>>=) :: Parser a -> (a -> Parser b) -> Parser b
pa >>= f = P (\inp -> case parse pa inp of
[] -> []
[(a, out)] -> parse (f a) out)
instance Alternative Parser where
-- empty :: Parser a
empty = P (\inp -> [])
-- (<|>) :: Parser a-> Parser a -> Parser a
-- if p1 works the that one otherwise p2
p1 <|> p2 = P (\inp -> case parse p1 inp of
[] -> parse p2 inp
out -> out)
sat :: (Char -> Bool) -> Parser Char
sat p = do
x <- item
if p x then return x else empty
digit :: Parser Char
digit = sat isDigit
lower :: Parser Char
lower = sat isLower
upper :: Parser Char
upper = sat isUpper
letter :: Parser Char
letter = sat isAlpha
alphanum :: Parser Char
alphanum = sat isAlphaNum
char :: Char -> Parser Char
char x = sat (==x)
string :: String -> Parser String
string [] = return []
string s@(x:xs) = do
char x *> string xs *> return s
ident :: Parser String
ident = do
x <- lower
xs <- many alphanum
return (x:xs)
ident' :: Parser String
ident' = pure (:) <*> lower <*> many alphanum
nat :: Parser Int
nat = do
xs <- some digit
return (read xs)
nat' :: Parser Int
nat' = pure read <*> some digit
space :: Parser ()
space = do
many (sat isSpace )
return ()
space' :: Parser ()
space' = many (sat isSpace ) *> return ()
int :: Parser Int
int = do
char '-'
n <- nat
return (-n)
<|> nat
int' :: Parser Int
int' = char '-' *> pure ((-1)*) <*> nat <|> nat
token :: Parser a -> Parser a
token p = do
space
v <- p
space
return v
token' :: Parser a -> Parser a
token' p = space *> p <* space
identifier :: Parser String
identifier = token ident
natural :: Parser Int
natural = token nat
integer :: Parser Int
integer = token int
symbol :: String -> Parser String
symbol xs = token (string xs)
nats :: Parser [Int]
nats = do
symbol "["
n <- natural
ns <- many ( do symbol ","
natural )
symbol "]"
return (n:ns)
-- comment being '--'
comment :: Parser ()
comment = do
string "--"
many (sat ( /='\n') )
return ()
comment' = string "--" *> many (sat (/='\n') )
nats' :: Parser [Int]
-- sequence and ignore "[" and the rest
-- the rest is fmap list cons into result of natural and the apply that to many others and
-- finally ignore the closing "]"
nats' = symbol "[" >> (:) <$> natural <*> many (symbol "," >> natural) <* symbol "]"
More information about the Beginners
mailing list