当前位置: 首页 > news >正文

延续抽象副作用:Gleam 中延续的应用及业务逻辑抽象实现

用延续(Continuations)抽象副作用

将错误表示为值是编写可靠程序的强大工具。结果值可以包装所需的值,也可以包含计算失败原因的信息。显式的结果类型在类型系统中体现了失败的可能性,返回结果的函数会迫使调用者处理失败情况。结果类型是一个更广泛模式的具体实例,Promise 表示异步计算,返回一个 Promise 时,调用者必须等待计算完成才能访问值。结果类型和 Promise 各自跟踪计算的特定细节,若要对计算细节进行泛化,可以使用延续。使用延续意味着:“我不清楚你将如何获取值,但当你获取到之后,接下来应该这样处理。”Filinski 在 1994 年发表的论文《Representing Monads》中证明,延续可以表示任何单子,比如结果类型和 Promise。本文不会深入探讨证明的数学原理,而是展示如何在 Gleam 中使用延续。

一个示例

我们使用一个 `fetch` 函数,它根据键返回对应的值。这个函数由调用者提供,接受一个 `String` 类型的键,并返回一个 `String` 类型的值。将 `fetch` 作为参数传入,能让我们根据需要从不同数据源中获取值。一个简单的 `fetch` 实现可以忽略键,始终返回 "yes"。业务逻辑如下:对于一个固定的键列表,将每个键转换为大写,然后返回关联值的长度。

企业级需求

我们的 `simple_func` 运行良好,业务开始拓展。业务逻辑保持不变,但企业客户的数据存储方式多种多样。有些 `fetch` 实现无法总是返回值。为了处理这种情况,我们创建了一个新的业务逻辑版本,其中 `fetch` 返回一个 `Result(String, Nil)`。这个新函数取得了不错的效果,不久后又有了对异步数据存储的需求。另一个接受返回 `Promise(String)` 的 `fetch` 函数的实现解决了这个问题。此时,我们有了三个实现来满足所有不同的需求。每个版本的业务逻辑相同,函数也很相似,但我们没有在不同实现之间复用业务逻辑。更糟糕的是,我们还面临着对可能失败的异步实现的需求,即 `fetch` 返回 `Promise(Result(String, Nil))`。我们无法复用之前的可能失败或异步的实现,需要为函数编写第四个实现。

缺失的抽象

不同实现之间的差异仅在于 `fetch` 执行的计算类型:直接计算、可能失败的计算、异步计算或其他类型。每个实现的共同点是如何创建键,以及在值可用时如何处理它。延续允许我们表示这种“前后”关系,同时对计算类型进行泛化。我们创建一个新的版本,接受返回 `Continuation(t, String)` 的 `fetch`。这个任务现在对计算类型进行了泛化。调用者将通过提供的 `fetch` 实现来选择 `t` 的具体类型。为了提取最终值,调用者需要提供一个最终回调函数。基于延续的任务的调用者通常被称为运行器或解释器。

简单运行器

在简单情况下,`fetch` 没有额外的副作用,并且总是返回一个字符串。它仍然返回一个延续,因此最终值用 `continuation.return` 包装。由于最终值会被解包,所以将恒等函数作为最终回调函数传入。这个简单运行器返回一个 `List(Int)`,表明 `fetch` 本身是可靠且同步的。

可能失败的运行器

当 `fetch` 返回 `Result(String, Nil)` 时,我们的最终回调函数也必须返回一个结果。因此,最终回调函数用 `Ok` 包装值。`then` 是恢复任务的回调函数,它在值存在时被调用。

异步运行器

当 `fetch` 是异步时,运行器将 `t` 选为 `Promise(List(Int))`。最终回调函数使用 `promise.resolve` 来匹配 `t`。

结论

有了 `task`,我们对业务逻辑有了单一的定义。它描述了如何使用值,而不考虑值是如何获取的。运行器决定如何获取值。任何以这种方式编写的任务都可以使用相同的运行器。这种逻辑和副作用的分离就是延续为我们提供的抽象。

我正在构建 EYG,这是一个关于构建更好的语言和工具的实验;这里的“更好”是有一定衡量标准的。所有进展都会在我的不定期时事通讯中汇报。

http://www.jsqmd.com/news/1205704/

相关文章:

  • 解决华为eNSP与VirtualBox在Win11上的兼容性问题
  • 2026螺旋板式换热器怎么选不踩雷?优质厂家实力排名 全工况选购攻略 - 资讯在线
  • TrollInstallerX终极教程:3分钟搞定iOS 14-16.6.1 TrollStore安装的完整指南
  • Dify平台:AI应用开发与RAG技术实践指南
  • AI解决数学难题?拆解GPT模型能力边界与验证方法
  • C++ string进阶:find、substr与关系运算符实战解析
  • 如何轻松管理游戏DLSS版本:玩家必备的智能工具终极指南
  • 2026在广州怎么高价出手闲置奢侈品?速看这篇回收门店测评! - 全国二奢机构参考
  • 解决Windows磁盘8MB空间无法删除的终极方案
  • wild-wild-path vs 其他路径工具:为什么它是处理复杂对象的最佳选择
  • Phigros高难度谱面操作分析:从珍贵录像中提取音游进阶技巧
  • 基于大数据的亚健康人群的分析系统的设计与实现
  • CW32开发板ADC电压采集与优化实践
  • AI代码审查工具altimate-code:原理、部署与实战集成指南
  • 5分钟解决Unity游戏插件加载难题:BepInEx完全指南
  • 2026年沈阳空乘艺考培训挑选攻略 博冠国际教育等机构服务梳理 - 资讯在线
  • 【软考备考】流水线计算详解:吞吐率、加速比、效率,看懂时空图就不用背公式(附 10 道练习)
  • XbsjEarthUI开发模式对比:dev vs dev2 vs build模式深度解析
  • AwesomeSplash适配指南:多分辨率、多版本Android系统的兼容性处理
  • LSP Plugins性能优化:如何获得最佳音频处理性能的10个技巧
  • 5分钟上手mini-coder-4b-OptiQ-4bit:Python代码生成实例教程
  • Claude提示词工程:从CRAM原则到高效模板实战
  • Solod:让 Go 代码无缝转换为 C 代码,零运行时开销带来新编程体验!
  • 移动新闻客户端个性化推荐系统
  • 大模型应用安全实战:基于OWASP Top 10构建纵深防御体系
  • Flutie源码深度解析:理解Rails视图助手的设计模式与实现原理
  • GLM Coding Plan抢购困境解析与智能编程替代方案实战
  • CPU在AI计算中的优化技术与实践
  • Nginx+CentOS高性能Web服务器部署与优化指南
  • 2026年沈阳本科单招集训机构盘点:博冠国际教育及行业优质机构梳理 - 资讯在线