【免费下载链接】rocA fast, friendly, functional language.项目地址https://gitcode.com/GitHub_Trending/ro/roc点击查看免费下载本文以仓库中的 REPL 快照测试 test/snapshots/try_map_err.md 为核心线索结合内置标准库 src/build/roc/Builtin.roc 中Try类型的真实实现系统讲解Try.map_err与Try.map_err!的语义、实现原理、类型签名及实战用法。读完本文你将理解 Roc 中结果类型Try错误分支变换的完整行为——包括 effectful 版本map_err!的差异、与map_ok/on_err/catch等近亲函数的取舍以及快照测试如何为这些语义提供机器可验证的保障。一、背景Try 类型在 Roc 中的地位Roc 使用Try表示一个可能成功也可能失败的计算结果。在 Builtin.roc 中Try被定义为一个带有Ok、Err两个变体的普通标记联合体并挂载了一批方法Try(ok, err) : [Ok(ok), Err(err)].{ parser_for : _ encoder_for : _ ... }它本质上就是Result/Either的 Roc 版本Try.Ok(value)表示成功并携带成功值Try.Err(error)表示失败并携带错误值。围绕这个类型内置库提供了is_ok/is_err判定、map_ok/map_err/map_both单边或双边变换、on_err恢复、catch折叠、ok_or/err_or兜底等一系列方法。而本文主角map_err正是只对错误分支做变换这一职责的承担者。二、快照内容逐条解读test/snapshots/try_map_err.md 是一个typerepl的 REPL 快照它在 SOURCE 段中依次求值 4 个表达式并在 OUTPUT 段固化每一次的输出» Try.map_err(Try.Err(50), |err_code| err_code 1) » Try.map_err!(Try.Err(50), |err_code| err_code 1) » Try.map_err(Try.Ok(hello), |_| world) » Try.map_err!(Try.Ok(hello), |_| world)对应输出Err(51.0) --- Err(51.0) --- Ok(hello) --- Ok(hello)2.1 Err 分支被变换Ok 分支原样保留表达式 1 与 2输入是Try.Err(50)经过|err_code| err_code 1变换后输出Err(51.0)——错误值 50 被加 1 变成 51并仍然包裹在Err中。无论是否带!结果一致。表达式 3 与 4输入是Try.Ok(hello)变换函数|_| world根本没有被调用输出保持Ok(hello)不变。这正是map_err的核心语义只作用于Err分支对Ok分支不做任何事连变换函数都不会执行。2.2 输出51.0背后的类型推断细节值得注意的一个细节是输入字面量是50输出却打印为51.0。这是因为在 REPL 环境中未标注类型的数字字面量默认按浮点类型F64推断50 1的结果以51.0的浮点形式显示。这说明map_err本身不关心错误值的具体数值类型——err_code 1中运算符决定了错误类型为数值类型而 REPL 的默认字面量推断决定了它是浮点。若想得到整数结果需像内置库文档示例那样显式标注例如Try.Err(50.I64)。2.3 PROBLEMS 段的含义快照末尾的PROBLEMS段为NIL。按照 test/snapshots/README.md 的说明普通快照含repl类型的PROBLEMS段保存编译器诊断的规范 S-expression 序列化NIL表示编译过程没有产生任何报告——即这 4 个表达式在类型检查、求值等各阶段全部顺利通过没有任何错误或警告。这本身就是对Try.map_err/Try.map_err!类型签名正确性的一次自动化验证。三、map_err 的源码实现Try.map_err的完整定义位于 Builtin.roc## If the result is Err, transforms the value it holds by running a conversion ## function on it. Then returns a new Err holding the transformed value. If ## the result is Ok, this has no effect. Use [Try.map_ok] to transform an Ok. ## roc ## expect [].last().map_err(|_| ProvidedListIsEmpty) Err(ProvidedListIsEmpty) ## ## expect [4].last().map_err(|_| ProvidedListIsEmpty) Ok(4.0) ## map_err : Try(ok, a), (a - b) - Try(ok, b) map_err |try, transform| match try { Err(a) Err(transform(a)) Ok(ok) Ok(ok) }3.1 类型签名解读map_err : Try(ok, a), (a - b) - Try(ok, b)第一个参数是Try(ok, a)ok是成功值类型a是错误值类型第二个参数是变换函数(a - b)只接收错误值、返回新错误值返回值是Try(ok, b)成功值类型ok保持不变错误值类型从a变为b。类型签名已经剧透了语义ok同时出现在输入和输出的同一位置意味着Ok分支的类型和值都不变只有错误分支的类型a - b发生迁移。这解释了快照中Ok(hello)原样返回、而Err(50)变为Err(51)的行为。3.2 实现逻辑一个简单的 match实现部分是一个直白的match命中Err(a)时调用transform(a)得到新错误值再包回Err命中Ok(ok)时不调用 transform直接把ok原样包回Ok。这个模式与map_okBuiltin.roc镜像对称map_ok命中Ok(a)时变换、命中Err时原样返回。两者合起来正是分别只动一边的精确语义。3.3 一个贴近实战的官方示例Builtin 文档注释中给出了用List.last()配合map_err的例子expect [].last().map_err(|_| ProvidedListIsEmpty) Err(ProvidedListIsEmpty) expect [4].last().map_err(|_| ProvidedListIsEmpty) Ok(4.0)List.last()本身返回Try空列表时为Err通过map_err(|_| ProvidedListIsEmpty)可以把底层的无元素错误翻译成业务自定义的错误标签ProvidedListIsEmpty而成功分支的Ok(4.0)则被原样透传。这是错误规范化error normalization的典型用法在错误跨越模块边界之前把内部错误转换为调用方理解的领域错误。四、effectful 版本 map_err!带副作用的错误变换与普通版本并排定义的是带!后缀的 effectful 版本Builtin.roc## Like [Try.map_err], but the transform function is effectful. If the argument is ## an Err, the effect is run and its return value is wrapped in a new Err. If ## the result is Ok, the effect is not run and the Ok is returned unchanged. ## roc ## # Log the failure to the database only when the request errored. ## request.map_err!(|e| SQL.execute!(INSERT INTO errors (message) VALUES (?), [e.message])) ## map_err! : Try(ok, a), (a b) Try(ok, b) map_err! |try, transform!| match try { Err(a) Err(transform!(a)) Ok(ok) Ok(ok) }4.1 签名差异-变成普通版参数类型是(a - b)纯函数而map_err!是(a b)effectful 函数即可能执行 IO、数据库操作、日志等能力的函数。在 Roc 的能力系统capabilities中表示该函数体内可以使用能力。整个函数类型因此也以连接Try(ok, a), (a b) Try(ok, b)。4.2 语义差异仅在 Err 分支执行副作用实现逻辑与普通版完全同构Err(a)分支执行transform!(a)效果运行、结果包回ErrOk(ok)分支不执行效果原样返回。文档注释给出的应用场景非常具体只在请求出错时把失败信息写入数据库——request.map_err!(|e| SQL.execute!(INSERT INTO errors (message) VALUES (?), [e.message]))这里SQL.execute!是一个 effectful 操作用map_err!可以保证成功时不产生任何数据库写入失败时把错误信息落库同时错误值仍以Try的形式继续传递。这种失败时才记账/审计/上报的模式正是map_err!相对于普通map_err的价值所在。快照中表达式 2 与 4 验证了map_err!与map_err在行为上的一致性Try.Err(50)变换后是Err(51.0)Try.Ok(hello)原样返回——即使变换函数被声明为 effectfulOk分支依然不会被触碰。五、与相邻 API 的取舍map_ok、map_both、on_err、catch理解map_err最好的方式是把它放进Try家族的分工表中看。以下函数都定义在 Builtin.roc 的同一区域L5323-L5519相互之间有明确的分工函数签名简化语义map_okTry(a, err), (a - b) - Try(b, err)只变换Ok分支Err原样返回map_errTry(ok, a), (a - b) - Try(ok, b)只变换Err分支Ok原样返回map_bothTry(a, b), (a - c), (b - d) - Try(c, d)两边各自变换命中哪个分支就运行哪个函数on_errTry(ok, a), (a - Try(ok, b)) - Try(ok, b)出错时运行恢复函数可返回新的Try恢复本身可失败catchTry(ok, err), (err - a), (ok - a) - a把结果折叠成普通值两边都必须返回同一类型源码注释里给出了精确的指引想让Ok与Err各自映射为不同类型、结果仍是Try→ 用 map_both出错时想恢复而非变换且恢复过程还可能再次失败 → 用 on_err想把Try折叠成一个普通值如日志字符串、HTTP 状态码→ 用 catch只想把错误值转换一下、不恢复也不折叠 → 用map_err。另外ok_or 和 err_or 提供了出错/成功时给默认值的兜底但源码注释特别提醒ok_or这类函数会掩盖错误的发生、增加调试难度应谨慎使用优先用?转发错误或用match显式处理。map_err由于保留了Try结构错误依然在Err里、类型变为新错误类型是比吃掉错误更安全的选择。六、仓库中的真实调用map_err 如何被编译器自身使用map_err并非仅供应用层使用Roc 编译器自身的代码也大量使用它这为理解它的实战形态提供了绝佳样本。在 Builtin.roc 中十六进制数字解析错误被映射为结构化错误标签hex_digit_value(byte).map_err(|_| InvalidHex({ index, byte }))同一文件的 L23214 处JSON 字符串中的非法\uXXXX转义被映射为.map_err(|_| InvalidJson(invalid hex digit in \\uXXXX escape))这两处的共同模式是底层解析函数返回的底层错误在向上层传播前被map_err转换为带上下文的领域错误——InvalidHex携带了出错位置{ index, byte }InvalidJson携带了人类可读的消息。这就是map_err在实际编译器中承担的错误上下文增强error enrichment职责。在解释器测试 src/eval/test/eval_issue_tests.zig#L1474 中也能看到同样的链式用法request.headers.find_first(|h| h.name x-foo).map_err(|_| NotFound)find_first查找失败时返回Err通过map_err(|_| NotFound)统一转换为NotFound错误。可见在 Roc 生态中map_err是把低层失败翻译成高层语义错误的标准工具。七、快照测试如何锁定这些语义try_map_err.md属于仓库的 REPL 快照体系。根据 test/snapshots/README.mdSnapshot tests provide comprehensive validation of the compilation pipeline by showing how source code is transformed through each stage: tokenization, parsing, canonicalization, and type checking etc.快照文件包含META元信息、SOURCE被测代码、OUTPUT期望输出与PROBLEMS期望诊断四个区段typerepl表示该快照通过 REPL 解释器实际求值并捕获输出。try_map_err.md的OUTPUT段精确锁定了map_err/map_err!在四种输入组合下的结果任何对语义的破坏比如错误分支不调用变换函数、或错误分支意外调用纯变换以外的效果都会导致快照失配从而在 CI 中暴露回归。对开发者而言可以按 README 提供的方式手动复现与调试这份快照# 更新/生成指定快照 zig build run-snapshot-tool -- test/snapshots/try_map_err.md # 从 PROBLEMS 更新期望值本快照为 NIL无需 zig build run-snapshot-tool -- test/snapshots/try_map_err.md --update-expected # 跟踪 REPL 求值过程仅适用于 typerepl 快照 zig build run-snapshot-tool -- test/snapshots/try_map_err.md --trace-eval注意 README 的提示--trace-eval只适用于 REPL 快照且一次只能处理单个文件trace 输出在 debug 构建中默认开启release 构建需以-Dtrace-evaltrue开启。八、实践要点小结map_err只动错误分支Err(a)会被变换为Err(f(a))Ok(ok)原样返回且变换函数不会执行——快照中 4 个表达式是这一语义的最直观验证。map_err!是带能力的版本变换函数以声明可在错误分支执行日志、写库等效果Ok分支依然不触发任何效果。适合失败时才审计/上报的场景。错误类型可以安全更换签名Try(ok, a), (a - b) - Try(ok, b)表明错误类型可在变换中改变常用于把底层错误转换为领域错误参考编译器内部的InvalidHex/InvalidJson/NotFound用法。与恢复、折叠区分开要恢复失败用on_err要把结果折叠成普通值用catch要两边都变换用map_both要兜底默认值用ok_or/err_or但需警惕其掩盖错误的副作用。REPL 数字字面量默认按浮点推断Err(50)经1后显示为Err(51.0)需要整数语义时应显式标注类型如50.I64。围绕 try_map_err.md 这份快照从 Builtin.roc 的类型定义到解释器测试 eval_issue_tests.zig整个仓库形成了一条完整的证据链map_err语义既有文档注释的权威说明又有 REPL 快照的机器验证还有编译器内部的实际调用样本。掌握了它你就能在 Roc 中写出既清晰又安全的错误处理链。赞分享【免费下载链接】rocA fast, friendly, functional language.项目地址https://gitcode.com/GitHub_Trending/ro/roc点击查看免费下载相关推荐从源码到运行AndroidScreencast编译与部署完全指南从源码到运行AndroidScreencast编译与部署完全指南 AndroidScreencast是一款强大的开源工具让你能够在电脑上查看和控制AndroRoc 语言 List.chunks_of 列表分块全解析从 REPL 快照测试到 Builtin 源码实现Roc 语言 List.chunks_of 列表分块全解析从 REPL 快照测试到 Builtin 源码实现 导读 List.chunks_of 是 RocRoc 语言 List.map2 深度实战从 REPL 快照到 Builtin 源码掌握成对映射的完整语义Roc 语言 List.map2 深度实战从 REPL 快照到 Builtin 源码掌握成对映射的完整语义 本篇技术指南以 Roc 语言测试快照 test/上一篇mini-vue组件错误边界捕获子组件异常下一篇amis 辅助类 Visibility 完全指南用 visible / invisible 控制元素显示与隐藏创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
Atlas 300V部署YOLO实战:从CANN环境到模型转换与性能调优 第一次拿到Atlas 300V 24G的时候,我差点做出一个很业余的决定:把它像显卡一样插进服务器,装个驱动就想直接跑YOLO。结果当然不意外——系统根本没把它当作显示设备,CUDA环境里更是彻底找不到它。如果你在搜索引擎里敲过"Atla… · 2026/9/20 23:02:59
单位网络建设的设计方案全流程解析避坑指南 单位网络建设的设计方案全流程解析避坑指南 改个需求建站公司拖一周,这种痛谁懂?很多单位搞网络建设,前期方案写得漂漂亮亮,后期落地全是坑。别急着怪供应商,大概率是你们的【单位网络建设的设计方案】里,把【完整流程】搞丢了,或者干脆没搞。… · 2026/9/21 9:17:55
3个实战案例教你挑对软件下载网站哪个好防挂马 3个实战案例教你挑对软件下载网站哪个好防挂马 上周帮客户复盘,发现官网弹窗全是博彩广告,后台日志被清空,这种被黑挂马的恐惧,很多站长都经历过。 别慌,选对底层架构的下载站,比事后打补丁重要十倍。 结合3个被黑过的实战案例,我拆解一下“软件下载网站哪个好”的评判标准。 设计原则与信任感构建… · 2026/9/21 9:02:23
网站标识代码怎么加实操详解及对比评测避坑指南 网站标识代码怎么加实操详解及对比评测避坑指南 备案流程一头雾水,是很多中小企业在上线官网时最容易卡壳的环节。很多老板以为只要把网站做出来,挂上域名就能收流量,结果发现没ICP备案根本打不开,或者加了备案代码位置不对导致审核不通过。这时候,一份清晰的网站标识代码怎么加的操作指南,加上不同服务商方案的对… · 2026/9/21 8:45:49
别被网页制作模板中文坑了,懂建站报价才不亏 别被网页制作模板中文坑了,懂建站报价才不亏 网站做好了没人访问,这钱白花得冤不冤?很多老板找外包,问完建站报价,对方甩给你一个“网页制作模板中文”链接,说这是高端定制。你一看,哦,是套壳的。更坑的是,有些模板连基础的SEO结构都没做好,上线三个月,百度搜不到你公司名字。… · 2026/9/21 8:31:34
2026最新微信小程序连接wordpress:解决域名服务器搞不懂的实战指南 2026最新微信小程序连接wordpress:解决域名服务器搞不懂的实战指南 域名解析指向不对,服务器端口没开放,SSL证书配置报错——这三座大山,劝退了一半想用微信小程序展示WordPress内容的开发者。别急,2026最新的连接方案早已绕开了传统Web服务器配置的深坑,核心逻辑是:… · 2026/9/21 8:17:36
企业网站做电脑营销多少钱?揭秘防黑挂马的底层逻辑 企业网站做电脑营销多少钱?揭秘防黑挂马的底层逻辑 网站突然被黑,首页挂满赌博广告,后台密码怎么改都没用,这种绝望感做过站的都懂。很多老板第一反应是问:“清理一次病毒多少钱?”或者“换个服务器多少钱?”但真相往往扎心:单纯清理病毒的费用可能只要几百块,但重建信任、修复SEO权重、补全安全漏洞的成本,往… · 2026/9/21 8:03:27
Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化 直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡… · 2026/9/21 0:02:39
Word表格编号全攻略:从列表编号到题注交叉引用 写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技… · 2026/9/21 0:02:39
从第一个站到第二个站:独立开发者的静态网站选型与落地实践 1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&… · 2026/9/20 0:00:41
agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 0:00:18
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,… · 2026/9/21 0:00:18