Roc 语言 Try.map_both 实战:从 REPL 快照测试看懂 Ok/Err 双分支映射语义
Roc 语言 Try.map_both 实战从 REPL 快照测试看懂 Ok/Err 双分支映射语义【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc本篇技术指南以 Roc 仓库中的 REPL 快照测试 test/snapshots/repl/try_map_both.md 为核心结合 Builtin.roc 中Try类型的源码实现系统讲解Try.map_both与Try.map_both!的语义、参数与返回值规则并演示如何通过roc snapshot在本地复现与验证。读完本文你将掌握 Roc 结果类型双分支映射的完整用法以及 REPL 快照文件的结构化格式能够独立阅读、编写和运行同类测试。一、背景Roc 的Try结果类型在 Roc 语言中Try(ok, err)是一个内置的结果类型用于表示可能成功也可能失败的计算。它在 Builtin.roc 中被定义为Try(ok, err) : [Ok(ok), Err(err)]即Try恰好包含两个变体携带成功值ok的Ok(ok)以及携带失败信息err的Err(err)。这种结构与许多语言中的Result/Either类型类似是 Roc 中显式错误处理的基石函数可以返回Try调用方通过match或Try模块提供的组合子如map_ok、map_err、map_both、catch等安全地处理两种分支。Try.map_both与它的 effectful 版本Try.map_both!正是同时对 Ok 和 Err 两个分支做转换的组合子也是本快照测试文件的核心验证对象。二、快照文件的结构一个可执行的 REPL 会话记录test/snapshots/repl/try_map_both.md是 Roc 仓库中 REPL 快照测试的一种它以 Markdown 形式记录一次 REPL 会话的输入与期望输出由roc snapshot工具读取并执行输出与文件中记录不符时即判定测试失败。这类文件统一由四段组成METAini 格式的元信息description描述测试意图typerepl声明这是 REPL 快照区别于eval、build等其他类型SOURCE以»为提示符的 REPL 输入序列每行是一条独立语句OUTPUT与输入一一对应的期望输出相邻输出之间以---分隔PROBLEMS期望的编译/运行问题列表NIL表示全部通过、无任何问题。本文件的完整内容如下摘录自 try_map_both.md# META ~~~ini descriptionTry.map_both with Ok and Err variants typerepl ~~~» Try.map_both(Try.Err(failed), |val| val 1, |_| Failed) » Try.map_both!(Try.Err(failed), |val| val 1, |_| Failed) » Try.map_both(Try.Ok(100), |val| val - 50, |_| Failed) » Try.map_both!(Try.Ok(100), |val| val - 50, |_| Failed) » t Try.Ok(a string long enough to be heap-allocated instead of stored inline) » Try.map_both(t, |s| s, |e| e) » t对应输出Err(Failed) --- Err(Failed) --- Ok(50.0) --- Ok(50.0) --- assigned t --- Ok(a string long enough to be heap-allocated instead of stored inline) --- Ok(a string long enough to be heap-allocated instead of stored inline)从输出可以看出该快照在 src/snapshot_tool/main.zig 的驱动下逐行执行---是每次求值结果之间的标准分隔符assignedt 是 REPL 对绑定语句的固定反馈其生成逻辑位于 src/cli/ReplSession.zig 附近绑定成功时输出assigned关键字。下面逐行拆解语义。三、逐行实验map_both 在 Ok 与 Err 上的行为3.1 Err 分支只有 err_transform 被调用» Try.map_both(Try.Err(failed), |val| val 1, |_| Failed)结果为Err(Failed)。观察要点输入是Try.Err(failed)携带字符串错误failed第一个参数|val| val 1是ok_transform本应作用于Ok携带的值第二个参数|_| Failed是err_transform把原错误failed整体丢弃、替换为标签Failed由于输入是Err只有 err_transform 运行ok_transform 完全未被调用即使它会对val 1也不会产生任何影响返回值仍被包裹在Err变体中类型从Try(_, Str)变为Try(_, Failed)。这验证了map_both的只运行与当前变体匹配的那个函数的核心语义。3.2 Ok 分支只有 ok_transform 被调用» Try.map_both(Try.Ok(100), |val| val - 50, |_| Failed)结果为Ok(50.0)。观察要点输入是Try.Ok(100)携带数值 100ok_transform|val| val - 50执行计算得到 50err_transform|_| Failed未被执行结果以Ok变体返回。注意输出中的50.0Roc 的 REPL 在展示数值字面量时使用浮点书写形式可对照 repl_unbound_numbers_hide_type.md 中42→42.0、1 2→3.0的输出惯例这是 REPL 的显示约定并不代表运算本身涉及浮点精度问题。3.3 effectful 版本 map_both!同样的分支语义支持副作用» Try.map_both!(Try.Err(failed), |val| val 1, |_| Failed) » Try.map_both!(Try.Ok(100), |val| val - 50, |_| Failed)输出与纯函数版本完全一致Err(Failed)与Ok(50.0)。区别在于签名中的map_both!接受两个 effectful 变换函数其类型为map_both! : Try(a, b), (a c), (b d) Try(c, d)这意味着 ok_transform 与 err_transform 内部可以执行日志、数据库写入、HTTP 请求等有副作用的操作例如文档中给出的request.map_both!(|ok| Log.info!(...), |e| Log.warn!(...))场景并且只有与当前变体匹配的那个 effect 会被真正运行另一个则完全不会触发——这在副作用场景下尤为关键能避免在错误分支上误执行成功路径的逻辑。3.4 不变式验证map_both 保持包装结构» t Try.Ok(a string long enough to be heap-allocated instead of stored inline) » Try.map_both(t, |s| s, |e| e) » t这里做了两件事将一个大字符串装入Try.Ok并绑定到tREPL 输出assignedt用两个恒等函数|s| s与|e| e调用map_both随后再次求值t。两行输出都是Ok(a string long enough to be heap-allocated instead of stored inline)证明传入的字符串足够长会被堆分配而不是内联存储这正是测试 description 隐含的意图之一——验证 REPL 对堆分配字符串的显示与引用语义map_both使用恒等变换时是纯透传的Ok保持Ok内容原样保留t本身未被修改Roc 值默认不可变。四、源码级剖析map_both 与 map_both! 的实现在 Builtin.roc 中两个函数的完整实现如下map_both : Try(a, b), (a - c), (b - d) - Try(c, d) map_both |try, ok_transform, err_transform| match try { Err(b) Err(err_transform(b)) Ok(a) Ok(ok_transform(a)) }map_both! : Try(a, b), (a c), (b d) Try(c, d) map_both! |try, ok_transform!, err_transform!| match try { Err(b) Err(err_transform!(b)) Ok(a) Ok(ok_transform!(a)) }几个值得注意的源码事实分支选择由match try决定只有命中的分支对应的变换函数被求值。对Err(b)执行err_transform(b)并包回Err对Ok(a)执行ok_transform(a)并包回Ok。变换函数是尾随的二元参数调用顺序为map_both(result, ok_transform, err_transform)注意 ok_transform 在前、err_transform 在后与match分支书写顺序一致阅读源码时不易混淆。类型允许 Ok 与 Err 变换为不同目标类型(a - c)与(b - d)中的c、d相互独立因此map_both可以把Try(I64, Str)一步变成Try(I64, Failed)如本节实验也可以把两个分支分别变换成完全不同的类型。!后缀是 Roc 的 effect 约定带!的函数可运行副作用其类型箭头从-变为map_both!内部同样遵循只跑匹配分支的规则从源码可见Err分支只调用err_transform!。从实现角度map_both可以看作 map_ok 与 map_err 的合并形态——后两者分别只变换单个分支未命中的分支原样返回而map_both一次性覆盖两个分支。五、与相邻组合子的选型对比围绕TryBuiltin.roc 提供了多组相似函数选型时可按下表区分函数签名要点语义适用场景map_bothTry(a,b), (a-c), (b-d) - Try(c,d)分别变换 Ok/Err仍返回Try两个分支都要改、且保持结果类型map_both!Try(a,b), (ac), (bd) Try(c,d)同上但变换函数可有副作用在分支内执行日志、IO 等 effectmap_ok/map_ok!Try(a,err), (a-b) - Try(b,err)只变换 OkErr 原样返回仅成功路径需要转换map_err/map_err!Try(ok,a), (a-b) - Try(ok,b)只变换 ErrOk 原样返回仅错误路径需要转换、不恢复catch/catch!Try(ok,err), (err-a), (ok-a) - a两个分支收敛为同一普通类型需要把Try折叠成普通值如错误处理兜底on_err/on_err!Try(ok,a), (a-Try(ok,b)) - Try(ok,b)仅对 Err 运行恢复函数可返回新的Try从错误中恢复且恢复本身可能失败map2/map2!Try(a,err), Try(b,err), (a,b-c) - Try(c,err)两个结果都 Ok 才运行合并函数组合多个可能失败的计算关键判别标准有二是否两个分支都要变换map_both是map_ok/map_err否以及结果是否保持Try包装保持则用map_both收敛成普通值则用 catch。快照测试中|_| Failed这类丢弃原错误、换成统一错误标签的写法正是map_both最常见的实战形态之一。六、在本地运行与验证该快照仓库根目录下即可执行快照测试。roc snapshot是快照工具 src/snapshot_tool/main.zig 暴露的命令它支持直接运行单个 REPL 快照文件该文件会给出--trace-eval等调试用法并提示--trace-eval只能用于typerepl的快照# 在仓库根目录执行运行指定的 REPL 快照测试 roc snapshot test/snapshots/repl/try_map_both.md执行过程中工具会启动一个真实 REPL 会话复用 src/cli/ReplSession.zig 中的会话逻辑逐条执行 SOURCE 段中的语句将实际输出与 OUTPUT 段比对PROBLEMS为NIL意味着该文件当前无需记录任何诊断问题若 REPL 行为发生变化导致输出不一致快照测试即会失败从而充当map_both语义的回归防线。若想手动体验同样行为可以直接在 REPL 中粘贴 SOURCE 段的语句» Try.map_both(Try.Err(failed), |val| val 1, |_| Failed) » Try.map_both!(Try.Err(failed), |val| val 1, |_| Failed) » Try.map_both(Try.Ok(100), |val| val - 50, |_| Failed) » Try.map_both!(Try.Ok(100), |val| val - 50, |_| Failed)预期会得到与快照 OUTPUT 完全一致的Err(Failed)、Err(Failed)、Ok(50.0)、Ok(50.0)。七、总结该快照验证了什么try_map_both.md虽只有 31 行却系统覆盖了Try.map_both的全部关键行为双分支映射Ok与Err各自绑定专属变换函数互不干扰惰性分支求值只运行与当前变体匹配的变换未命中分支完全不执行纯函数与 effectful 版本语义一致map_both与map_both!在分支选择、包装结构上行为相同差异仅在是否允许副作用类型变换自由度Ok/Err 可分别变换为不同的目标类型错误标签可整体替换不可变性与透传对已绑定值施加恒等map_both不会改变原值。这些结论既有快照输出的直接证据又与 Builtin.roc 中match驱动的实现一一对应。对想要深入 Roc 错误处理模型的开发者而言从这样一个最小可复现的 REPL 快照出发配合源码阅读是理解Try组合子语义最直接、最不易出错的路径。【免费下载链接】rocA fast, friendly, functional language.项目地址: https://gitcode.com/GitHub_Trending/ro/roc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

