Haskell:根据列表匹配字符串前缀
Haskell: Matching String Prefixes against List
最近我一直在学习一些 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)
但这似乎是一种糟糕的做事方式。有没有办法对列表中的元素进行模式匹配?我可以创建所有关键字的列表,并尝试将它们匹配为输入字符串的前缀吗?
如果要根据字符串前缀进行匹配,可以使用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
来实现。
最近我一直在学习一些 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)
但这似乎是一种糟糕的做事方式。有没有办法对列表中的元素进行模式匹配?我可以创建所有关键字的列表,并尝试将它们匹配为输入字符串的前缀吗?
如果要根据字符串前缀进行匹配,可以使用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
来实现。