{"slug": "an-o-x-caml-book-that-runs", "title": "An O(x)Caml book that runs", "summary": "A new OCaml course book for the NPTEL MOOC platform runs code directly in the browser with no installation or server, aiming to eliminate the setup barrier that has long plagued beginners. The book, which covers OCaml and OxCaml, uses a purely client-side approach so learners can edit and execute code immediately. The author built the book with LLM assistance and highlights the zero-step setup as a key innovation.", "body_md": "# An O(x)Caml book that runs\n\n13 Jun 2026I am building a course, “Functional Programming with OCaml”, for the\n[NPTEL](https://onlinecourses.nptel.ac.in/e-learning/preview/noc26_cs90)\nMOOC platform: twelve modules, recorded lectures, the works. The\n[course book](https://fplaunchpad.org/ocaml_nptel) is not a PDF and\nnot a website with code listings you copy elsewhere. It is a website\nwhere the code runs, in your browser, with nothing installed and no\nserver behind it. The first half is\nOCaml; the last few modules cross into OxCaml. An O(x)Caml book, and\none that runs.\n\nThis post is about why I built it that way, how I wrote it (with a lot of help from an LLM, under careful review), and the pieces I think are genuinely new.\n\n## Zero to OCaml in zero steps\n\nThe single biggest obstacle a beginner hits with any language is not a concept. It is the install.\n\nOCaml has gotten much better here over the years. The\n[OCaml Platform extension](https://github.com/ocamllabs/vscode-ocaml-platform)\nfor VS Code will install a compiler toolchain for you, and the\n[ dune](https://dune.build/) build system and the\n\n[package manager have all worked seamlessly together for years now. But that is the experience for someone who already knows they want VS Code, knows what a switch is, and knows what to do when a step does not go as the happy path describes. For a beginner, the path from “I have a laptop” to “I ran my first OCaml program” still has non-trivial steps, and the failure modes are exactly the ones a beginner is least equipped to debug.](https://opam.ocaml.org/)\n\n`opam`\n\nI have lost count of the hours spent at the start of hands-on\nworkshops just getting OCaml onto people’s machines.\n[Anil Madhavapeddy](https://anil.recoil.org/) once told me that he\nand [Yaron Minsky](https://github.com/yminsky) spent almost the\nentire session of their\n[2013 CUFP OCaml tutorial](http://cufp.org/2013/t2-yaron-minsky-anil-madhavapeddy-ocaml-tutorial.html)\ngetting OCaml installed on attendees’ laptops. I have done my share\nof the same, walking a room through `opam`\n\n, and more than once\napologising for the state of Windows support. That last apology I no\nlonger have to make, thanks to the opam team’s work over the past\nfew years (see the\n[opam 2.2.0 alpha announcement](https://ocaml.org/backstage/2023-07-04-opam-2-2-0-alpha)\non native Windows). I have had my own forays into fixing the broader\nproblem: OCaml [Jupyter](https://jupyter.org/) notebooks wrapped in a\n[Docker](https://www.docker.com/) container (I wrote about\n[teaching with Jupyter notebooks](/ocaml/prolog/jupyter/notebooks/2020/01/19/OCaml-Prolog-Jupyter/)\nyears ago, and that is how I taught CS3100), and more recently\ndevcontainers for workshops. The\n[OxCaml ICFP tutorial](https://github.com/avsm/oxcaml-icfp-tutorial)\nand our\n[learn-ocaml workshop](https://github.com/fplaunchpad/learn-ocaml-workshop-2026)\nmaterials both lean on containers too.\n\nThese work, but only in the right setting. In a classroom where people can spend a couple of hours getting dependencies in place, fine. On conference wifi, for a two-hour tutorial, downloading a devcontainer or a Docker image takes all the fun out of programming before any programming has happened.\n\nWhat I wanted was zero to OCaml in zero steps. No install. And, just as importantly, no servers for me to administer. But still a seamless experience where a learner can change code and execute it.\n\nYou are reading the book right now, in a sense. Here is a live cell.\nIf you are in a browser, there is a Run button near the top right.\nClick it. Change `\"reader\"`\n\nto your own name and run it again.\n\nThe OCaml toplevel just ran in your browser. No server, no install, and the bytes never left your machine.\n\n## Why purely client side\n\nThe best thing about programming is that you can poke at it: change something, watch how it reacts, and learn from the reaction. Books cannot be poked. The usual fix is to read with an editor open alongside and type things in, but that always feels slightly off, because the book cannot assume you are playing along. It has no way to know you have the same compiler version, the same libraries, the same anything, so the interactive part drifts out of sync with the prose. I wanted the opposite: a book that assumes you are playing with it, because the playground is built into the page.\n\nWhere this course lives makes that assumption load-bearing. NPTEL is a MOOC; I never meet the students and there are no dedicated labs. A student might be on a laptop shared with a parent, on Windows 11, on a tablet with an external keyboard, or on some machine you would not expect to still be in use and that OCaml very likely does not support. Around 170 people have enrolled so far, and I do not want a single one of them to give up on OCaml over an installation problem in the first hour.\n\nSo the book is purely client side. The website *is* the textbook:\n\nThere is no separate textbook to buy or download. Every lecture in this course is also a page on the course website, and the slides you see in the videos are excerpts from those pages. The website is the book: the same material, expanded into prose, with the examples runnable in place and the quizzes interactive. Open it in any browser; no login, no install, nothing to download.\n\nNone of the individual pieces are new. Running OCaml in the browser\nhas been possible for years: the official\n[playground at ocaml.org](https://ocaml.org/play),\n[TryOCaml](https://try.ocamlpro.com/), [sketch.sh](https://sketch.sh/),\nand `x-ocaml`\n\nitself, which this book is built on. Emulating a whole\nCPU in the browser is not new either, and the quiz idea comes\nstraight from the Brown group. What I think is new is the assembly:\none course where the prose, the slides, the runnable cells, and a\nreal Linux machine are a single artifact, kept correct and\non-pedagogy by its own tooling. The rest of this post is about that\nassembly.\n\n## The book is the slides is the notebook\n\nThere is a second reason the page matters as much as the video. When\nI teach CS3100, the executable notebook *is* the slide deck, thanks\nto the [RISE](https://rise.readthedocs.io/) extension that turns\nJupyter cells into a [reveal.js](https://revealjs.com/) presentation. Students ask questions, and I answer them by live\ncoding in the same surface I am presenting from.\n\nThis book rebuilds that idea, but purely in JavaScript. One markdown source produces the lecture webpage, a reveal.js slide deck, and the runnable cells, all from the same file. Since NPTEL videos show only the slides, the slides have to carry the full content, and because they are generated from the same source as the prose, they cannot drift away from it. More on that machinery below.\n\n## How it is built: two tiers\n\nUnder the hood there are two tiers of execution.\n\nThe **light tier** is the cell you ran above. It is the\n[ x-ocaml](https://github.com/art-w/x-ocaml) WebComponent (Arthur\nWendling’s work), an OCaml 5.4 toplevel compiled to JavaScript with\n\n[. What makes it feel like a real editor rather than a text box is that](https://github.com/ocsigen/js_of_ocaml)\n\n`js_of_ocaml`\n\n[Merlin](https://github.com/ocaml/merlin)runs inside it, in a Web Worker: hover over any expression and you get its inferred type, you get autocompletion as you type, errors are reported inline, and\n\n[will tidy the code on request. Scroll back up and hover over](https://github.com/ocaml-ppx/ocamlformat)\n\n`ocamlformat`\n\n`greeting`\n\nin that first cell; the type\nappears without your running anything. It all runs entirely in the\ntab, your edits persist in local storage, and the whole\nfunctional-programming half of the course lives in cells like it. I\nhave written before about\n[embedding x-ocaml in a blog](/ocaml/x-ocaml/blogging/2025/06/20/xocaml/); this course is what that experiment grew into.\n\nThe **heavy tier** is for when a toplevel is not enough. To run a\ntest suite, measure coverage, compile and run a C program, or build\nand boot an operating system, you need a real project on a real\nmachine: `dune`\n\n, several files, a test runner, a C compiler. So the\nlater modules embed a *full 32-bit\nAlpine Linux machine* that boots inside\nthe browser tab, using the\n\n[v86](https://github.com/copy/v86)x86-to-wasm emulator. It resumes from a compressed snapshot rather than cold-booting, serves its filesystem lazily over 9p (you download only the chunks your commands actually touch), and ships with OCaml 5.4 bytecode,\n\n`dune`\n\n, and [preinstalled. It is about 12 MB to an interactive shell. The promise, quoting the course intro, is the same as the cells:](https://gcc.gnu.org/)\n\n`gcc`\n\nnothing is installed on your computer and nothing runs on a server; the entire machine runs in the page.\n\nHere is one, embedded in this post exactly as it appears in the\ncourse. Click Start, wait a few seconds for the snapshot to load,\nand you land at a shell in a `hello`\n\nproject. Try `ls`\n\n, or\n`dune exec ./hello.exe`\n\nto build and run it, or `cat hello.ml`\n\n. It is\na real Linux machine, booting in this tab, fetching the disk image\non demand from a CDN; nothing is installed on your computer.\n\nThat a student can compile and run real C, or boot a unikernel, on a shared Windows laptop with nothing but a browser tab still feels a little unreasonable to me, in the best way.\n\nThe two tiers trade off very differently, and not only on size. The light cell is OCaml compiled straight to JavaScript, so once the one-time bundle has loaded (about 17 MB gzipped, then cached by the browser) it runs at JavaScript speed: type, Run, done. The VM is the opposite. You are running OCaml bytecode inside a Linux guest inside an x86 machine emulated in WebAssembly, several layers of emulation deep, so it boots in a few seconds and then runs noticeably slower than a real machine would. That is why the light tier carries most of the course and the VM comes out only where a real build genuinely needs it. In both cases “zero install” means nothing is left on your machine, not that nothing is downloaded.\n\n## How I wrote the course: teaching the model how to teach\n\nHere is the honest version of how the chapters got written.\n\nI have recorded video lectures for CS3100, my “Paradigms of\nProgramming” course at IIT Madras (the\n[lectures are on YouTube](https://www.youtube.com/watch?v=9R8Oim7YU20&list=PLt0HgEXFOHdkE-NTs87s7QjwYwqeihb-D)).\nThe pipeline that turns those into drafting material is\n[in the repo](https://github.com/fplaunchpad/ocaml_nptel/tree/main/tools/video-pipeline):\n[ yt-dlp](https://github.com/yt-dlp/yt-dlp) pulls each video from\nthat playlist,\n\n[extracts the audio and uses scene detection to pull out the slide stills, a local](https://ffmpeg.org/)\n\n`ffmpeg`\n\n[Whisper](https://github.com/openai/whisper)model (run on my laptop via Apple’s\n\n[MLX](https://github.com/ml-explore/mlx)) transcribes the audio, and a small script aligns each slide with the narration spoken while it was on screen. The output is a drafting view that pairs every slide image with, in my words, what I said about it. That is a good starting point for a chapter: the model can see the slide and read the explanation.\n\nThe first drafts were rougher than I expected. The *content* was all\nthere; what was missing was the pedagogy. A draft would lean on an\nidea a few paragraphs before introducing it, or state a new concept\nflat instead of setting up the question it answers. The order was the\norder the slides happened to be in, not an order designed to teach.\nThe effect was a chapter that was technically correct and\npedagogically flat: everything present, nothing sequenced to actually\ncarry a reader from not-knowing to knowing.\n\nSo the real work became encoding *how to teach* in a form the model\ncould apply consistently. That turned into a growing set of feedback\nnotes, accumulated as persistent memory the agent loads every\nsession. A few of the recurring ones:\n\n**No forward concepts.** Each module introduces one tool; earlier lectures stay inside the toolbox built so far. Before writing any example, ask what is in the student’s toolbox at this point.**Slides carry the content.** Most students only watch the videos, which show only slides. Every derivation, worked example, and comparison the student needs has to be on a slide, not gestured at.**Fresh activities.** An exercise must not ask for a function the chapter already walked through, even renamed.**No jumps.** The audience knows C and data structures, not FP and not type theory. Every new idea is motivated before use and reached by small steps. This one outranks “be thorough” and “show the powerful example.”\n\nLater modules came out noticeably better than earlier ones, because the notes were richer by the time I got to them, and because I could re-run the review over earlier chapters with the accumulated rules.\n\nThe book should be read as a set of lecture notes rather than a\npolished textbook. It borrows organisation and broad ideas from\n[Cornell’s CS3110](https://cs3110.github.io/textbook/) and\n[Real World OCaml](https://dev.realworldocaml.org/), alongside my own\nCS3100 notes, but I chose the examples and co-developed them\ndeliberately rather than letting them be generated wholesale.\n\n## Under the hood: an executable, self-checking book\n\nOnce you have written down how the book should teach, how do you keep 345,000 words of interactive material from quietly violating those rules as it grows? By hand, you do not. So the build pipeline does the checking.\n\n**The book is executable and checked in CI.** Every runnable\n` ``` ocaml ` cell in the lectures is compiled and run by ```\ndune\nruntest\n```\n\n(via [ ocaml-mdx](https://github.com/realworldocaml/mdx))\non every change. If an example stops\ncompiling, the build fails. There are two nice details here. The\ntest prelude caps the bytecode stack so that a\n\n`Stack_overflow`\n\ndemo\ntrips in CI at the same depth it trips in the browser, instead of\ngrinding for minutes; and it de-fangs [OUnit2](https://github.com/gildor478/ounit)’s argument parsing and exit so that the very same test-suite cells a student runs in the page also run green in CI. The code in the book cannot bit-rot.\n\n**One markdown source, three outputs.** I write lectures with\n[Pandoc](https://pandoc.org/)-style fenced divs:\n\n```\n:::slide\n## Pattern matching\n- Match deconstructs and branches in one step\n:::\n\n:::quiz code id=bmi\nWrite `bmi : float -> float -> float`.\n``` ocaml\nlet bmi mass height = failwith \"not implemented\"\n```\n\n::: ```\n\nThe build (a small OCaml program) turns those into the webpage, the reveal.js deck, and the runnable or checkable cells, all from one file. The slides cannot drift from the prose because they are generated from it.\n\n**Checks beyond “does it compile.”** One script walks every coding\nexercise and flags any that ask the student to reproduce a function\nthe chapter already defined right above it, a repeat the early drafts\nkept slipping in. Alongside it run a per-slide overflow check (every\nslide must fit a 1280x800 canvas, verified by driving a headless\nbrowser), a cross-reference and anchor checker, and a single\npre-recording gate that runs all of it before I record a lecture.\n\n**A composable in-browser toplevel.** The testing module needs\n[QCheck](https://github.com/c-cube/qcheck) and OUnit2 available in the\nbrowser cells. Rather than ship a\nsecond, heavier toplevel, those libraries are layered *onto* the\nexisting one using a small `js_of_ocaml`\n\npatch (`--toplevel-extend`\n\n)\nplus a shim that isolates the extension’s domain-local state, so that\nMerlin’s types-on-hover keeps working in the same page. Getting these\nbundles small enough to ship was its own adventure, which I wrote up\nin\n[shrinking the OxCaml js_of_ocaml bundle from 285 MB to 4 MB](/ocaml/oxcaml/modes/2026/05/10/shrinking-the-oxcaml-bundle/).\n\nOne more small thing I am quietly proud of: each page is stamped with the commit SHA of the source it was built from, and quizzes carry stable ids, so the anonymous feedback (next section) correlates to an exact version of the book and reordering questions never silently re-attaches old answers to a new question.\n\nAll of this is in the open. The\n[course repository](https://github.com/fplaunchpad/ocaml_nptel) is\npublic: the lecture content is under CC BY-NC-SA, and the build\ntoolchain (the markdown-to-site compiler and the quiz backend) is\nISC. If you teach OCaml and want the pipeline, the fenced-div system,\nor the in-browser VM tooling, take it.\n\n## Learning from the learners\n\nI am borrowing an idea from the\n[Brown PLT group’s quiz study](https://rust-book.cs.brown.edu/) for\nthe Rust book. The lectures carry inline quizzes that come, as the\nintro puts it,\n\nin two flavours: multiple-choice questions with explanations, and code-completion challenges where you fill in a function and click\n\nCheckto run a set of tests against your solution.\n\nBecause the code quizzes run their tests in the browser, a code-completion question gives a real pass or fail, not a self-assessment. It is the same cell machinery as the rest of the book: a stub to fill in, a Run button, and a Check that runs hidden tests against your answer.\n\nThe quizzes matter to me because of the feedback loop. The site records anonymous responses: a random per-browser id, no account, no IP address, no personal data, not even a copy of the code you type. I get to see which questions trip people up and fix the material around them. The privacy page has a per-device opt-out and a delete-my-data button. I would much rather find out where readers actually get stuck than guess.\n\n## What is in the book\n\nNine of the twelve modules are recorded; I expect to finish the last three in a week or two. The shape is eight modules of functional programming (values and types, functions and recursion, algebraic data types, pattern matching, higher-order functions, modules and functors, and effects) followed by four on building real systems: testing, memory safety, OxCaml, and unikernels. A few highlights of the content itself.\n\nThe **memory-safety module** is the one I find hardest to believe\nworks. It is the full Linux VM, in the page, and students compile and\nrun real C while watching buffer overflows, use-after-free, and\nundefined behaviour happen live. No install, no separate sandbox, on\nwhatever machine they happen to have.\n\nThe **testing module** has come together really nicely: unit testing\nwith OUnit2, property-based testing with QCheck, and model-based\ntesting, all runnable in the browser. Testing is a natural on-ramp to\nthinking about correctness, and being able to actually run a shrinking\ncounterexample in the page makes the ideas land.\n\nThe **OxCaml module** is the most fun and the most volatile. It grows\nout of the OxCaml lecture in\n[CS6868](https://fplaunchpad.org/cs6868_s26/), my concurrent\nprogramming course at IITM, and covers locality and stack allocation,\nuniqueness,\nlinearity, contention, and portability: the mode system that gives\ndata-race freedom and allocation control. It\nis very new and very likely to keep changing, which is exactly the\npoint. What is the fun in only teaching things that have already\nossified? If you want the deeper version of this material, I have\nwritten about\n[data-race freedom in OxCaml](/ocaml/oxcaml/x-ocaml/blogging/2026/05/07/data-race-freedom-in-oxcaml/)\nand [capsules](/ocaml/oxcaml/modes/blogging/2026/05/08/capsules-in-oxcaml/)\nseparately.\n\nThe ** MirageOS module** at the end builds a\nunikernel from OCaml: a\nlibrary operating system, virtualisation for isolation, and language\nsafety, brought together into a single specialised VM. I will be\nhonest that this module is less hands-on than the rest. A 32-bit VM\nunder wasm cannot build a unikernel quickly, and full qemu emulation\nin the browser would be painfully slow, so the interactive surface is\nthinner here. The thing I would love to reach is booting a\n\n*compiled*unikernel directly in wasm via\n\n[WASI](https://wasi.dev/), with no Linux host underneath at all. That would make the last module as live as the rest.\n\n## LLM use, with the receipts\n\nI wrote this book with an LLM, mostly\n[Claude Code](https://www.anthropic.com/claude-code), and reviewed\nall of it myself. Here is the lifetime token usage for the repo:\n\n| Category | Tokens |\n|---|---|\n| Input (fresh, uncached) | 3.1M |\n| Output | 36.1M |\n| Cache creation | 168.2M |\n| Cache read | 11,055.2M (~11.1B) |\n| Grand total | ~11.26B |\n\nBy model: Opus 4.7 about 5.1B total (14.3M output), Opus 4.8 about 5.1B total (17.4M output), and Fable 5 about 1.1B total (4.4M output).\n\nHow to read this. The headline 11.3B is dominated (98%) by cache reads, which are billed at roughly a tenth of the input rate and are huge only because every turn re-reads the conversation from cache. The figures that reflect real work are output (36M) and cache creation (168M) plus fresh input (3M), call it about 207M tokens of non-cached traffic. At rough Opus list rates that lands somewhere around 2,800 to 3,000 US dollars over the lifetime of the repo, split roughly evenly between Opus 4.7 and 4.8 with Fable adding about ten percent.\n\nWhat actually helped, beyond drafting? Two things.\n\nThe first is fearless, though not perfect, refactoring. “Move this example to that other module, and rewrite everything downstream so it still makes sense” is a request I made constantly, without worrying about the breakages it would cause across two dozen files. The history is full of these: a wholesale redesign of the secure-systems modules, a restructuring of the unikernels module from six lectures down to four, a reframing of a lecture around effects and a typed stack machine. The shape of the development is visible if you plot it:\n\n392 commits over about 25 days. Most of the lecture text lands in the\nfirst three days; after that the cumulative line count is almost\nflat, while the commits keep coming. That flat-but-busy stretch is\nthe point: the bulk of the effort after the initial draft is\nrewriting in place, not adding, and about a quarter of all commits\nare explicit review, audit, or sweep passes. (A caveat on honesty:\nsome individual diffs look enormous, hundreds of thousands of lines,\nbut those are regenerated `js_of_ocaml`\n\nand Wasm bundles committed to\nthe repo, not prose. The line count above is lecture markdown only.)\n\nThe second is review. I have the LLM read chapters back against the\npedagogy notes to catch content that came out of turn: an idea used\nbefore it was introduced, an exercise that duplicates the chapter, a\nslide that overflows. This is the same agentic-review pattern I used\nfor proofs in\n[from convergence to confidence](/verification/rdts/lean/2026/04/28/from-convergence-to-confidence/),\npointed at prose instead of [Rocq](https://rocq-prover.org/).\n\nThere are surely still bugs in the book. For those I take responsibility; the review was mine to do.\n\n## Where this is going: a book that evolves with the reader\n\nHere is what I wish for next.\n\nImagine the book ships with an LLM that acts as a tutor. It sets exercises, takes your feedback, and dynamically rewrites parts of the book as you read, keeping the difficulty where it should be for you specifically: enough challenge to stay engaged, not so much that you give up. For the coding parts, the tutor can close its own loop: write a program, compile it, test it, and only then generate a question from it. That way the questions are produced autonomously but with a real notion of correctness behind them, rather than hallucinated.\n\nTyped languages look especially well suited to this. OCaml’s compiler is a correctness oracle the tutor can lean on, and the entire compile-and-test loop already runs client side here, the light tier for cells and the full VM for real projects, so the tutor needs no server either. The anonymous feedback signal is the seed of this loop, and the LLM-authoring pipeline is the existence proof that the rewriting half is feasible. The best way to learn is still to poke at something and see how it reacts; a book that pokes back, and adjusts, is where I would like this to go.\n\n## Enrol\n\nIf you would like to learn OCaml this way, the course is\n[open for enrolment on NPTEL](https://onlinecourses.nptel.ac.in/e-learning/preview/noc26_cs90)\nuntil 27 July 2026, and it is free. Or just\n[open a lecture](https://fplaunchpad.org/ocaml_nptel) and poke at it.", "url": "https://wpnews.pro/news/an-o-x-caml-book-that-runs", "canonical_source": "https://kcsrk.info/ocaml/oxcaml/teaching/nptel/llm/2026/06/13/an-oxcaml-book-that-runs/", "published_at": "2026-06-13 13:11:04+00:00", "updated_at": "2026-06-13 13:19:36.640997+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["OCaml", "OxCaml", "NPTEL", "VS Code", "Dune", "opam", "Anil Madhavapeddy", "Yaron Minsky"], "alternates": {"html": "https://wpnews.pro/news/an-o-x-caml-book-that-runs", "markdown": "https://wpnews.pro/news/an-o-x-caml-book-that-runs.md", "text": "https://wpnews.pro/news/an-o-x-caml-book-that-runs.txt", "jsonld": "https://wpnews.pro/news/an-o-x-caml-book-that-runs.jsonld"}}