Проблема с синтаксическим анализом ‘\’ при реализации анализатора для созданного языка в назначении Haskell

#haskell

#haskell

Вопрос:

Я пишу анализатор для языка, предоставляемого EBNF. Все шло гладко, я успешно проанализировал «if», «then», «else», «Let», «in» и инфикс, подобный 1 2. Но когда я использую тот же подход для «», возвращается «Ничего», и я просто не знаю почему. EBNF описывает лямбду следующим образом:

 block ::= cond | lambda | let | infix
lambda ::= "" var "->" block
var is a letter followed by 0 or more letters. I tested my var parser, it works
  

Тест настроен следующим образом:

 newtype Parser a = PsrOf (String -> Maybe (String, a))
runParser :: Parser a -> String -> Maybe a
runParser (PsrOf p) inp = case p inp of
                            Nothing -> Nothing
                            Just (_, a) -> Just a
parse = runParser mainParser
testHandout =
    "handout" ~: parse inp
    ~?= (Just (Lambda "y" (Num 3)))
  

Это предоставленный тип данных Expr:

 data Expr
    = Num Integer
    | Var String
    | Prim2 Op2 Expr Expr       -- Prim2 op operand operand
    | Let [(String, Expr)] Expr -- Let [(name, rhs), ...] body
    | Lambda String Expr        -- Lambda var body
    | App Expr Expr             -- App func arg
    | Cond Expr Expr Expr       -- Cond test then-branch else-branch
    deriving (Eq, Show)

data Op2 = Eq | Lt | Plus | Minus | Mul | Div | Mod
    deriving (Eq, Show)
  

Моя задача — написать mainParser. Приведенный ниже код — это часть, связанная с этим вопросом (весь код компилируется без ошибок или предупреждений)

 mainParser :: Parser Expr
mainParser = whitespaces *> block <* eof
  where
    block = cond <|> lambda <|> letin <|> infixx <|> return (Var "Error")
    lambda = do
        char '\' *> whitespaces
        va <- var
        keyword "->"
        blk <- block
        return (Lambda va blk)
...more code unrelated to question
  

для строки

 char '\' *> whitespaces
  

Я пытался

 operator "\"
  

и

 keyword "\"
  

и

 string "\" *> whitespaces
  

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

 char :: Char -> Parser Char
char wanted = satisfy (c -> c == wanted)

satisfy :: (Char -> Bool) -> Parser Char
satisfy pred = PsrOf p
  where
    p (c:cs) | pred c = Just (cs, c)
    p _ = Nothing

string :: String -> Parser String
string wanted = PsrOf p
  where
    p inp = case stripPrefix wanted inp of
              Nothing -> Nothing
              Just suffix -> Just (suffix, wanted)

keyword :: String -> Parser String
keyword wanted = do
    c <- satisfy isAlpha
    cs <- many (satisfy isAlphaNum)
    whitespaces
    if c:cs == wanted then return wanted else empty

-- | Read something that looks like an operator, then skip trailing spaces.
anyOperator = some (satisfy symChar) <* whitespaces
  where
    symChar c = c `elem` "=/<>amp;| -*%\"

-- | Read the wanted operator, then skip trailing spaces.
operator wanted = do
    sym <- anyOperator
    if sym == wanted then return wanted else empty
  

Мой тестовый пример:

 "\y->3"
  

Ожидаемый результат:

 (Just (Lambda "y" (Num 3)))
  

Фактический результат:

 Nothing
  

Я знаю, что это проблема с «», потому что я переключил «if» в моем рабочем анализаторе if then else на «» then else, и анализатор if then else мгновенно сломался.
Также я хочу хотя бы попытаться получить сообщение об ошибке, поэтому я добавил

  lambda = (do ...... ) <|> return (Var "lambdaError")
  

в конце лямбда-блока в mainParser, но вместо Just (Var «lambdaError») Я все еще ничего не получаю.
Как разобрать »? Или, по крайней мере, как проверить, в чем здесь проблема?

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

1. Попробуйте ввести lambda сначала block , так что что-то вроде block = lambda <|> cond <|> ... . (Я не уверен, что это сработает, но иногда такие вещи работают хорошо.)

2. Нет, это не так. Но я думаю, что я мог бы понять, в чем проблема. «->» также неправильно анализируется

3. Может ли кто-нибудь задать этот вопрос решаемым?

Ответ №1:

NVM я обнаружил проблему

 operator "\"
  

на самом деле работает, но

 keyword "->"
  

не потому, что ключевое слово анализирует только буквы, вот почему я ничего не получал при использовании operator «». Поэтому я собираюсь использовать оператор «» и написать синтаксический анализатор только для «->»

В конце концов это сработало:

     lambda = do
        operator "\"
        va <- var
        char '-'
        operator ">"
        blk <- block
        return (Lambda va blk)
  

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

1. Когда я это делаю, я получаю это: > Вы можете принять свой собственный ответ через 2 дня

2. Почему бы и нет operator “->” ?