2017-01-01 15 views
0

Я следую this tutorial для реализации Комбиниров Parser (a la parsec) в Haskell. Я реализовал все, что упоминалось в NanoParsec.Реализация try (look-ahead) и доStop с комбинаторными компиляторами

За несколько часов в настоящее время, я struggeling реализовать

-- try p. If p fails continue without consuming anything 
try :: Parser a -> Parser a 
try p = ... 

-- Parser for everything, until the character-sequence stop appears. 
-- If stop does not appear at all: fail 
untilStop :: String -> Parser String 
untilStop stop = ... 

Моя лучшая попытка реализовать untilStop выглядит несколько, как это и не совсем работа

untilStop :: String -> Parser String 
untilStop (c : cs) = do 
    s <- some $ satisfy (/= d) 
    string (c : cs) <|> do 
    i <- item 
    untilStop (d : ds) 
    -- maybe use msum from MonadPlus to combine? 

Я не мог понять, как объединить s, i и рекурсивный звонок без сбоев из-за string не все вместе.

Я думаю, что у меня есть try, untilStop должно быть простым. Может ли кто-нибудь указать мне в правильном направлении или реализовать его (try) для меня?

Сейчас я все еще изучаю Монады, Применительные и связанные с ними вещи, поэтому попытка понять исходный код парсека была невозможна для меня.

+0

Вам не нужно 'try' для этой простой библиотеки парсеров. 'p <|> q' уже ведет себя как' try p <|> q'. Я прав? – Euge

+0

Well '<|> :: Parser a -> Parser a -> Parser a' нуждается в альтернативе моей * проверенной * опции. Я надеялся на что-то, что я могу просто «попробовать», и если он терпит неудачу, ничего не делайте и просто переходите к следующему утверждению в моей записи «do». – elfeck

+0

Именно так работает '<|>''. – Euge

ответ

1

Как я уже сказал в комментарии, я думаю, что вам не нужно иметь Parsec-подобный try.

Для untilStop, проверить это:

untilStop :: String -> Parser String 
untilStop [] = everything 
untilStop (c:cs) = item >>= fun 
    where fun i = do { s <- untilStop cs; 
        if i == c && s == "" then return "" else failure } <|> do 
        s <- untilStop (c : cs) 
        return (i : s) 

Во-первых, если остановка строка пуста, вы разбираете все. Где everything является:

everything :: Parser String 
everything = Parser (\inp -> [(inp,"")]) 

В противном случае, если она имеет вид c:cs, а затем разобрать характер i и рассмотрим два случая:

  • Строка остановка находится в передней части потока разборе (потому что c == i и синтаксический анализ остальной строки cs дает пустой результат), затем верните «". Или,

  • Это где-то в потоке, поэтому вы ищите его дальше.

Обратите внимание, что оператор <|> используется для обратного хода. Если untilStop cs не может быть тем, что мы хотим, нам нужно вернуть , используя вместо этого untilStop (c:cs).

+1

Спасибо за ваш ответ, но это работает неправильно. 'parse (untilStop" end ")" abcdef end "' дает '[(" abcd "," ef end ")]'. Он также не использует комбинаторы, которые, по моему мнению, должны быть целью. – elfeck

+0

Вы правы. Я думаю, что сейчас это работает. – Euge

+0

Спасибо ** много **, это работает теоретически, но я предложил изменить ваше решение, чтобы оно было скомпилировано и скопировано. Форматирование и – elfeck