Haskell Parsec如何实现冒号分隔的多组件Parser优雅组合?
解决方案
首先明确核心问题:sepBy 仅适用于重复使用同一个parser解析多个同构字段的场景,而你的需求是每个位置的parser类型不同(异构),自然无法直接适配。根据场景不同可以选择以下两种实现方案:
方案1:预定义多参数版本(最实用)
实际业务中日志字段数量通常不会超过10个,直接预定义常用参数数量的组合子即可,没有额外依赖,可读性最高:
-- 先提取公共的分隔符解析器,避免重复代码 colon :: Parser Char colon = char ':' -- 2个字段 parser2 :: (a -> b -> res) -> Parser a -> Parser b -> Parser res parser2 f pa pb = f <$> pa <* colon <*> pb -- 3个字段 parser3 :: (a -> b -> c -> res) -> Parser a -> Parser b -> Parser c -> Parser res parser3 f pa pb pc = f <$> pa <* colon <*> pb <* colon <*> pc -- 4个字段(替代你原来的实现) parser4 :: (a -> b -> c -> d -> res) -> Parser a -> Parser b -> Parser c -> Parser d -> Parser res parser4 f pa pb pc pd = f <$> pa <* colon <*> pb <* colon <*> pc <* colon <*> pd -- 后续需要更多字段时按相同规则扩展即可
使用方式和你原来的完全一致:
data Log = Log String Int String Bool deriving (Show) -- 假设有四个对应类型的parser logParser :: Parser Log logParser = parser4 Log parseA parseB parseC parseD
方案2:异构列表通用实现(适配任意数量字段)
如果不想每次加字段都新增组合子,可以用异构列表实现通用的分隔组合子,需要开启少量语言扩展:
{-# LANGUAGE TypeOperators, MultiParamTypeClasses, FlexibleInstances #-} -- 定义异构列表构造符 infixr 5 ::: data a ::: b = a ::: b deriving (Show, Eq) class Separated ps res where -- 第一个参数是分隔符解析器,第二个是异构的parser列表,返回组合后的Parser separatedBy :: Parser Char -> ps -> Parser res instance Separated (Parser a) a where separatedBy _ p = p instance Separated ps res => Separated (Parser a ::: ps) (a -> res) where separatedBy sep (p ::: ps) = (\a rest -> rest a) <$> p <* sep <*> separatedBy sep ps
使用时直接按顺序拼接parser即可,不需要新增组合子定义:
-- 4个字段的用法 logParser :: Parser Log logParser = Log <$> separatedBy colon (parseA ::: parseB ::: parseC ::: parseD) -- 5个字段直接往后加就行,不需要改组合子代码 logParser5 :: Parser Log5 logParser5 = Log5 <$> separatedBy colon (p1 ::: p2 ::: p3 ::: p4 ::: p5)
补充:同构字段场景
如果所有字段的规则完全相同,只用同一个parser就能解析所有位置的字段,直接用sepBy1加长度校验即可:
-- 示例:解析4个冒号分隔的数字 parseFourInts :: Parser [Int] parseFourInts = do nums <- sepBy1 (read <$> many1 digit) colon if length nums == 4 then pure nums else fail "expected 4 colon-separated integers"
内容的提问来源于stack exchange,提问作者Lando-L
相关产品推荐
相关产品推荐

