Haskell:针对列表匹配字符串前缀

时间:2019-02-25 02:09:11

标签: haskell lexer

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

一般程序结构为:

var express = require("express");
var app = express();

app.get('/', function(req, res) {
  if (userIsLoggedIn()) {
    res.sendFile(__dirname + '/public/html/entry.html');
  } else {
    res.sendFile(__dirname + '/public/accessDenied.html');
  }
});

function userIsLoggedIn() {
  return true;
}

app.use(express.static('public'));

app.use('/html', express.static(__dirname + '/public/html'));
app.use('/css', express.static(__dirname + '/public/css'));
app.use('/js', express.static(__dirname + '/public/js'));
app.use('/images', express.static(__dirname + '/public/images'));

var server = app.listen(3000, function(){
    var port = server.address().port;
    console.log("Server started at http://localhost:%s", port);
});

lex :: [Char] -> Maybe [Token] lex s = case tokenize([], s) of Just (tokens, []) -> Just tokens _ -> Nothing tokenize :: ([Token], [Char]) -> Maybe ([Token], [Char]) 在哪里建立令牌列表。 我在为tokenize设计合适的结构时遇到了麻烦。例如,要匹配tokenize之类的关键字,我可以这样写:

int

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

1 个答案:

答案 0 :(得分: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来做到这一点。