You need to enable JavaScript to run this app. 如何使用最新版本Parsec.Indent库编写缩进敏感语法的解析器
优惠活动
大模型
产品
解决方案
定价
更多

如何使用最新版本Parsec.Indent库编写缩进敏感语法的解析器

问题原因

你遇到的类型错误是由于新版indents库的实现逻辑变更导致的:旧版示例中手动基于State SourcePos封装缩进解析栈的写法已经不再适用,新版库已经通过IndentT monad转换器封装了所有缩进状态管理逻辑,库提供的indented等函数要求解析器的monad栈必须包含IndentT,你自定义的IParser类型不满足这个要求,因此出现类型不匹配报错。

完整实现方案

下面给出解析你所需缩进格式整数列表的完整可运行代码:

import Text.Parsec
import Text.Parsec.Indent
import Text.Parsec.String (Parser)

-- 正确的解析器类型定义,用IndentT封装Parsec解析器
type IParser a = IndentT Parser a

-- 解析整数
parseInt :: IParser Integer
parseInt = read <$> many1 digit <* spaces

-- 解析缩进层级的整数
parseIndentedInt :: IParser Integer
parseIndentedInt = indented *> parseInt

-- 解析整个列表结构:先读列表名,再读下面所有同缩进层级的整数条目
parseList :: IParser (String, [Integer])
parseList = do
  listName <- many1 letter <* spaces
  items <- block parseIndentedInt
  return (listName, items)

-- 解析入口函数
main :: IO ()
main = do
  let testContent = unlines [
        "mylist",
        "    123",
        "    456"
      ]
  -- 运行解析:先跑IndentT,再调用Parsec的标准parse
  case parse (runIndentT parseList) "测试输入" testContent of
    Left err -> print err
    Right (name, items) -> putStrLn $ "列表名:" ++ name ++ ",元素:" ++ show items
关键说明
  • 你不需要自己手动管理SourcePos状态,IndentT已经内部封装了所有缩进计算、层级校验逻辑
  • block函数可以自动解析当前位置下缩进层级更深的所有同级别条目,不需要手动控制缩进判断
  • 运行解析时需要先调用runIndentT把缩进转换器层展开,再传给Parsec的标准parse函数即可

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 05:24:07