OCaml 提议中的 include functor 语法如何减少重复

原标题How OCaml's Proposed Include Functor Syntax Reduces Repetition

一个反向数组示例展示如何从最小实现派生常用模块函数,同时省去额外的包装模块。

频道
Jane Street
发布
2024年8月7日
视频
8:06
阅读
3 分钟
幻灯片
4
原文
英语
在 YouTube 打开
往下滚动阅读时,视频会缩到右下角继续播放。字幕跟随阅读语言。
阅读语言共 2 种语言可读
由 AI 从英语原文翻译。打开“对照原文”可以逐段核对。
摘要

30 秒看懂

一位 Jane Street 演讲者演示在其 OCaml 编译器分支中开发、并提议合并到上游的实验性 include functor 语法。他从数组映射接口出发,构造一个提供派生操作的函子,展示传统的包装模块方式,再用新语法取而代之。

  1. 1可映射接口接口提供 map、iter,以及同样传入键的 mapi 和 iteri。数组实现使用整数键。
  2. 2反向遍历反向数组实现处理空数组,并从末尾开始访问元素。当传入的函数有副作用时,遍历顺序很重要。
  3. 3派生其余操作忽略键参数即可从 mapi 和 iteri 构造 map 和 iter,因此可以用可复用的函子实现这一常见模式。
  4. 4包装模块的样板代码传统方法将最小定义放入一个模块,包含该模块,再包含将函子应用于它的结果。
  5. 5include functor提议中的语法使用当前模块中先前的定义来应用函子,省去了显式包装模块和额外的 include。

要点建议

  1. 模块接口可以暴露由较少核心操作派生出的便利函数。
  2. 在示例中,忽略键参数即可从 mapi 和 iteri 定义 map 和 iter。
  3. 函子可以将这些派生定义打包,供多个模块复用。
  4. 传统方法将已有定义放入模块,再分别包含该模块和函子应用的结果。
  5. 提议中的 include functor 语法直接将函子应用于当前模块中先前的定义,无需显式包装模块。
全文

按章节阅读整理后的全文

只看原始文稿
01

提议中的模块便利语法

演讲者介绍在 Jane Street 编译器分支中开发、正考虑合并到上游的 include functor。Mappable 签名展示了重复的实现模式。

我想介绍 include functor,这项功能在 Jane Street 的 OCaml 编译器分支中开发,我们正在努力将其合并到上游。它简化了一种常见模式:编写模块的核心部分,再利用可复用的逻辑补全其余部分。视频简介中提供了演示所用编译器的链接。

Mappable 签名
幻灯片 1 / 4Mappable 签名签名定义了 map、iter 和接收键的 mapi、iteri 操作。

考虑一个名为 Mappable 的模块类型,它包含数据类型、键和四项操作:map、iter,以及其函数还会接收键的 mapi 和 iteri。数组可以直接实现这个接口:键是 int,数据类型是数组,四个函数可以使用对应的数组操作。

02

反向数组与派生函数

反向实现从最后一个元素开始定义带索引的操作。忽略索引即可派生普通操作。

现在假设我们想要另一个从后往前遍历的数组模块。当迭代函数有副作用时,顺序很重要。键和数据类型保持不变,但 mapi 反向工作:它单独处理空数组,将函数应用于最后一个元素以初始化结果,然后依次向前填充剩余位置,直到索引零。

反向数组遍历
幻灯片 2 / 4反向数组遍历实现从后向前遍历,并在 mapi 中处理空数组。

反向 iteri 更简单,它使用一个递减的 for 循环。但我不想再写一次 map 和 iter。只要忽略额外的键参数,就能从 mapi 和 iteri 派生它们;每次实现 Mappable 时都可以使用同样的模式。如果效率需要,我们仍然可以提供专门的实现。

03

可复用函子及其样板代码

签名被拆分为最小接口和额外操作。用传统方式应用函子需要包装模块和显式 include。

