【问题标题】:Haskell: Matching String Prefixes against ListHaskell:根据列表匹配字符串前缀
【发布时间】:2019-02-25 02:09:11
【问题描述】:

我最近一直在学习一些 Haskell,我认为词法分析器可能是一个有趣的项目。我使用this ANSI C Yacc grammar 作为指导。

一般的程序结构是:

lex :: [Char] -> Maybe [Token]
lex s =
  case tokenize([], s) of
    Just (tokens, []) -> Just tokens
    _ -> Nothing

tokenize :: ([Token], [Char]) -> Maybe ([Token], [Char])

tokenize 在哪里构建令牌列表。 我无法为tokenize 寻找合适的结构。 例如,要匹配int 这样的关键字,我可以这样写:

tokenize (toks, 'i':'n':'t':' ':rest) = tokenize (toks++[TokenKeyword IntK], rest)

但这似乎是一种糟糕的做事方式。有没有办法对列表中的元素进行模式匹配?我可以创建所有关键字的列表,并尝试将它们作为输入字符串的前缀进行匹配吗?

【问题讨论】:

  • 匹配前缀不会让你走得太远,因为有些标记不是预定义的字符串——例如数字或标识符。
  • 对,当然前缀匹配不会涵盖所有内容。我说的是保留关键字
  • 也许regex-applicative 会满足您的需求。
  • 你应该学习如何使用一些 parsec 库。
  • 感谢大家的意见。为了进一步澄清我的问题,我想限制我使用解析/正则表达式库的次数。

标签: haskell lexer


【解决方案1】:

如果要根据字符串前缀进行匹配,可以使用ViewPatterns extension。可以通过将 -XViewPatterns 传递给编译器、在 ghci 中运行 :set -XViewPatterns 或将 {-# LANGUAGE ViewPatterns #-} 放在文件顶部来启用此扩展。

然后,您可以编写一个函数 matchPrefix(不是 100% 最优的,因为它确实会迭代 prefix 两次):

matchPrefix :: String -> String -> Maybe String
matchPrefix prefix result
  | and (zipWith (==) prefix result) = Just (drop (length prefix) result)
  | otherwise = Nothing

然后以如下模式使用它:

startsWithInt :: String -> Bool
startsWithInt (matchPrefix "int " -> Just rest) = True
startsWithInt _ = False

如果您想根据标记列表进行匹配,并找出字符串的其余部分以及匹配的标记,您可以通过修改 matchPrefix 来实现。

【讨论】:

    猜你喜欢
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    • 2021-05-20
    相关资源
    最近更新 更多