凸极同步发电机电磁计算:非线性磁路建模与饱和耦合求解

凸极同步发电机电磁计算:非线性磁路建模与饱和耦合求解

简介:本资源是一份面向电机设计初学者与电气工程专业学生的凸极同步发电机电磁计算教学文档,聚焦中小型同步发电机(75kW/400V/1500r/min/50Hz)的完整电磁设计流程。文档系统覆盖额定参数选定、磁路几何尺寸计算(含定子…

2026/9/20 18:09:28 阅读更多 →
UI UX Pro Max 装进 Cursor 后,把 Cursor 的 Base URL 改到 TaoToken

UI UX Pro Max 装进 Cursor 后,把 Cursor 的 Base URL 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 22:20:12 阅读更多 →
用91n镜像源加速gpt-oss-20b大模型依赖安装的完整方案

用91n镜像源加速gpt-oss-20b大模型依赖安装的完整方案

我把话放在开头:如果你家里网络下载大模型依赖时经常卡在进度条最后10%、重试三次还失败、一天时间全耗在装环境上,那这篇内容就是写给你看的。实测用91n镜像源给gpt-oss-20b这套依赖做加速,稳定性提升非常明显,单次安装时间能砍掉…

2026/9/20 17:20:56 阅读更多 →

最新新闻

Biome 与 Prettier 兼容性挑战报告深度解读:96%+ 相似度的背后

Biome 与 Prettier 兼容性挑战报告深度解读:96%+ 相似度的背后

Biome 与 Prettier 兼容性挑战报告深度解读:96% 相似度的背后 【免费下载链接】biome A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP. 项目地址: https://gitco…

2026/9/20 23:53:58 阅读更多 →
Docz Monorepo 独立文档包实战:跨 Package 文档化与 docgen 配置全解析

Docz Monorepo 独立文档包实战:跨 Package 文档化与 docgen 配置全解析

文档静态站点开发工具 【免费下载链接】docz ✍ It has never been so easy to document your things! 项目地址: https://gitcode.com/gh_mirrors/do/docz 点击查看 免费下载 本指南以 docz 仓库中的 examples/monorepo-separate-docs 示例为核心,讲解…

2026/9/20 23:53:58 阅读更多 →
FreeUltraCode 不走官方通道,改到 TaoToken 还能一键生成 UMG 吗?

FreeUltraCode 不走官方通道,改到 TaoToken 还能一键生成 UMG 吗?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 23:53:58 阅读更多 →
把 Llama 3.2 智能体的 Base URL 改到 TaoToken 后,自定义 MCP 工具调用怎么跑

把 Llama 3.2 智能体的 Base URL 改到 TaoToken 后,自定义 MCP 工具调用怎么跑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 23:53:57 阅读更多 →
Zephyr 在 PHYTEC phyBOARD-Lyra AM62x A53 上的移植与实战指南

Zephyr 在 PHYTEC phyBOARD-Lyra AM62x A53 上的移植与实战指南

Zephyr 在 PHYTEC phyBOARD-Lyra AM62x A53 上的移植与实战指南 【免费下载链接】zephyr Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures. 项目地址: https://gitcode.…

2026/9/20 23:53:57 阅读更多 →
TDengine 边云协同数据同步实战:边缘推送/云端拉取 × 数据订阅/数据查询 四种方案的选择与配置指南

TDengine 边云协同数据同步实战:边缘推送/云端拉取 × 数据订阅/数据查询 四种方案的选择与配置指南

TDengine 边云协同数据同步实战:边缘推送/云端拉取 数据订阅/数据查询 四种方案的选择与配置指南 【免费下载链接】tdengine TDengine is an open source, high-performance, cloud native time-series database optimized for Internet of Things (IoT), Connecte…

2026/9/20 23:52:57 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →