Haskell 词法分析器输入和返回的标记列表或错误

Haskell lexer input and returning list of tokens or error

您好,我正在处理词法分析器接受输入字符串和 return 标记列表或错误的问题。如果有人知道如何解决问题,请提供帮助。谢谢:)

lexer :: String -> Either Error [Token]

我在不使用任何一个的情况下工作时遇到了问题,但无法弄清楚 Haskell 的任何一个功能。我想向左给出一个错误,向右制作带有模式匹配的标记列表和多个条件。

这是不起作用的代码:

lexar (x:xs) 
  | isSpace x = Main.lexar xs 
  | isDigit x = Right (Literal (show x): Main.lexar xs) 
  | x == '+' = Right (Plus : Main.lexar xs) 
  | x == '-' = Right (Minus : Main.lexar xs) 
  | x == '*' = Right (Mult : Main.lexar xs) 
  | x == '/' = Right (Div : Main.lexar xs) 
  | x == '(' = Right (LeftP : Main.lexar xs) 
  | x == ')' = Right (RightP : Main.lexar xs) 
  | otherwise = Left (error "fail")

首先,不能将:运算符与lexar的return值一起使用。

此版本的 lexar return 是一个 Either 不是 列表,因此不能作为运算符 :.

每次你递归调用lexar,它return给你一个Either,它可能是LeftRight。如果它是 Left,它包含错误,您只需将它向上传递到堆栈。如果它是 Right,那么它包含下游词法分析的结果,您可以将当前标记添加到它前面,然后在 returning 之前再次将其包装在 Right 中。让我们记下来:

  | isDigit x = 
      case lexar xs of
          Left err -> Left err
          Right tokens -> Right (Literal (show x) : tokens)

当然,如果您必须为每个标记编写一个完整的 case 表达式,这将变得非常乏味。因此,您可以将其包装在辅助函数中:

lexar (x:xs)
  ...
  | isDigit x = prependToken (Literal (show x)) 
  | x == '+' = prependToken Plus
  ...
  where
      prependToken t = 
          case lexar xs of
              Left err -> Left err
              Right tokens -> Right (t : tokens)

如果您对更抽象的概念足够满意,您还可以通过使用运算符 <$>:

来利用 EitherFunctor 实例
lexar (x:xs)
  ...
  | isDigit x = (Literal (show x) :) <$> lexar xs
  | x == '+' = (Plus :) <$> lexar xs
  ...

Either 的运算符 <$> 的标准库实现将给定函数应用于 Right 值或 return Left 值不变。本质上,这正是我的辅助函数 prependToken 正在做的事情。


最后,当 return 调用 Left 时,不要调用 error 函数。这个函数会在计算结果时使程序崩溃,这不是你想要的。只需将字符串包装在 Left:

  | otherwise = Left "fail"