ParS c setState не сбрасывает статус потребления - PullRequest
2 голосов
/ 09 января 2020

Я пытаюсь понять, как Parse c сбрасывает свое состояние и что является частью этого состояния. Я удивлен поведением следующего кода:

parseAbReset :: Parser Char                                                                    
parseAbReset = do                                                                              
    st <- getParserState                                                                  
    char 'A'                                                                              
    ret <- char 'b' <|> (setParserState st >> fail mempty)                                
    return ret                                                                            


parseFinal :: Parser Char                                                                     
parseFinal = parseAbReset <|> (char 'A' >> char 't')

Я ожидаю, что parseFinal успешно проанализирует "At". Вот мои рассуждения (| обозначает текущее состояние на входе): <|> пытается parseAbReset, который анализирует до "A | t", затем он не работает на char 'b' без использования ввода и поэтому сбрасывает состояние обратно к «| At», parseAbReset завершается ошибкой (и, по моему мнению, он должен завершиться с ошибкой без использования ввода, так как он сбрасывается в состояние до того, как потребляет ввод). Это позволяет альтернативе (char 'A' >> char 't') потреблять «At», и мы заканчиваем «At |».

В других примерах я проверял, что setParserState успешно сбрасывает позицию в потоке, но кажется, что состояние он что-то потреблял или нет не сбрасывается.

Любые идеи, как я могу сбросить, потреблял ли он или нет?

1 Ответ

1 голос
/ 09 января 2020

Позиция потока не является частью состояния анализатора, поэтому сброс состояния анализатора не может повлиять на то, какие входные данные были использованы. Одно использование {get, set} ParserState в самом Parse c находится в lookahead. Как видите, он выполняет некоторую работу по сохранению входного потока в дополнение к сохранению состояния анализатора. Полезно отметить, что если он потребляет ввод в тех случаях, когда вы не можете использовать sh, вы должны использовать try. Это имеет смысл: try - это типичный инструмент Parse c для восстановления после частичного сбоя анализа.

И действительно, то, что вы пытаетесь сделать, очень просто с try:

parseAbReset :: Parser Char
parseAbReset = try $ char 'A' *> char 'b'
...