attoparsec???????????,????????????; ????????:

#

type Environment = M.Map String String 
import Data.Attoparsec (maybeResult)
import qualified Data.Attoparsec.Char8 as A
import qualified Data.ByteString.Char8 as B
environment :: A.Parser Environment
environment = M.fromList <$> A.sepBy entry A.endOfLine
parseEnvironment = maybeResult .flip A.feed B.empty . A.parse environment
spaces = A.many $ A.char ' '
entry = (,) <$> upTo ':' <*> upTo ';'
upTo delimiter = B.unpack <$> A.takeWhile (A.notInClass $ delimiter : " ")
                      <* (spaces >> A.char delimiter >> spaces)

???????,????????: ????????,???????A.feed????????????????B.empty? ????????????? ????

有帮助吗?

解决方案

There's an explanation of the need for feed in the answers to this StackOverflow question. As Bryan O'Sullivan (the creator of Attoparsec) says there:

If you write an attoparsec parser that consumes as much input as possible before failing, you must tell the partial result continuation when you've reached the end of your input.

You can do this by feeding it an empty bytestring.

I'll admit that I wrote the code in question, and I actually didn't use pointfree in this case. Simple composition just makes sense to me here: you run the parser (A.parse environment), you tell it you're done (flip A.feed B.empty), and you convert to a Maybe as a kind of basic error handling (maybeResult). In my opinion this feels cleaner than the pointed version:

parseEnvironment b = maybeResult $ A.feed (A.parse environment b) B.empty

The rest is I think fairly idiomatic applicative parsing, although I'm not sure why I would have used >> instead of *>.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top