У меня есть грамматика, которую я анализирую, которая состоит из ровно двух необходимых и уникальных логических частей, Alpha
и Beta
. Эти части могут быть определены в любом порядке, Alpha
до Beta
или visa-vera. Я хотел бы предоставить надежные сообщения об ошибках для менее опытных пользователей.Как вернуть несколько сбоев разбора в монадическом контексте Parsec?
В приведенном ниже примере есть случаи, когда существует несколько сбоев разбора. Я объединяю сообщение об ошибке String
с функцией unlines
и передаю полученную конкатенацию в комбинатор fail
. Это создает значение ParseError
с одиночнымMessage
значение, когда parse
вызывается на 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
Я хотел бы, чтобы содержать ParseError
множественныеMessage
значения в случае множественных отказов. Это должно быть возможным из-за существования функции addErrorMessage
. Я не уверен, что нужно обеспечить множественный сбой в монадическом контексте Parsec, прежде чем результат будет реализован путем вызова parse
.
Пример Функция:
fails :: [String] -> ParsecT s u m a
fails = undefined -- Not sure how to define this!
Как поставить несколькоMessage
значения в ParseError
результате в монадической контексте парсек в?
Ваш ответ был очень информативным, однако [** 'Data.Parsec.Prim' **] (HTTP: // hackage .haskell.org/package/parsec-3.1.8/docs/Text-Parsec-Prim.html) не экспортирует конструктор 'ParsecT'. Это делает большинство представленных вами решений из источника модуля непригодным для использования вне открытого интерфейса библиотеки. –
Рад узнать, что использование 'меток' сработало для вас. – ErikR
Это не идеально, потому что я предпочел бы «Message» вместо «Expect», но, вероятно, так близко, как я получу. Плюс определение 'fail' является коротким и сладким;) –