Haskell: Неисчерпывающий шаблон в функции предотвращает выполнение другой функции, даже если она не используется - PullRequest
0 голосов
/ 03 августа 2020

Я пытаюсь реализовать функциональность car, cdr, and cons на языке игрушек, который я пишу, однако, когда я пытаюсь выполнить свою функцию car через main, я получаю следующую ошибку:

./parser "car [1 2 3]"
parser: parser.hs:(48,27)-(55,45): Non-exhaustive patterns in case

Функция в строках 48-55 следующая:

parseOp :: Parser HVal
parseOp = (many1 letter <|> string "+" <|> string "-" <|> string "*" <|> string "/" <|> string "%" <|> string "&&" <|> string "||") >>= 
      (\x -> return $ case x of
                "&&" -> Op And
                "||" -> Op Or
                "+" -> Op Add
                "-" -> Op Sub
                "*" -> Op Mult
                "/" -> Op Div
                "%" -> Op Mod)

Я действительно не понимаю, почему сообщение об ошибке указывает на эту функцию, потому что она не имеет ничего общего с функциональностью списка. Однако функция car работает, потому что мне удалось успешно выполнить ее через GHCI. Я знаю, что моя проблема связана с синтаксическим анализом, но я не вижу, где она. Ниже перечислены функции, относящиеся к спискам. Я не могу понять из них, как на них влияет parseOp.

data HVal = Number Integer
          | String String
          | Boolean Bool
          | List [HVal]
          | Op Op
          | Expr Op HVal HVal
          | Car [HVal]
           deriving (Read)

car :: [HVal] -> HVal
car xs = head xs


parseListFunctions :: Parser HVal
parseListFunctions = do
            _ <- string "car "
            _ <- char '['
            x <- parseList
            _ <- char ']'
            return $ Car [x]
            

parseExpr :: Parser HVal
parseExpr =  parseNumber
         <|> parseOp
         <|> parseBool
     <|> parseListFunctions 
         <|> do
        _ <- char '['
                x <- parseList
                _ <- char ']'
                return x
         <|> do
            _ <- char '('
            x <- parseExpression
                _ <- char ')'
                return x

eval :: HVal -> HVal
eval val@(Number _) = val
eval val@(String _) = val
eval val@(Boolean _) = val
eval val@(List _) = val -- Look at list eval NOT WORKING
eval val@(Op _) = val
eval (Expr op x y) = eval $ evalExpr (eval x) op (eval y)
eval (Car xs) = eval $ car xs

Удаление many1 letter в parseOp переносит ту же ошибку в следующую функцию parseBool:

parseBool :: Parser HVal
parseBool = many1 letter >>= (\x -> return $ case x of
                                               "True" -> Boolean True
                                               "False" -> Boolean False)

1 Ответ

4 голосов
/ 03 августа 2020

Вы пишете

parseExpr = ... <|> parseOp <|> ... <|> parseListFunctions <|> ...

, и поэтому

car ...

сначала передается в parseOp, затем parseListFunctions. Парсер parseOp преуспевает в ветке

many1 letter

, и поэтому в \x -> return $ case x of ... x привязан к "car". Так как parseOp завершается успешно (и возвращает значение ошибки со встроенным, еще не оцененным исчерпывающим регистром!), parseListFunctions никогда не пробуется.

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

...