Парсер Haskell Parsec для встреч []

Я пытаюсь написать парсер на Haskell, используя Parsec. В настоящее время у меня есть программа, которая может разбирать

test x [1,2,3] end

Код, который это делает, выглядит следующим образом

testParser = do { 
  reserved "test"; 
  v <- identifier; 
  symbol "["; 
  l <- sepBy natural commaSep;
  symbol "]";
  p <- pParser;
  return $ Test v (List l) p
 } <?> "end"

где commaSep определяется как

commaSep        = skipMany1 (space <|> char ',')

Есть ли у меня способ разобрать подобное утверждение, а именно:

test x [1...3] end

Поскольку я новичок в Haskell и Parsec в этом отношении, я уверен, что есть хороший лаконичный способ сделать это, о котором я просто не знаю. Любая помощь будет оценена по достоинству.

Спасибо еще раз.


person Vincent Russo    schedule 17.07.2012    source источник
comment
Должно ли количество периодов быть постоянным или переменным? Разрешены ли пробелы между числами и точками, а также между точками? Кстати, ваш первый парсер соответствует test x [1 , ,2, ,,3] end; может быть, это не то, что вы хотите.   -  person dflemstr    schedule 17.07.2012
comment
Количество периодов должно быть постоянным, т.е. [1 ... 3] должно состоять ровно из 3 периодов для любого случая. Пробелы между ними, например [1 ... 3], следует игнорировать. Надеюсь, это проясняет то, что мне нужно, немного больше.   -  person Vincent Russo    schedule 17.07.2012


Ответы (1)


Я буду использовать некоторые функции из Control.Applicative, например (*>). Эти функции полезны, если вы хотите избежать монадического интерфейса Parsec и предпочитаете прикладной интерфейс, потому что, на мой взгляд, синтаксические анализаторы легче читаются.

Если вы не знакомы с основными прикладными функциями, оставьте комментарий, и я их объясню. Вы можете найти их в Hoogle, если не уверены.


Как я понял вашу проблему, вам нужен синтаксический анализатор для некоторой структуры данных, подобной этой:

data Test = Test String Numbers
data Numbers = List [Int] | Range Int Int

Парсер, который может анализировать такую ​​структуру данных, будет выглядеть так (я не компилировал код, но он должен работать):

-- parses "test <identifier> [<numbers>] end"
testParser :: Parser Test
testParser =
  Test <$> reserved "test" *> identifier
       <*> symbol "[" *> numbersParser <* symbol "]"
       <*  reserved "end"
       <?> "test"

numbersParser :: Parser Numbers
numbersParser = try listParser <|> rangeParser

-- parses "<natural>, <natural>, <natural>" etc
listParser :: Parser Numbers
listParser =
  List <$> sepBy natural (symbol ",")
       <?> "list"

-- parses "<natural> ... <natural>"
rangeParser :: Parser Numbers
rangeParser =
  Range <$> natural <* symbol "..."
        <*> natural
        <?> "range"
person dflemstr    schedule 17.07.2012
comment
Ах, большое спасибо, это именно то, что мне было нужно. Спасибо еще раз! - person Vincent Russo; 17.07.2012
comment
@VincentRusso это синоним fmap. - person phipsgabler; 17.07.2012
comment
Хорошо, еще кое-что, что я все еще пытаюсь исправить. Могу я просто сделать что-нибудь вроде l ‹- try (sepBy natural commaSep‹ | ›естественный символ ... естественный); Только моя реализация здесь не работает, есть ли что-то подобное, что я могу сделать? Ваш пример великолепен, но способ, которым парсер в настоящее время реализован, похоже, не так хорошо сочетается с приведенным выше примером. Еще раз спасибо за вашу помощь. - person Vincent Russo; 17.07.2012
comment
Какая часть не работает? У меня нет вашего pParser, поэтому я не могу проанализировать часть end, поэтому я просто превратил его в зарезервированный токен. Вы, конечно, можете сделать l <- List <$> try listParser <|> Range <$> rangeParser, если хотите использовать свое старое решение, но решение, которое я опубликовал, по существу идентично вашему старому решению; они просто используют разные стили. - person dflemstr; 17.07.2012
comment
Да, разные стили ставят меня в тупик, так как я немного новичок в этом, поэтому я прошу прощения за свое невежество. Я попытался вставить предложенный вами код в ваш комментарий, но получаю некоторые ошибки, которые я не совсем понимаю, как интерпретировать. Извините, я ничем не могу больше помочь в этом отношении. - person Vincent Russo; 17.07.2012
comment
В моем исходном сообщении единственной ошибкой, которую я получал, была ошибка синтаксического анализа, имеющая форму: неожиданно. ожидание цифры, пробела или]. Это то, о чем вы имеете в виду, или вы имеете в виду свой пост? - person Vincent Russo; 17.07.2012
comment
Ха, нет, я имел в виду, что вы должны отредактировать исходный пост, чтобы включить в него появившееся сообщение об ошибке. - person dflemstr; 18.07.2012
comment
Ах вот что я подумал. Что ж, с вашей помощью я, в конце концов, дошел до того, что [...] признал этот случай. Мое решение не самое элегантное, и я, скорее всего, вернусь и потрачу некоторое время, пытаясь сделать его немного чище, как ваше. Просто хотел еще раз поблагодарить вас за терпение и помощь. Ваше здоровье. - person Vincent Russo; 18.07.2012