一本可运行的O(x)Caml书籍

Hacker News Top 产品

摘要

KC Sivaramakrishnan宣布了一本面向NPTEL的交互式OCaml课程书籍,该书籍可直接在浏览器中运行代码,无需安装和维护服务器。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/16 00:02

# 一本可运行的 O(x)Caml 书籍 · KC Sivaramakrishnan 来源:https://kcsrk.info/ocaml/oxcaml/teaching/nptel/llm/2026/06/13/an-oxcaml-book-that-runs/ 2026年6月13日 我正在为NPTEL (https://onlinecourses.nptel.ac.in/e-learning/preview/noc26_cs90)MOOC平台构建一门课程《函数式编程与OCaml》,包含十二个模块的录播讲座。课程教材 (https://fplaunchpad.org/ocaml_nptel)既不是PDF,也不是那种让你把代码复制到别处运行的网站。它是一个代码真正能运行的网站——在你的浏览器里运行,无需安装任何东西,背后也没有服务器。前半部分讲的是 OCaml;最后几个模块则进入了 OxCaml 的领域。一本 O(x)Caml 的书籍,而且是可运行的。 这篇文章将说明我为什么选择这样的构建方式,以及我是如何编写它的(大量借助了 LLM 的帮助,并经过仔细审核)。 这也是一份征求意见的呼吁:如果你有任何让课程变得更好的想法,或者发现材料中有任何错误,请告诉我。课程仍在不断完善中,我希望尽可能为即将学习的学生提供最好的体验。 ## 零步骤从零到 OCaml 初学者在学习任何语言时遇到的最大障碍不是概念理解,而是安装。 多年来,OCaml 在这方面已经有了显著改善。用于VS Code 的OCaml Platform 扩展 (https://github.com/ocamllabs/vscode-ocaml-platform)可以自动安装编译工具链,`dune` (https://dune.build/)构建系统和`opam` (https://opam.ocaml.org/)包管理器多年来也一直无缝协作。但这是针对那些已经知道自己想用 VS Code、知道什么是 switch、知道当某一步不按预期进行时该怎么处理的人。对于一个初学者来说,从「我有一台笔记本电脑」到「我运行了第一个 OCaml 程序」之间仍然存在一些不小的步骤,而故障模式恰恰是初学者最不擅长调试的。 我已经记不清在实操工作坊开始时花了多少时间,只为让 OCaml 在大家的机器上运行起来。Anil Madhavapeddy (https://anil.recoil.org/)曾告诉我,他和Yaron Minsky (https://github.com/yminsky)在2013年的CUFP OCaml 教程 (http://cufp.org/2013/t2-yaron-minsky-anil-madhavapeddy-ocaml-tutorial.html)中,几乎把整个会议时间都花在了帮与会者安装 OCaml 上。我自己也做过同样的事情,带着一屋子人过一遍`opam`,还不止一次为 Windows 支持状况道歉。现在,由于 opam 团队过去几年的努力(参见关于原生 Windows 的opam 2.2.0 alpha 公告 (https://ocaml.org/backstage/2023-07-04-opam-2-2-0-alpha)),我最后一次道歉已经不需要了。我也曾试图解决这个更广泛的问题:将OCamlJupyter (https://jupyter.org/)笔记本封装在Docker (https://www.docker.com/)容器中(我多年前写过关于使用 Jupyter 笔记本教学 (https://kcsrk.info/ocaml/prolog/jupyter/notebooks/2020/01/19/OCaml-Prolog-Jupyter/)的文章,那也是我教授 CS3100 的方式),以及最近用于工作坊的 devcontainer。OxCaml ICFP 教程 (https://github.com/avsm/oxcaml-icfp-tutorial)和我们的learn-ocaml 工作坊 (https://github.com/fplaunchpad/learn-ocaml-workshop-2026)材料也依赖容器。 这些方法在合适的场合是可行的。在教室里,人们可以花几个小时把依赖关系搞定,这没问题。但在会议 wifi 环境下,一个两小时的教程,下载 devcontainer 或 Docker 镜像就已经把编程的乐趣消耗殆尽,还没开始编程呢。 我想要的是零步骤从零到 OCaml。无需安装。同样重要的是,不需要我来管理服务器。但依然要提供无缝的体验,让学习者可以修改代码并执行它。 某种意义上,你现在就在阅读这本书。这是一个实时单元格。如果你在浏览器中,右上角附近有一个运行按钮。点击它。将`"reader"`改为你自己的名字,再次运行。 let greeting who = "hello, " ^ who let () = print_endline (greeting "reader")OCaml 顶层就在你的浏览器中运行了。没有服务器,无需安装,字节从未离开你的机器。 ## 为什么纯客户端 编程最美妙的地方在于你可以戳它一下:改改东西,观察它的反应,从中学习。书是不能被戳的。通常的解决方法是,旁边打开一个编辑器,边读边输入代码,但这总是感觉有点不对劲,因为书无法假设你正在一起操作。它无从知道你是否拥有相同的编译器版本、相同的库、相同的任何东西,因此交互部分就会和正文脱节。我想要相反的效果:一本假设你正在和它互动的书,因为游乐场就内置在页面中。 这门课程的存在方式让这一点更加重要。NPTEL 是一个 MOOC;我从不见到学生,也没有专门的实验室。学生可能在使用与家长共享的笔记本电脑、Windows 11、带有外接键盘的平板电脑,或者某种你意想不到仍在使用的机器,而 OCaml 很可能不支持它。目前大约有 170 人注册,我不想让其中任何一个人因为在第一个小时遇到安装问题而放弃 OCaml。 所以这本书是纯客户端的。网站*就是*教科书: > 没有单独的教材需要购买或下载。本课程的每一讲都是课程网站上的一个页面,视频中的幻灯片就是这些页面的摘录。网站即书籍:同样的内容,以散文形式展开,示例可原地运行,测验可交互。在任何浏览器中打开;无需登录,无需安装,无需下载。 没有哪个单独的组件是新的。在浏览器中运行 OCaml 已经可能多年:官方的 ocaml.org 练习场 (https://ocaml.org/play)、TryOCaml (https://try.ocamlpro.com/)、sketch.sh (https://sketch.sh/),以及构建本书所用的`x-ocaml`本身。我认为新的地方在于将这些组件整合在一起:一门课程中,散文、幻灯片、可运行单元格和完整的 Linux 机器都是同一回事,并且有工具保证它们正确且一致。这篇文章的其余部分将介绍具体方法。 ## 单一来源:页面、幻灯片、单元格 页面与视频同等重要还有第二个原因。当我教授 CS3100 时,可执行笔记本*就是*幻灯片,这要归功于RISE (https://rise.readthedocs.io/)扩展,它将 Jupyter 单元格转换为reveal.js (https://revealjs.com/)演示文稿。学生提问,我通过在我演示的同一个界面中进行实时编码来回答。 这本书重建了那个想法,但纯用 JavaScript 实现。一个 markdown 源文件同时生成讲座网页、reveal.js 幻灯片和可运行单元格,全部来自同一个文件。由于 NPTEL 视频只显示幻灯片,幻灯片必须承载全部内容,而且因为它们与散文来自同一个源文件,所以不会与正文脱节。关于底层机制,后面会详述。 幻灯片视图中的一讲幻灯片,包含要点和嵌入在幻灯片上的可运行 OCaml 单元格,带有运行按钮 ## 构建方式:两个层级 在底层,有两个执行层级。 **轻量层级**就是上面你运行的那个单元格。它是`x-ocaml` (https://github.com/art-w/x-ocaml)WebComponent(Arthur Wendling (https://github.com/art-w) 的作品),一个使用`js_of_ocaml` (https://github.com/ocsigen/js_of_ocaml)编译为 JavaScript 的 OCaml 5.4 顶层。让它感觉像真正的编辑器而不是文本框的,是Merlin (https://github.com/ocaml/merlin)在其中运行,位于一个 Web Worker 中:将鼠标悬停在任何表达式上,你就能得到其推断出的类型,输入时获得自动补全,错误会内联报告,并且`ocamlformat` (https://github.com/ocaml-ppx/ocamlformat)可以应要求整理代码。向上滚动,将鼠标悬停在第一个单元格中的`greeting`上;无需运行任何东西,类型就会显示出来。这一切完全在标签页中运行,你的编辑内容会保存在本地存储中,课程中整个函数式编程部分都存在于这样的单元格中。我之前写过关于在博客中嵌入 x-ocaml (https://kcsrk.info/ocaml/x-ocaml/blogging/2025/06/20/xocaml/)的文章;这门课程就是那个实验发展而来的产物。 **重量层级**用于顶层不足以解决问题的情况。要运行测试套件、测量覆盖率、编译并运行 C 程序,或者构建并启动一个操作系统,你需要一个真实机器上的真实项目:`dune`、多个文件、测试运行器、C 编译器。因此,后面的模块嵌入了一个*完整的 32 位Alpine Linux (https://alpinelinux.org/)机器*,它在浏览器标签页内启动,使用v86 (https://github.com/copy/v86) x86 到 wasm 的模拟器。它从压缩快照恢复,而不是冷启动,通过 9p 协议按需提供文件系统(你只下载命令实际触及的块),并预装了 OCaml 5.4 字节码、`dune`和`gcc` (https://gcc.gnu.org/)。从交互式 shell 开始大约需要 12 MB。引用课程介绍中的承诺,与单元格一样: > 你的电脑上什么也没安装,服务器上也没有运行任何东西;整个机器都在页面中运行。 下面就是一个,以课程中完全相同的格式嵌入在这篇文章中。点击开始,等待几秒钟让快照加载,你就会在一个`hello`项目的 shell 中。试试`ls`,或者`dune exec ./hello.exe`来构建并运行它,或者`cat hello.ml`。这是一个真正的 Linux 机器,在这个标签页中启动,按需从 CDN 获取磁盘映像;你的电脑上什么也没安装。 学生可以在共享的 Windows 笔记本电脑上,仅凭一个浏览器标签页,编译并运行真正的 C 语言,或者启动一个 unikernel。 两个层级的权衡非常不同,不仅体现在大小上。轻量单元格是将 OCaml 直接编译为 JavaScript,因此一次性包加载后(约 17 MB gzipped,然后由浏览器缓存),它以 JavaScript 的速度运行。虚拟机则相反。你是在 WebAssembly 模拟的 x86 机器内部的 Linux 客户机中运行 OCaml 字节码,经过多层模拟,因此它启动需要几秒钟,然后运行速度明显比真实机器慢。这就是为什么轻量层级承载了课程的大部分内容,而虚拟机只在真正需要实际构建时才出现。在这两种情况下,「零安装」意味着你的机器上不会留下任何东西,而不是什么都不下载。 ## 我是如何编写课程的:教会模型如何教学 我已经为 CS3100 录制了视频讲座,这是我在印度理工学院马德拉斯分校的课程《编程范式》(讲座在 YouTube 上 (https://www.youtube.com/watch?v=9R8Oim7YU20&list=PLt0HgEXFOHdkE-NTs87s7QjwYwqeihb-D))。将这些视频转化为草稿材料的流程在仓库中 (https://github.com/fplaunchpad/ocaml_nptel/tree/main/tools/video-pipeline):`yt-dlp` (https://github.com/yt-dlp/yt-dlp)从那个播放列表中拉取每个视频,`ffmpeg` (https://ffmpeg.org/)提取音频并使用场景检测提取幻灯片静态图像,一个本地的Whisper (https://github.com/openai/whisper)模型(在我的笔记本电脑上通过 Apple 的MLX (https://github.com/ml-explore/mlx)运行)转录音频,一个小脚本将每张幻灯片与它显示时的旁白对齐。输出是一个草稿视图,每张幻灯片图像旁边都放着,用我自己的话说,我当初对它的讲解。这是一个章节很好的起点:模型可以看到幻灯片并阅读解释。 初稿比我预期的要粗糙。*内容*都已经有了;缺少的是教学法。更大的问题是,模型很难只引入一个模块需要的内容,而不超出。它总是跳到那些典型学生不熟悉或者属于课程后部分的概念:在介绍某个想法之前几段就已经在依赖它,或者直接陈述一个新概念,而不是先铺垫它要回答的问题。顺序是幻灯片恰好出现的顺序,而不是设计用来教学的顺序。这个神谕什么都知道,并且急于展示;我需要的不是一个神谕,而是一个老师。这个差距有一个名字:教学内容知识 (https://www.wcu.edu/webfiles/pdfs/shulman.pdf),这是独立于学科知识本身之外的教学方法。LLM 可能是知识的诅咒 (https://en.wikipedia.org/wiki/Curse_of_knowledge)最纯粹的例子:它天生不具备感知任何特定读者还不知道什么的能力。 因此,真正的工作变成了将*如何教学*编码成模型可以一致应用的形式。这变成了一套不断增长的反馈笔记,作为持久记忆累积,代理每次会话都会加载。其中几个反复出现的要点: - **无超前概念。**每个模块只介绍一个工具;前面的讲座始终保持在目前为止已建立的工具箱内。在编写任何示例之前,先问问学生此时该有什么工具。 - **幻灯片承载内容。**大多数学生只看视频,而视频只显示幻灯片。学生需要的所有推导、工作示例和比较都必须在幻灯片上,不能只是口头提及。 - **新鲜的练习。**练习题不能要求实现本章已经讲解过的函数,即使改个名字也不行。 - **无跳跃。**受众了解 C 语言和数据结构,而不是函数式编程和类型理论。每个新想法在使用前都要先说明动机,并通过小步骤达到。这条规则优先于「要详尽」和「展示强大的例子」。 后面的模块明显比前面的模块好,因为等我写到它们时,笔记更丰富了,而且我可以用累积的规则重新审核前面的章节。 这本书应该被视为讲义的集合,而不是一本精良的教科书。它借鉴了康奈尔大学 CS3110 (https://cs3110.github.io/textbook/)和《Real World OCaml》(https://dev.realworldocaml.org/)的组织结构和广泛思想,以及我自己的 CS3100 笔记,但我选择了示例,并故意与它们共同开发,而不是让它们被整体生成。 ## 幕后:一本可执行、可自我检查的书 一旦你写下了书应该如何教学,如何在 34.5 万字的交互式材料增长过程中防止它们悄悄违反这些规则?靠手工是不行的。因此构建流程来执行检查。 **这本书是可执行的,并在 CI 中检查。**讲座中每个可运行的 ````ocaml ` 单元格都会在每次更改时被编译并通过`dune runtest`运行(通过`ocaml-mdx` (https://github.com/realworldocaml/mdx))。如果某个示例停止编译,构建就会失败。这里有两个不错的细节。测试的前缀设置了字节码栈的限制,这样 CI 中`Stack_overflow`演示在同样的深度触发,而不是耗时几分钟;它还去掉了OUnit2 (https://github.com/gildor478/ounit)的参数解析和退出功能,使得学生在页面中运行的完全相同测试套件单元格也能在 CI 中通过。书中的代码不会腐化。 **一个 markdown 源文件,三种输出。**我使用Pandoc (https://pandoc.org/)风格的围栏 div 来编写讲座: ``` :::slide ## 模式匹配 - 匹配在一步中完成解构和分支 ::: :::quiz code id=bmi 编写 `bmi : float -> float -> float`。 ```ocaml let bmi mass height = failwith "not implemented" ``` ::: ``` 构建过程(一个小的 OCaml 程序)将这些转换为网页、reveal.js 幻灯片和可运行或可检查的单元格,全部来自同一个文件。幻灯片不会与散文脱节,因为它们是由散文生成的。 **超出「是否能编译」的检查。**一个脚本会遍历每个编程练习,标记任何要求学生重现本章刚刚在上面定义过的函数的练习,这是早期草稿中经常出现的重复。与此同时,还运行每张幻灯片的溢出检查(每张幻灯片必须适合 1280x800 的画布,通过驱动无头浏览器验证)、跨引用检查(确保

