Как вернуть несколько проанализированных ADT за парсек?

#haskell #parsec

#haskell #парсек

Вопрос:

Я использую Parsec для анализа файла, который выглядит следующим образом:

 ## public_id

ANALOG-CLOCK

## name

Analog Wall Clock
Some more text...

## domain

Time measurement

More text here...
  

за исключением того, что файл может иметь переменное количество разделов, где каждый раздел начинается со строки «# #» и может содержать 0 строк содержимого.

 type Model = [Section]

data Section = Section String [String]
               deriving Show


headingLine :: Parser String
headingLine = do
  try (string "##")
  spaces
  title <- many1 (noneOf "rn")
  char 'n'
  return title


nonHeadingLine :: Parser String
nonHeadingLine = do
  try (noneOf "#")
  contents <- many1 (noneOf "rn")
  char 'n'
  return contents


section :: Parser Section
section = do
  title <- headingLine
  contentLines <- many1 nonHeadingLine
  spaces
  return $ Section title contentLines


model :: Parser Model
model = do
  s1 <- section
  s2 <- section
  s3 <- section
  return [s1, s2, s3]
  --return $ many1 section


main :: IO ()
main = do
  modelStr <- readFile "analog3.md"
  let result = do parse model "" modelStr
  case result of
    Left  err -> putStrLn $ "Error "    show err
    Right mdl -> putStrLn $ show mdl
  

Я хочу, чтобы результат выглядел примерно так:

 [Section "public_id" "ANALOG-CLOCK",Section "name" "Analog Wall Clock",Section "domain" "Time measurement"]
  

Код работает, когда у меня есть ровно одна строка содержимого на раздел, и выдает вышеуказанный результат.

У меня две проблемы:

1) Код не работает, когда у меня более одной строки содержимого на раздел, и

2) Когда я использую return $ many1 section вместо return [s1, s2, s3] , я получаю сообщение об ошибке типа «Не удалось сопоставить данные типа ‘Text.Parsec.Prim.ParsecT String ().Функтор.Идентификация.Идентификация [Section]’с ‘[Section]’ «.

Как мне заставить его обрабатывать более одной строки содержимого и как мне заставить его обрабатывать более одного раздела? Спасибо.

Комментарии:

1. many1 это уже монадический тип, поэтому вам не нужно использовать return его. Просто введите many1 section . «return» не является ключевым словом в Haskell; это функция, которая встраивает значение в монаду: return :: Monad m => a -> m a

2. Спасибо! Это избавляет от ошибки типа, но я получаю ошибку времени выполнения «Ошибка (строка 12, столбец 1): неожиданный конец ввода, ожидающий пробел или «##» «. У меня такое чувство, что я неправильно разделяю / завершаю разделы, но я не знаю, как мне следует.

3. @citrus Похоже, что он запускается headingLine в конце файла, после того, как все это уже было проанализировано. Если у вас теперь есть many1 section в конце вашей model функции, но вы забыли удалить предыдущие четыре строки, это приведет к тому, что она попытается проанализировать по крайней мере четыре раздела, когда их всего три.

4. @DarthFennec: Спасибо, это сработало! Я забыл удалить другие строки.