I am trying to write a simple parser in Haskell using readP and following some pre-made code examples I have found.
I use the following:
import Data.Char
import Text.ParserCombinators.ReadP
import Control.Applicative ((<|>))
type Parser a = ReadP a
type ParseError = String
space :: Parser Char
space = satisfy isSpace
spaces :: Parser String
spaces = many space
space1 :: Parser String
space1 = many1 space
symbol :: String -> Parser String
symbol = token . string
schar :: Char -> Parser Char
schar = token . char
token :: Parser a -> Parser a
token combinator = spaces >> combinator
runParser = readP_to_S
e :: Parser Int
e = do t
t :: Parser Int
t = (do string "0"
return 0)
<|>
(do string "1"
return 1)
parseString input = runParser (e >> eof) input
However I get the following output:
ghci> parseString "1"
[((),"")]
ghci> parseString "0"
[((),"")]
ghci> parseString ""
[]
Whereas I would expect the following output
ghci> parseString "1"
[("1","")]
ghci> parseString "0"
[("0","")]
ghci> parseString ""
[]
How come that is? And is there a way to make it print these outputs instead?
CodePudding user response:
The new code is better, but there is still an issue here
parseString input = runParser (e >> eof) input
--^^^^^^^^^^--
Adding >> eof
discards the result of e
. To retain it, we can either use
parseString input = runParser (e <* eof) input
Or, with a more basic approach:
whole :: Parser Int
whole = do
val <- e -- save the value produced by e
eof -- ensure the end of the parsed string
return val -- return the saved value
parseString input = runParser whole input
In either case, we get:
> parseString "1"
[(1,"")]
Note that the first component of the pair in the list is 1
, an Int
. Indeed, it has the same type mentioned in the signature whole :: Parser Int
.