在Haskell分配中为组合语言实现解析器时无法解析“ \\”

时间:2019-04-06 21:48:44

标签: haskell

我正在为EBNF提供的语言编写解析器。一切都进行得很顺利,我成功地解析了“ if”,“ then”,“ else”,“ Let”,“ in”和像1 + 2这样的中缀。但是当我对“ \”使用相同的方法时,“ Nothing”不会返回,我只是不知道为什么。 EBNF像这样描述lambda:

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` "=/<>&|+-*%\\"

-- | 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 else解析器的“ if”切换为“ \” then else,而if then else解析器立即中断。 另外,我至少希望收到一条错误消息,所以我添加了

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

mainParser 中的lambda块的末尾,但是我仍然没有得到Just(Var“ lambdaError”)。 如何解析“ \”?或者至少如何测试这里的问题?

1 个答案:

答案 0 :(得分:3)

我找到问题的NVM

operator "\\"

实际上可以,但是

keyword "->"

不是因为关键字仅解析字母,所以这就是为什么我在使用运算符“ \”时得到什么都没有的原因。因此,我将使用运算符“ \”并为“->”编写一个解析器

最终成功了:

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