函子可以将这种常见派生方式打包。首先,我将接口拆成 Mappable_minimal 和完整的 Mappable:前者包含类型和带索引的操作,后者包含最小部分并增加 map 和 iter。函子 Make_map_iter 接收一个符合 Mappable_minimal 的模块 M。

在 Make_map_iter 内,map 调用 M.mapi,传入一个忽略第一个参数、并对其余输入应用指定函数的函数。iter 对 M.iteri 做同样的处理。编译器推断出预期签名,于是我们就有了一个可复用的方法来生成这两个普通操作。

用传统语法把该函子应用于反向数组定义比较繁琐。我需要把这些定义包装在模块 M 中,include M,再 include Make_map_iter(M)。这样可以工作,但需要额外的包装和显式包含;如果没有外层签名,M 本身也会保持可见。

使用包装模块应用函子
幻灯片 3 / 4使用包装模块应用函子传统版本包含模块 M,以及 Make_map_iter(M) 的结果。
04

使用 include functor

新语法将函子应用于当前模块中先前的定义,并包含结果。演讲者简要指出它也适用于模块类型。

include functor 省去了这个包装。将核心定义直接写在模块中之后,我写下 include functor Make_map_iter。从概念上说,它将函子应用于模块中已有的定义,并包含结果。因此我只需定义核心功能,就能获得其余部分,无须重复编写额外模块和 include。

include functor 语法
幻灯片 4 / 4include functor 语法新语法无需显式包装模块,就能将 Make_map_iter 应用于先前的定义。

该语法也适用于模块类型,在那里它会包含函子的模块类型,不过这种用法不如实现示例常见。文档中有更多相关细节。

同频道的其他文章

1:48:29EN → 简体中文
JSJane Street· 2026年10月16日AI 如何改变编程:John Krazit 与 Ron Minsky 的对话Ron Minsky, John Krazit · Jane StreetJane Street 的 AI 工具负责人和 Signals and Threads 主持人探讨智能体基础设施、安全、代码审查,以及软件开发体验的变化。编程智能体Developer productivity评估+2
9 张幻灯片1:05:45EN → 简体中文
JSJane Street· 2026年9月11日Cyrus Omar:实时编程与人与 AI 共享的计算公共空间Cyrus Omar通过 Hazel 演示,探讨即时反馈、结构化协作和精细权限如何帮助人类与 AI 智能体共同工作。Programming LanguagesHuman-AI Collaboration开发流程与测试+2
1:25:00EN → 简体中文
JSJane Street· 2026年9月2日Eric Mannes:如何将杂乱的外部数据用于交易研究Ron, Eric Mannes · Jane Street从商品期货和 Excel 风险系统,到时点数据集和 AI,Eric Mannes 解释 Jane Street 数据工程背后的领域知识。Data quality & curation开发流程与测试Investing+2
7 张幻灯片1:16:29EN → 简体中文
JSJane Street· 2026年8月26日Grant Sanderson 与 Alok Puranik:从群论看位置编码Grant Sanderson, Alok Puranik · 3Blue1Brown从注意力机制的假设出发,他们推导矩阵指数,并将旋转、衰减和 Jordan 块与 RoPE、ALiBi 联系起来。Transformers & attentionMathematics机器学习基础+1
4:41EN → 简体中文
JSJane Street· 2026年7月6日走进 Jane Street 实习项目:工作、导师与学习Cody · Jane Street实习生和员工讲述协作式面试、从零学习金融,以及参与公司实际使用的项目的经历。CareersCompany CultureMachine Learning+1
1:34:29EN → 简体中文
JSJane Street· 2026年6月24日Jacob Baskin:构建 Superstore 与调度 HiveYaron Minsky, Jacob Baskin · Jane Street这位 Jane Street 工程师回顾分布式分析数据库背后的设计选择,以及为不断扩大的研究集群分配资源的挑战。基础设施与部署Software engineeringDecision Making+1