
Flow 守卫式 match 的穷尽性实战解析match_008_guard_exhaustiveness任务中的 guard 与穷尽检查协作【免费下载链接】flowAdds static typing to JavaScript to improve developer productivity and code quality.项目地址: https://gitcode.com/gh_mirrors/flow30/flow本篇技术指南围绕 Flow 官方 AI Evals 仓库evals/README.md中match_008_guard_exhaustiveness这一求值任务展开剖析 Flow 的match表达式如何与守卫guard配合完成「按类别 价格阈值」的折扣计算并解释为什么带守卫的分支不参与穷尽性计数、必须额外提供兜底分支。读完本文你将掌握match表达式 if守卫的完整写法、[match-not-exhaustive]错误的成因与修复方式以及该任务在 AST 层面如何被自动评分验证。一、任务速览这个 eval 在考什么match_008_guard_exhaustiveness位于求值目录 evals/evals/02_unique_features/match_008_guard_exhaustiveness/属于「Flow 独有特性」类别其 config.json 中标注的标签为flow、match、guards、exhaustiveness、pattern_matching难度为hard。任务的核心诉求见 prompt.md非常精炼main.js定义了一个Item类型包含name、price以及取值仅为food、electronics、clothing的category要求编写一个 Flow 函数discount(item: Item): number用match表达式按类别和价格阈值施加折扣落入阈值以下的所有其他情况返回原价。虽然任务描述刻意只描述「行为」而不指定「写法」这是该 eval 平台的设计原则见 evals/README.md 中「The prompt describes behavior, not the Flow syntax under test」但评分器明确要求使用match表达式且每个用例必须带 guard禁止使用switch。这决定了我们只能用 Flow 的match 守卫来实现。二、需求建模Item类型与三条折扣规则先建立类型模型type Item { name: string, price: number, category: food | electronics | clothing, };这里的关键点在于category是一个字符串字面量联合类型union of string literal types它正好是match穷尽性检查的理想输入Flow 可以枚举出所有可能取值。对应到本仓库官方文档match对 disjoint object unions 的检查是明确支持的见 website/docs/match/index.md 中的「Exhaustive Checking」一节。折扣规则按 prompt 原样复述类别价格阈值折扣food价格 $5010% off乘以 0.9electronics价格 $10015% off乘以 0.85clothing价格 $7520% off乘以 0.8其余所有情况—返回原价注意「价格超过阈值」属于动态条件它无法通过字面量模式表达price是number不是某个字面量这正是 guard 的用武之地。三、核心语法回顾match 表达式与 guardFlow 的match有两种形态表达式与语句。本任务要求的是discount(item: Item): number返回number因此使用match 表达式每个用例的 body 是一个表达式整个match的结果类型是所有用例表达式类型的联合见 website/docs/match/index.md 中「Match Expressions」一节。基本结构const e match (arg) { pattern-1 expression-1, pattern-2 if (cond) expression-2, pattern-3 expression-3, };守卫guard的语义有两个关键点同见 website/docs/match/index.md只有当模式本身匹配时守卫表达式才会被求值整个用例只有在「模式匹配且守卫结果为真」时才生效守卫作用于整个模式包括|或模式例如1 | 2 if (cond)会先匹配1 | 2再检查cond。更重要的规则是带守卫的用例不参与穷尽性检查计数。因为守卫可能为假编译器无法保证该分支一定覆盖对应取值。这一点在官方文档中写得非常明确Guarded cases do not count toward exhaustiveness checks, since they may or may not match based on the condition.仓库测试 tests/match/expression.js 还展示了一个与本任务高度相关的细节守卫可以细化与 match 参数无关的其他值例如1 if (typeof y number) y as number。在我们的任务里守卫条件直接引用item.price正是这一能力的典型用法。四、参考实现两条等价的解法路线有了上面的语法基础实现discount有两种等价路线。路线 A直接对item.category做 match守卫引用item.pricetype Item { name: string, price: number, category: food | electronics | clothing, }; function discount(item: Item): number { return match (item.category) { food if (item.price 50) item.price * 0.9, electronics if (item.price 100) item.price * 0.85, clothing if (item.price 75) item.price * 0.8, _ item.price, }; }路线 B对item整体做 match用对象模式 变量声明模式提取pricefunction discount(item: Item): number { return match (item) { {category: food, price: const p} if (p 50) p * 0.9, {category: electronics, price: const p} if (p 100) p * 0.85, {category: clothing, price: const p} if (p 75) p * 0.8, _ item.price, }; }两种写法都满足评分要求包含MatchExpression节点、每个用例带 guard、且没有switch。路线 A 更简短路线 B 则演示了对象模式中const p的变量提取能力对应官方文档 website/docs/match/patterns.md 中「Object patterns」的{prop: const x}语法。无论选哪条路线最后都必须保留_兜底分支原因见下一节。另外注意一个书写细节match (arg) {的左花括号必须与参数在同一行这是为了保证与旧的函数调用语法match(x);向后兼容见 website/docs/match/index.md 的「Fine print」说明。五、为什么兜底分支是必须的guard 不参与穷尽性计数这是本任务命名为guard_exhaustiveness的核心考点。删掉_分支后return match (item.category) { food if (item.price 50) item.price * 0.9, electronics if (item.price 100) item.price * 0.85, clothing if (item.price 75) item.price * 0.8, // ERROR [match-not-exhaustive] };Flow 会报[match-not-exhaustive]错误。原因是item.category的输入类型是food | electronics | clothing虽然每个类别都写了模式但这些模式全部带守卫——守卫可能为假例如一件 $20 的食品因此 Flow 无法确认这些取值被覆盖只能要求一个无条件匹配的兜底分支。仓库中 tests/match_exhaustive/guards.js 用大量用例精确验证了这一语义例如节选自「Basic」一节declare const x: 1 | 2; match (x) { // ERROR: missing 1 1 if (cond) {} 2 {} } match (x) { // OK带守卫的 1 之后补一个不带守卫的 1 1 if (cond) {} 1 {} 2 {} }第一段说明「仅带守卫的1」不足以覆盖1第二段说明「守卫用例 普通用例」组合起来才算覆盖。这与我们任务中「守卫用例 _兜底」的组合完全同构。_通配符模式匹配一切见 website/docs/match/patterns.md 中「Wildcard patterns」因此它能兜住「类别匹配但价格未达阈值」的所有剩余情况——这正是 prompt 中「All other items return their original price」的语义。通配符还有一种替代写法是变量声明模式const x两者都匹配一切见 website/docs/match/index.md。反向的「unused pattern」检查也值得注意一旦某取值已被前面的无条件用例覆盖后面的重复模式会被标记为冗余。例如 tests/match_exhaustive/guards.js 中match (x) { // OK 1 {} 1 if (cond) {} // ERRORunused pattern 2 {} }因此守卫用例必须排在其对应无守卫用例之前。而 tests/match_exhaustive/guards.js 的「Wildcards」一节还验证了「带守卫的通配符不算覆盖」对string类型的输入_ if (cond) {}单独出现会被报「missing_」必须再补一个无守卫的_。此外match语句场景下同样遵循该语义tests/match/statement.js 中「Throws in guards」一段展示了即使守卫if (invariant(false))恒为假恒抛出match 之后的代码也不算不可达——因为守卫可能为假分支可能不匹配。这从另一个角度印证了「守卫 不确定匹配」这一心智模型。六、AST 级自动评分求值器如何确认你用了 match guard本任务所在的 eval 平台采用 SWE-bench 风格compile_swebench.py对input/与ideal/做 diff 生成 gold patch 与评分脚本run_swebench.py在临时工作目录中应用补丁并运行评分器见 evals/README.md。本任务在 config.json 中自定义了三个 AST 级评分器grading: { graders: [ { type: contains_ast_node_type, query: MatchExpression }, { type: ast_query, selector: .type \MatchExpressionCase\ and .guard }, { type: contains_ast_node_type, query: SwitchStatement, negate: true } ] }逐一解读必须出现MatchExpression节点证明你确实用了match而不是其他条件结构至少一个MatchExpressionCase带.guard证明你使用了守卫语法这是guard_exhaustiveness的题眼禁止出现SwitchStatementnegate防止你用switch绕过match作答。评分器通过flow ast输出 AST 再交给jq断言结构见 evals/README.md 的「Grading」一节。这意味着即使代码能通过类型检查只要没用match guard评分依然会失败。在本地验证时可以运行make validate ARGS--eval match_008_guard_exhaustiveness让平台应用参考解法并跑通全部评分器无需调用任何模型。七、常见错误与调试指引把上述讨论整理成一份速查表方便排查问题现象原因修复[match-not-exhaustive]报缺少food等模式对应类别的模式全部带守卫守卫可能为假不算覆盖为该类别补无守卫用例或加_兜底守卫用例后跟同模式无守卫用例时报 unused pattern取值已被前面用例覆盖后续模式不可达调整用例顺序把无守卫用例放在守卫用例之后守卫用例先于无守卫用例只有_ if (cond)仍报 missing_带守卫的通配符不算覆盖再补一个无守卫的_返回类型不匹配match 表达式结果是所有用例表达式类型的联合确保各分支都返回number把 match 表达式写在语句位置表达式语句位置保留给 match 语句用return match (...) {...}或赋值给变量想在表达式 body 里throwthrow是语句match 表达式 body 需要表达式改用invariant(false, msg)见 website/docs/match/index.md最后补充启用条件pattern_matching配置项控制match的开关自 Flow v0.317 起默认开启true更早版本需要在.flowconfig的[options]下显式添加pattern_matchingtrue。该配置项在 website/docs/config/options.md 中有完整说明。你可以在本仓库的 tests/match/ 与 tests/match_exhaustive/ 目录下看到大量可直接运行的测试样例例如 tests/match_exhaustive/basic.js字面量/布尔/可空类型穷尽性、tests/match/matching.js对象/元组/联合匹配以及 tests/match_exhaustive/exhaustive-error-message.js错误消息格式它们是学习match语义最直接的第一手素材。【免费下载链接】flowAdds static typing to JavaScript to improve developer productivity and code quality.项目地址: https://gitcode.com/gh_mirrors/flow30/flow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考