I am confused by the result of sepBy1
Following code is running in ghci
λ> import Text.ParserCombinators.ReadP
λ> import Data.Char
λ> readP_to_S ((munch1 isAlpha) `sepBy1` (char '-')) "dish-dash-dosh"
[(["dish"],"-dash-dosh"),(["dish","dash"],"-dosh"),["dish","dash","dosh"],"")]
[(["dish","dash","dosh"],"")]
?The following doctest
is only one that failed.
-- |
-- >>> readP_to_S readValues "dish-dash-dosh"
-- [(V ["dish","dash","dosh"],"")
readValues :: ReadP Value
readValues = do
xs <- (munch isAlpha) `sepBy1` (char '-')
pure $ V xs
Main.hs:64: failure in expression `readP_to_S readValues "dish-dash-dosh"'
expected: [(V ["dish","dash","dosh"],"")
but got: [(V ["dish"],"-dash-dosh"),(V ["dish","dash"],"-dosh"),(V ["dish","dash","dosh"],"")]
I am using ReadP
for Read
instance of my data. The code for Read
instance is working but I am confused.
Haven't done any complex parsing, I always think that running ReadP
will return output in form of single element list [(result,"")]
, obviously it is not the case.
data Value = V [String]
deriving Show
-- |
-- >>> read "dish-dash-dosh" :: Value
-- V ["dish","dash","dosh"]
--
instance Read Value where
readPrec = readP_to_Prec (const readValues)
read
will success only if there is nothing left in the snd
of the last [(Value,String)]
, other elements in this list are unuse anywhere?I am aware of alternative way to do this. This question is solely about understanding sepBy
output and it usage.
Running ReadP
will return all the possible parses. You can restrict the number of valid parses by specifying what should happen after the sepBy1
parse, e.g. end of input or some other syntactic element.
For instance, try something like:
readValues = do
xs <- (munch isAlpha) `sepBy1` (char '-')
eof
pure $ V xs
Addendum...
The ReadS
type follows the development of monadic parsing as presented in the classic Hutton and Meijer paper Monadic Parsing in Haskell. From the little documentation there is, I gather that the ReadP
implements parallel exploration of all alternatives. There is a lot of support for creating ReadP
actions and not so much for ReadS
, so I think you're using the library correctly by building a ReadP
action and then using readP_to_S
at the end. When I've used the module I've just taken the first match of the ReadS
action (or returned a parse error if it was the empty list.)
The ReadPrec
monad is used to support precedence, and it basically is ReaderT Int ReadP
-- here the Int
is the current precedence. Again, it looks like you start with a ReadP
parser and then convert it to a ReadPrec
action using lift
or readP_to_Prec
. To run it you can use readPrec_to_S
just like in the ReadP
case.