
简介这份资源是面向 Agda 语言开发者与函数式编程学习者的 VS Code 扩展用于在编辑器内获得接近 Emacs 的 Agda 交互体验解决在 VS Code 中编写、加载与类型检查 Agda 代码的痛点。压缩包共 179 个文件约 457KB以 67 个 js 与 64 个 res 源码文件为主体辅以 13 个 out、13 个 in 测试用例、5 个 json 配置、4 个 agda 示例及 less、yml、ttf 等资源结构上兼顾扩展实现、语言服务器适配与回归测试。已有 236 人学习下载。内容覆盖按键映射说明、归一化级别命令、Agda 语言服务器 LSP 支持以及 CaseSplit、QuotationMark、InputMethod 等示例文件读者可据此理解扩展的加载流程、命令前缀替换规则与测试组织方式适合希望迁移 Emacs 工作流或深入定制 Agda 编辑环境的中高级用户参考。1. 在 VS Code 里写 Agda这个扩展到底解决了什么痛点如果你写过 Agda大概率经历过这样的割裂一边是 Emacs 里 agda-mode 那套顺滑的交互式证明开发C-c C-l加载、C-c C-,看目标类型、C-c C-r精化另一边是团队里其他人都在用 VS Code 写 TypeScript、ReScript、ReasonML你不想为了一个语言单独开一个编辑器。agda-mode-vscode 就是冲着这个场景来的——它把 Agda 的交互式开发能力搬进了 VS Code让你在同一个窗口里既能写前端代码又能做依赖类型的形式化验证。这个扩展适合已经装好 Agda 编译器、想在 VS Code 里获得接近 Emacs agda-mode 体验的开发者也适合那些被「VS Code 能不能写 Agda」这个问题卡住、搜了半天只看到零散配置片段的人。它不是一个独立语言服务器而是对 Agda 自带交互协议的一层封装理解这一点后面很多行为就说得通了。2. 装之前先搞清楚agda-mode-vscode 的运行链路与依赖2.1 它不是语言服务器而是 Agda 交互命令的转发层很多人第一次搜 agda-mode-vscode会默认它像 rust-analyzer 或 clangd 那样自带一个完整的语言服务器。实际不是。Agda 本身提供了一个--interaction模式通过标准输入输出收发命令agda-mode-vscode 做的事情是在 VS Code 里启动一个 Agda 进程把你在编辑器里的操作翻译成 Agda 能识别的命令再把返回结果渲染成目标类型、上下文、错误信息这些面板内容。所以你的机器上必须先有一个能跑的 Agda 可执行文件扩展本身不包含编译器。这个链路决定了三件事。第一Agda 的版本会直接影响扩展行为不同版本的交互协议有细微差异。第二如果 Agda 不在 PATH 里扩展启动时会报找不到命令而不是给你一个友好的安装引导。第三所有证明检查的耗时都发生在 Agda 进程里VS Code 只是前端卡顿的时候不要怪编辑器。常见做法是先用包管理器装好 Agda确认命令行能跑再装扩展。我一般会先执行agda --version看到版本号再往下走。2.2 安装 Agda 编译器的几种路径与选择理由Agda 的安装方式主要有三种Haskell 工具链cabal 或 stack、系统包管理器、以及预编译二进制。如果你已经在用 Haskellcabal 是最自然的选择版本可控能和库一起管理。系统包管理器比如 apt、brew胜在快但版本往往偏旧可能和扩展期望的协议对不上。预编译二进制适合不想碰 Haskell 工具链的人但要注意平台匹配。下面是我在 Linux 上常用的 cabal 安装流程其他平台把包管理器命令换掉即可# 更新 cabal 包索引 cabal update # 安装指定版本的 Agda这里以 2.6.4 为例 cabal install Agda-2.6.4 # 确认可执行文件在 PATH 中 which agda agda --version逻辑说明cabal update拉取最新的包描述cabal install会编译并安装 Agda 及其依赖。参数上Agda-2.6.4是版本约束你可以换成自己需要的版本但建议和团队统一否则交互协议差异会导致扩展行为不一致。which agda用来确认安装路径已经进入环境变量如果这里为空后面扩展一定找不到。提示Windows 上用 cabal 安装 Agda 时编译时间可能很长建议预留足够磁盘空间和耐心或者改用预编译包。2.3 在 VS Code 中安装扩展并完成首次加载Agda 就绪后在 VS Code 扩展面板搜索 agda-mode-vscode 安装即可。安装完不要急着写代码先做一次最小验证新建一个.agda文件写一个最简模块然后触发加载命令。-- test.agda module test where -- 定义一个最简单的类型 data Bool : Set where true : Bool false : Bool保存后用命令面板CtrlShiftP执行Agda: Load。如果一切正常底部状态栏会显示加载成功光标停在Bool上时能看到类型信息。如果报错先看输出面板里 Agda 进程的原始输出那里会写清楚是找不到可执行文件还是语法错误。参数方面扩展通常会自动探测 PATH 里的agda。如果你的 Agda 装在非标准路径需要在 VS Code 设置里搜agda-mode找到可执行文件路径那一项手动填绝对路径。这一步是新手最容易翻车的地方明明终端里agda能跑扩展却报找不到原因就是 VS Code 启动时的环境变量和你的 shell 不一致。3. 把交互式证明开发跑起来加载、目标查看与精化3.1 加载与错误定位C-c C-l 的等价操作Emacs 里 agda-mode 的核心快捷键是C-c C-l在 VS Code 里对应命令面板的Agda: Load也可以自己在键位设置里绑一个顺手的组合。加载的作用是让 Agda 解析当前文件、类型检查、并把所有交互信息注册进来。没有加载之前查看目标类型、精化这些操作都不会有反应。加载失败时Agda 会在文件里标出错误位置同时在输出面板打印完整信息。常见的错误分两类语法错误和类型错误。语法错误通常指向解析失败的行类型错误会告诉你期望类型和实际类型。这里有个血泪经验Agda 的错误信息有时候会指向一个不太直观的位置尤其是涉及隐式参数的时候不要只盯着高亮行往上往下多看几行。module test where open import Data.Nat using (ℕ; zero; suc) -- 故意写一个类型错误的函数 bad : ℕ → ℕ bad x true -- 这里会报错true 不是 ℕ加载这段代码Agda 会明确告诉你true的类型Bool和期望的ℕ不匹配。这个反馈链路是后面所有交互操作的基础先确保它能正常工作。3.2 查看目标与上下文理解 Agda 的证明状态写证明的时候最常用的操作是查看当前目标的类型和上下文里有哪些变量可用。在 Emacs 里是C-c C-,VS Code 里通过命令面板执行Agda: Goal Type and Context。这个操作会把光标所在位置的洞hole的目标类型和上下文变量列出来。module test where open import Data.Nat using (ℕ; zero; suc) open import Data.Bool using (Bool; true; false) -- 一个带洞的函数用来观察目标 plus : ℕ → ℕ → ℕ plus x y {! !}把光标放在{! !}里执行查看目标你会看到目标类型是ℕ上下文里有x : ℕ和y : ℕ。这个信息决定了你下一步能做什么可以用x、y也可以对它们做模式匹配。参数上洞的写法是{! !}两个花括号加感叹号中间可以写内容作为提示Agda 会忽略里面的文字但保留位置。理解上下文和目标的关系是写 Agda 证明的基本功。很多人卡住不是因为不会语法而是没养成先看目标再动手的习惯。3.3 精化与自动求解C-c C-r 和 C-c C-a 的落地用法精化refine对应Agda: Refine作用是让 Agda 根据当前目标自动补一个最外层的构造子并把子目标留成新的洞。自动求解auto对应Agda: Auto会尝试用一组内置策略直接填满当前洞。module test where open import Data.Nat using (ℕ; zero; suc; __) -- 用精化来逐步构造 plus : ℕ → ℕ → ℕ plus zero y y plus (suc x) y suc (plus x y)如果你在plus x y {! !}上执行精化Agda 会提示你对x做模式匹配生成zero和suc两个分支。这就是交互式开发的节奏看目标、精化、填洞、再加载。自动求解适合那些结构简单、库里有现成引理的洞但它不是万能的复杂证明还是得手动来。参数上精化和自动求解都依赖当前加载的模块和已导入的库。如果库没导入自动求解能用的引理就少成功率会明显下降。所以写证明前先把需要的模块open import进来是个好习惯。4. 避坑与排查agda-mode-vscode 最常见的五类问题4.1 扩展报找不到 agda 可执行文件现象安装完扩展一加载就提示找不到agda命令但终端里agda --version正常。原因VS Code 启动时继承的环境变量和你的交互式 shell 不一致尤其是用 nvm、asdf 或自定义 PATH 的情况GUI 启动的 VS Code 拿不到你 shell 里配置的路径。解决在 VS Code 设置里搜agda-mode找到可执行文件路径配置项填agda的绝对路径。用which agda拿到路径粘进去重启 VS Code。4.2 加载成功但目标查看无反应现象文件能加载状态栏也显示成功但光标放在洞里执行查看目标没有任何输出。原因光标不在洞里或者洞的写法不规范。Agda 只认{! !}这种形式写成{ }或{- -}都不会被识别为交互洞。解决确认洞的写法把光标放在两个感叹号之间。如果还是不行重新加载一次文件有时候扩展状态和 Agda 进程会不同步。4.3 Agda 版本与扩展协议不匹配现象加载时报一些看不懂的协议错误或者某些命令行为异常。原因Agda 的交互协议在不同版本间有变化扩展可能针对某个版本区间做了适配版本太新或太旧都会出问题。解决查扩展的说明确认它支持的 Agda 版本范围把 Agda 降到或升到匹配的版本。团队协作时统一版本能省掉很多这类玄学问题。4.4 大文件加载慢到怀疑人生现象文件一大每次加载要等很久改一行重新加载更是煎熬。原因Agda 的类型检查是全局的加载会重新检查整个文件文件越大越慢。这是 Agda 本身的性质不是扩展的锅。解决把大文件拆成多个模块用open import组织改哪个模块加载哪个。另外Agda 有缓存机制但需要正确配置具体看你的安装方式。4.5 中文注释或特殊字符导致解析异常现象文件里写了中文注释加载时报解析错误位置指向注释附近。原因Agda 对源文件的字符编码有要求默认应该是 UTF-8。如果文件保存成了其他编码或者编辑器插入了一些不可见字符就会出问题。解决确认文件编码是 UTF-8VS Code 右下角可以看到。如果是从别处复制来的代码用「显示所有字符」检查有没有零宽字符有就删掉。5. 进阶技巧把 agda-mode-vscode 用出接近 Emacs 的效率5.1 自定义键位绑定减少命令面板依赖命令面板能用但写证明时频繁打开面板会打断节奏。VS Code 的键位设置里可以给 Agda 命令绑快捷键我一般会把加载、查看目标、精化、自动求解这四个绑到和 Emacs 接近的组合上肌肉记忆能直接迁移。// keybindings.json 片段 [ { key: ctrlc ctrll, command: agda-mode.load, when: editorLangId agda }, { key: ctrlc ctrl,, command: agda-mode.goal-type-context, when: editorLangId agda }, { key: ctrlc ctrlr, command: agda-mode.refine, when: editorLangId agda }, { key: ctrlc ctrla, command: agda-mode.auto, when: editorLangId agda } ]逻辑说明when条件限定只在 Agda 文件里生效避免和其他语言的快捷键冲突。命令名以扩展实际注册的为准不同版本可能有细微差异可以在键位设置里搜agda确认。参数上ctrlc ctrll这种两段式组合在 VS Code 里是支持的写起来和 Emacs 的C-c C-l对应。5.2 用洞和精化做增量式证明开发写复杂证明时不要试图一次写完整。我的习惯是先把函数签名和大致结构写出来在需要证明的地方留洞加载然后逐个洞看目标、精化、填。这样每次加载的检查范围可控出错也容易定位。module test where open import Data.Nat using (ℕ; zero; suc; __) open import Data.Nat.Properties using (-comm) -- 增量式开发先留洞再逐个填 lemma : ∀ (a b : ℕ) → a b ≡ b a lemma a b {! !}加载后看目标发现就是-comm的类型直接填-comm a b即可。这个流程的关键是洞不是失败而是开发状态的一部分。Agda 允许带洞加载只要洞不影响其他部分的类型检查。5.3 验证扩展是否正常工作的一套检查清单装完扩展、配好环境后我一般会走一遍这个清单确认链路是通的检查项操作预期结果Agda 可执行终端执行agda --version输出版本号扩展识别打开.agda文件看状态栏显示 Agda 相关状态加载功能命令面板执行Agda: Load无错误状态栏提示成功目标查看洞里执行查看目标输出目标类型和上下文精化功能洞里执行精化生成构造子或提示模式匹配错误反馈故意写类型错误加载标出错误位置和类型信息这套清单走完基本能确定扩展和 Agda 的配合没问题。后面遇到奇怪行为也可以回到这个清单逐项排查比盲目搜问题高效得多。从那以后我每次在新机器上配 Agda 环境都强制走一遍这个清单确认每一步都有反馈再开始写证明。希望帮到你。本文还有配套的精品资源点击获取