相似文章

太空中的O(x)Caml

Hacker News Top

一个纯OCaml实现的CCSDS协议栈,代号Borealis,在低地球轨道上的DPhi Space ClusterGate-2载荷模块上成功启动,展示了在太空中安全且高性能的OCaml。

OxCaml 中的数据竞态自由

Lobsters Hottest

OxCaml 是 Jane Street 对 OCaml 编译器的分支,它引入了编译时对数据竞态的保证,从而在不增加运行时开销的情况下实现顺序一致性。这篇博文解释了新的模式轴及其对并行编程的影响。

OCaml 入门:Dune 构建系统简介

Hacker News Top

一份实用指南,介绍适用于 OCaml 的 Dune 构建系统,涵盖项目设置、库和可执行文件的构建以及测试。

cuda-oxide 手册

Lobsters Hottest

cuda-oxide 是一个实验性的 Rust 到 CUDA 编译器,允许开发者编写安全、符合 Rust 惯用法的 GPU 内核,并直接编译为 PTX。

@KanikaBK: https://x.com/KanikaBK/status/2057778635365626231

X AI KOLs Timeline

一个全面的课程,介绍如何使用Claude Artifacts构建交互式应用程序,涵盖Artifacts的类型、工作原理以及逐步指导如何创建工具、仪表板、游戏和计算器,无需编写代码。