Roc 语言 Try.map_both 实战:从 REPL 快照测试看懂 Ok/Err 双分支映射语义

发布时间:2026/9/19 16:54:25

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),仅供参考
延伸阅读

更多相关文章

2026/9/19 16:54:25

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

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

2026/9/19 16:49:24

核心银行系统架构与存款业务实现:从客户信息到账务核对

简介:一份聚焦银行业核心系统基础知识的完整资料,面向银行新入职员工、核心系统运维与开发人员及金融IT项目人员,帮助快速建立从银行IT系统分类到核心业务系统模块的整体认知。资源为1个DOC文档,大小约1.54MB,内容覆盖…

2026/9/19 16:49:24

UE5摄像机抖动指南:Perlin噪点原理与Sequence实战调优

做游戏的人都知道,镜头是玩家和游戏世界之间的那层玻璃。镜头稍微抖一下,爆炸就有了重量;镜头处理得太平,再猛的场面也像在放幻灯片。UE5里实现摄像机抖动的方式不少,但最常用、最可控的路线,还是Perlin噪点…

2026/9/19 17:54:28

24位Δ-Σ ADC选型指南:ADS127L21动态范围与低功耗配置实战

1. 为什么ADS127L21值得单独拿出来聊第一次在选型表里看到ADS127L21的时候,我正为一个振动监测项目头疼。前端传感器输出信号幅度很小,现场又有电机和变频器在捣乱,之前用的16位ADC在50kSPS下有效位数掉得厉害,频谱底噪抬起来之后…

2026/9/19 17:54:28

FPGA实习报告工程化指南:从代码到bitstream的闭环实践

简介:本资源是一份完整的FPGA生产实习报告文档,面向电子工程、集成电路与数字系统设计方向的本科生及初学者,聚焦Verilog硬件描述语言实践与QuartusModelsim开发流程落地。报告系统梳理了FPGA开发核心环节:从阻塞/非阻塞赋值语法辨…

2026/9/19 17:54:28

知识产权交易平台建设方案:数据模型、哈希链与状态机设计

简介:2021年知识产权交易平台建设方案借鉴资料,面向政府园区、科技服务机构、高校成果转化部门及平台运营方,用于解决科技成果转化率不高、知识产权交易不活跃、科技型企业融资困难等问题。方案提出“一二三四五”建设思路,即一套…

2026/9/19 17:54:28

智慧党校智能化规划设计与实施路径全解析

简介:《智慧党校智能化规划设计方案PPT(41页)》是一份面向党校信息化主管部门、智慧校园集成商与基建规划人员的完整建设方案,系统梳理了智慧党校九大平台、校园网扁平化改造、无线覆盖优化、网络安全等保合规以及运维服务运营体系…

2026/9/19 17:49:28

GIS与遥感工程术语中英对照:从概念到代码落地

简介:本资源是一份面向遥感、地理信息系统(GIS)及空间信息相关专业学生与从业者的专业术语双语对照学习文档,聚焦遥感基础概念与GIS核心术语的中英文精准释义,有效解决跨语言文献阅读、外文资料理解及学术交流中的术语…

2026/9/18 14:13:01

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/19 0:03:10

验证 OpenSpec 兼容性,Cursor 的 Token 从 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/19 0:03:10

书桌角落的 Mac mini,OpenClaw 通过 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/19 0:03:10

oh-my-hermes:打造跨工具的命令编排与插件化工作流

1. 项目概述与设计初衷1.1 它到底是什么先说结论:oh-my-hermes 是一个面向开发者日常终端操作的效率工具套件,核心定位是“把分散在各类命令行工具里的高频操作,统一收拢成一套插件化、可编排的工作流”。项目灵感来源很明显——oh-my-zsh 重…

2026/9/18 14:13:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/18 14:13:02

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/18 14:13:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码