Parsing 如何在Parsec';什么是一元语境?
我正在解析的语法正好由两个必需且唯一的逻辑部分组成,Parsing 如何在Parsec';什么是一元语境?,parsing,haskell,error-handling,parsec,parse-error,Parsing,Haskell,Error Handling,Parsec,Parse Error,我正在解析的语法正好由两个必需且唯一的逻辑部分组成,Alpha和Beta。这些部件可以按任何顺序定义,Alpha在Beta之前或visa vera。我想为不太懂技术的用户提供可靠的错误消息 在下面的示例中,存在多个解析失败的情况。我将失败消息Strings与函数连接起来,并将结果连接传递给组合器。当在grammarDefinition上调用时,这将创建一个具有单个值的值 示例场景: import Data.Either (partitionEithers) i
Alpha
和Beta
。这些部件可以按任何顺序定义,Alpha
在Beta
之前或visa vera。我想为不太懂技术的用户提供可靠的错误消息
在下面的示例中,存在多个解析失败的情况。我将失败消息String
s与函数连接起来,并将结果连接传递给组合器。当在grammarDefinition
上调用时,这将创建一个具有单个值的值
示例场景:
import Data.Either (partitionEithers)
import Data.Set (Set)
import Text.Parsec (Parsec)
import Text.Parsec.Char
import Text.ParserCombinators.Parsec
data Result = Result Alpha Beta
type Alpha = Set (Int,Float)
type Beta = Set String
grammarDefinition :: Parsec String u Result
grammarDefinition = do
segments <- partitionEithers <$> many segment
_ <- eof
case segments of
( [], []) -> fail $ unlines [missingAlpha, missingBeta]
( _, []) -> fail $ missingBeta
( [], _) -> fail $ missingAlpha
((_:_:_), (_:_:_)) -> fail $ unlines [multipleAlpha, multipleBeta]
( _, (_:_:_)) -> fail $ multipleBeta
((_:_:_), _) -> fail $ multipleAlpha
( [x], [y]) -> pure $ Result x y
where
missingAlpha = message "No" "alpha"
missingBeta = message "No" "beta"
multipleAlpha = message "Multiple" "alpha"
multipleBeta = message "Multiple" "beta"
message x y = concat [x," ",y," defined in input, ","exactly one ",y," definition required"]
-- Type signature is important!
segment :: Parsec String u (Either Alpha Beta)
segment = undefined -- implementation irrelevant
fails :: [String] -> ParsecT s u m a
fails = undefined -- Not sure how to define this!
如何在Parsec的一元上下文中为结果提供多个值?
fail
在这种情况下等同于Text.Parsec.Prim
中的定义:
parserFail :: String -> ParsecT s u m a
parserFail msg
= ParsecT $ \s _ _ _ eerr ->
eerr $ newErrorMessage (Message msg) (statePos s)
由于newErrorMessage
和addErrorMessage
都创建了ParseError
,
parserFail
的这种变体也应该起作用:
parserFail' :: String -> ParsecT s u m a
parserFail' msg
= ParsecT $ \s _ _ _ eerr ->
eerr $ theMessages s
where
theMessages s =
addErrorMessage (Message "blah") $
addErrorMessage (Expect "expected this") $
newErrorMessage (Message msg) (statePos s)
这会将3条消息推送到错误消息列表中
同样在该模块中,请查看标签
和标签
,它们是
唯一使用addErrorMessage
的地方<代码>标签只是一条多信息
运算符的版本。注意它是如何使用foldr
构建化合物的
错误消息:
labels :: ParsecT s u m a -> [String] -> ParsecT s u m a
labels p msgs =
ParsecT $ \s cok cerr eok eerr ->
let eok' x s' error = eok x s' $ if errorIsUnknown error
then error
else setExpectErrors error msgs
eerr' err = eerr $ setExpectErrors err msgs
in unParser p s cok cerr eok' eerr'
where
setExpectErrors err [] = setErrorMessage (Expect "") err
setExpectErrors err [msg] = setErrorMessage (Expect msg) err
setExpectErrors err (msg:msgs)
= foldr (\msg' err' -> addErrorMessage (Expect msg') err')
(setErrorMessage (Expect msg) err) msgs
唯一的gatcha是您需要访问ParsecT
构造函数,该构造函数
不是通过Text.Parsec.Prim
导出的。也许你能找到一种使用标签的方法
或者用另一种方法来解决这个问题。否则,您可以始终包括您的
使用您的代码拥有被黑客攻击的
parsec
我们可以利用的一个实例,将的定义与函数相结合,得出所需的结果:
fails :: [String] -> ParsecT s u m a
fails = labels mzero
注意:有很多值,而不是很多值…我建议从转换到更新和更可扩展的库 自版本
4.2.0.0
以来已解决
使用以下函数可以轻松创建多个分析错误:
fails :: MonadParsec m => [String] -> m a
fails = failure . fmap Message
您的回答提供了大量信息,但是没有导出
ParsecT
构造函数。这使得您提出的大多数解决方案在库的公开界面之外无法使用模块的源代码。很高兴知道使用标签对您有效。这并不完美,因为我更喜欢消息而不是期望值值,但它可能是我能得到的最接近的解决方案。加上失败
定义又短又甜;)