{"id":27301048,"url":"https://github.com/lukstafi/curious-ocaml","last_synced_at":"2026-01-23T16:11:58.089Z","repository":{"id":68296430,"uuid":"594639333","full_name":"lukstafi/curious-ocaml","owner":"lukstafi","description":"A curious book about OCaml: logic (types), algebra (values), computation (rewrite semantics), functions (lambda calculus), constraints, monads, algebraic effects, expression.","archived":false,"fork":false,"pushed_at":"2026-01-20T20:14:00.000Z","size":30807,"stargazers_count":35,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-21T04:41:20.987Z","etag":null,"topics":["computer-science","functional-programming","ocaml"],"latest_commit_sha":null,"homepage":"https://lukstafi.github.io/curious-ocaml/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lukstafi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-29T06:55:17.000Z","updated_at":"2026-01-20T20:14:05.000Z","dependencies_parsed_at":"2023-02-27T20:45:23.572Z","dependency_job_id":"e8ca7275-0869-497d-a03e-3919f3658f1d","html_url":"https://github.com/lukstafi/curious-ocaml","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lukstafi/curious-ocaml","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukstafi%2Fcurious-ocaml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukstafi%2Fcurious-ocaml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukstafi%2Fcurious-ocaml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukstafi%2Fcurious-ocaml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukstafi","download_url":"https://codeload.github.com/lukstafi/curious-ocaml/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukstafi%2Fcurious-ocaml/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28695529,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T15:57:05.722Z","status":"ssl_error","status_checked_at":"2026-01-23T15:56:27.656Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computer-science","functional-programming","ocaml"],"created_at":"2025-04-12T01:33:33.817Z","updated_at":"2026-01-23T16:11:58.057Z","avatar_url":"https://github.com/lukstafi.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\ntitle: Curious OCaml\nauthor:\n  - Lukasz Stafiniak\n  - Claude Opus 4.5\n  - GPT-5.2\nheader-includes:\n  - \u003clink rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css\"\n       integrity=\"sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV\" crossorigin=\"anonymous\"\u003e\n  - \u003cscript defer src=\"https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js\"\n       integrity=\"sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8\"\n       crossorigin=\"anonymous\"\u003e\u003c/script\u003e\n  - \u003cscript defer src=\"https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js\"\n       integrity=\"sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05\" crossorigin=\"anonymous\"\n       onload=\"renderMathInElement(document.body);\"\u003e\u003c/script\u003e\n  - |\n    \u003cscript\u003e\n    document.addEventListener('DOMContentLoaded', function() {\n      const toc = document.getElementById('TOC');\n      if (!toc) return;\n\n      const tocLinks = toc.querySelectorAll('a[href^=\"#\"]');\n      const headings = [];\n\n      tocLinks.forEach(link =\u003e {\n        const id = link.getAttribute('href').slice(1);\n        const heading = document.getElementById(id);\n        if (heading) {\n          headings.push({ id, link, heading });\n        }\n      });\n\n      function updateActiveLink() {\n        const scrollPos = window.scrollY + 100;\n\n        let current = null;\n        for (const item of headings) {\n          if (item.heading.offsetTop \u003c= scrollPos) {\n            current = item;\n          } else {\n            break;\n          }\n        }\n\n        tocLinks.forEach(link =\u003e link.classList.remove('toc-active'));\n        toc.querySelectorAll('li').forEach(li =\u003e li.classList.remove('toc-active'));\n\n        if (current) {\n          current.link.classList.add('toc-active');\n          let parent = current.link.closest('li');\n          while (parent \u0026\u0026 toc.contains(parent)) {\n            parent.classList.add('toc-active');\n            parent = parent.parentElement?.closest('li');\n          }\n          if (window.innerWidth \u003e 900) {\n            current.link.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n          }\n        }\n      }\n\n      let ticking = false;\n      window.addEventListener('scroll', function() {\n        if (!ticking) {\n          requestAnimationFrame(function() {\n            updateActiveLink();\n            ticking = false;\n          });\n          ticking = true;\n        }\n      });\n\n      updateActiveLink();\n    });\n    \u003c/script\u003e\ndocumentclass: report\nclassoption:\n  - openany\nfontsize: 11pt\ngeometry:\n  - margin=1in\ntoc-depth: 3\n---\n\u003c!-- Do NOT modify this file, it is automatically generated --\u003e\n# Curious OCaml\n\n*Curious OCaml* invites you to explore programming through the lens of types, logic, and algebra. OCaml is a language that rewards curiosity—its type system catches errors before your code runs, its functional style encourages clear thinking about data transformations, and its mathematical foundations reveal deep connections between programming and logic. Whether you're new to programming, experienced with OCaml, or a seasoned developer discovering functional programming for the first time, this book aims to spark that \"aha!\" moment when abstract concepts click into place.\n\nThis book is intended for three audiences:\n\n- New to programming: ambitious students in areas with formal rigor -- math, computer science, philosophy, linguistics, etc.\n- Intermediate: OCaml programmers.\n- Advanced: programmers who are new to functional programming.\n\n\n## Chapter 1: Logic\n\n*From logic rules to programming constructs*\n\n**In this chapter, you will:**\n\n- Learn natural-deduction rules for the core connectives ($\\top, \\bot, \\wedge, \\vee, \\rightarrow$)\n- Practice reading and building derivation trees (including hypothetical derivations)\n- See the Curry–Howard correspondence emerge in OCaml typing rules\n- Connect logical reasoning patterns (cases, induction) to programming patterns (pattern matching, recursion)\n\n**Conventions.** OCaml code blocks are intended to be runnable unless marked with `ocaml skip` (used for illustrative or partial snippets).\n\nThroughout this chapter we use *natural deduction* in the style of intuitionistic (constructive) logic. This choice is not accidental: it is exactly the fragment of logic that lines up with the “pure” core of functional programming via the Curry–Howard correspondence.\n\n### 1.1 In the Beginning there was Logos\n\nWhat logical connectives do you know? Before we write any code, let us take a step back and think about logic itself. The connectives listed below form the foundation of reasoning, and as we will discover, they also form the foundation of programming.\n\n| $\\top$ | $\\bot$ | $\\wedge$ | $\\vee$ | $\\rightarrow$ |\n|---|---|---|---|---|\n|   |   | $a \\wedge b$ | $a \\vee b$ | $a \\rightarrow b$ |\n| truth | falsehood | conjunction | disjunction | implication |\n| \"trivial\" | \"impossible\" | $a$ and $b$ | $a$ or $b$ | $a$ gives $b$ |\n|   | shouldn't get | got both | got at least one | given $a$, we get $b$ |\n\nHow can we define these connectives precisely? The key insight is to think in terms of *derivation trees*. A derivation tree shows how we arrive at conclusions from premises, building up knowledge step by step:\n\n$$\n\\frac{\n\\frac{\\frac{\\,}{\\text{a premise}} \\; \\frac{\\,}{\\text{another premise}}}{\\text{some fact}} \\;\n\\frac{\\frac{\\,}{\\text{this we have by default}}}{\\text{another fact}}}\n{\\text{final conclusion}}\n$$\n\nWe define connectives by providing rules for using them. For example, a rule $\\frac{a \\; b}{c}$ matches parts of the tree that have two premises, represented by variables $a$ and $b$, and have any conclusion, represented by variable $c$. These variables act as placeholders that can match any proposition.\n\n**Design principle:** When defining a connective, we try to use only that connective in its definition. This keeps definitions self-contained and avoids circular dependencies between connectives.\n\n### 1.2 Rules for Logical Connectives\n\nEach logical connective comes with two kinds of rules:\n\n**Introduction rules** tell us how to *produce* or *construct* a connective. If you want to prove \"A and B\", the introduction rule tells you what you need: proofs of both A and B.\n\n**Elimination rules** tell us how to *use* or *consume* a connective. If you already have \"A and B\", the elimination rules tell you what you can get from it: either A or B (your choice).\n\nIn the table below, text in parentheses provides informal commentary. Letters like $a$, $b$, and $c$ are variables that can stand for any proposition.\n\n| Connective | Introduction Rules | Elimination Rules |\n|------------|-------------------|-------------------|\n| $\\top$ | $\\frac{}{\\top}$ | doesn't have |\n| $\\bot$ | doesn't have | $\\frac{\\bot}{a}$ (i.e., anything) |\n| $\\wedge$ | $\\frac{a \\quad b}{a \\wedge b}$ | $\\frac{a \\wedge b}{a}$ (take first) \u0026nbsp; $\\frac{a \\wedge b}{b}$ (take second) |\n| $\\vee$ | $\\frac{a}{a \\vee b}$ (put first) \u0026nbsp; $\\frac{b}{a \\vee b}$ (put second) | $\\frac{a \\vee b \\quad \\genfrac{}{}{0pt}{}{[a]^x}{\\vdots \\; c} \\quad \\genfrac{}{}{0pt}{}{[b]^y}{\\vdots \\; c}}{c}$ using $x, y$ |\n| $\\rightarrow$ | $\\frac{\\genfrac{}{}{0pt}{}{[a]^x}{\\vdots \\; b}}{a \\rightarrow b}$ using $x$ | $\\frac{a \\rightarrow b \\quad a}{b}$ |\n\n#### Notation for Hypothetical Derivations\n\nThe notation $\\genfrac{}{}{0pt}{}{[a]^x}{\\vdots \\; b}$ (sometimes written as a tree) matches any subtree that derives $b$ and can use $a$ as an assumption (marked with label $x$), even though $a$ might not otherwise be warranted. The square brackets around $a$ indicate that this is a *hypothetical* assumption, not something we have actually established. The superscript $x$ is a label that helps us track which assumption gets \"discharged\" when we complete the derivation.\n\nThis is the key to proving implications: to prove \"if A then B\", we temporarily assume A and show we can derive B. For example, we can derive \"sunny $\\rightarrow$ happy\" by showing that *assuming* it is sunny, we can derive happiness:\n\n$$\n\\frac{\\frac{\\frac{\\frac{\\frac{\\,}{\\text{sunny}}^x}{\\text{go outdoor}}}{\\text{playing}}}{\\text{happy}}}{\\text{sunny} \\rightarrow \\text{happy}} \\text{ using } x\n$$\n\nNotice how the assumption \"sunny\" (marked with $x$) appears at the top of the derivation tree. We use this assumption to derive \"go outdoor\", then \"playing\", and finally \"happy\". Once we complete the derivation, the assumption is *discharged*: we no longer need to assume it is sunny because we have established the conditional \"sunny $\\rightarrow$ happy\".\n\nA crucial point: such assumptions can only be used within the matched subtree! However, they can be used *multiple times* within that subtree. For example, if someone's mood is more difficult to influence and requires multiple sunny conditions:\n\n$$\n\\frac{\\frac{\n  \\frac{\\frac{\\frac{\\,}{\\text{sunny}}^x}{\\text{go outdoor}}}{\\text{playing}} \\quad\n  \\frac{\\frac{\\,}{\\text{sunny}}^x \\quad \\frac{\\frac{\\,}{\\text{sunny}}^x}{\\text{go outdoor}}}{\\text{nice view}}\n}{\\text{happy}}}{\\text{sunny} \\rightarrow \\text{happy}} \\text{ using } x\n$$\n\nIn this more complex derivation, the assumption \"sunny\" (labeled $x$) is used three times: once to derive \"go outdoor\", and twice more in deriving \"nice view\". All three uses are valid because they occur within the same hypothetical subtree.\n\n#### Reasoning by Cases\n\nThe elimination rule for disjunction deserves special attention because it represents **reasoning by cases**, one of the most fundamental proof techniques.\n\nSuppose we know \"A or B\" is true, but we do not know which one. How can we still derive a conclusion C? We must show that C follows *regardless* of which alternative holds. In other words, we need to prove: (1) assuming A, we can derive C, and (2) assuming B, we can derive C. Since one of A or B must be true, and both lead to C, we can conclude C.\n\nHere is a concrete example: How can we use the fact that it is sunny $\\vee$ cloudy (but not rainy)?\n\n$$\n\\frac{\n  \\frac{\\,}{\\text{sunny} \\vee \\text{cloudy}}^{\\text{forecast}} \\quad\n  \\frac{\\frac{\\,}{\\text{sunny}}^x}{\\text{no-umbrella}} \\quad\n  \\frac{\\frac{\\,}{\\text{cloudy}}^y}{\\text{no-umbrella}}\n}{\\text{no-umbrella}} \\text{ using } x, y\n$$\n\nWe know that it will be sunny or cloudy (by watching the weather forecast). Now we reason by cases: *If* it will be sunny, we will not need an umbrella. *If* it will be cloudy, we will not need an umbrella. Since one of these must be the case, and both lead to the same conclusion, we can confidently say: we will not need an umbrella.\n\n#### Reasoning by Induction\n\nWe need one more kind of rule to do serious math: **reasoning by induction**. This rule is somewhat similar to reasoning by cases, but instead of considering a finite number of alternatives, it allows us to prove properties that hold for infinitely many cases, such as all natural numbers.\n\nHere is the example rule for induction on natural numbers:\n\n$$\n\\frac{p(0) \\quad \\genfrac{}{}{0pt}{}{[p(x)]^x}{\\vdots \\; p(x+1)}}{p(n)} \\text{ by induction, using } x\n$$\n\nThis rule says: we get property $p$ for *any* natural number $n$, provided we can do two things:\n\n1. **Base case:** Establish $p(0)$, that is, prove the property holds for zero.\n2. **Inductive step:** Show that *assuming* $p(x)$ holds for some arbitrary $x$, we can derive $p(x+1)$. This assumption $p(x)$ is called the *induction hypothesis*.\n\nHere $x$ is a unique variable representing an arbitrary natural number. We cannot substitute a particular number for it because we write \"using $x$\" on the side, indicating that the derivation works for any choice of $x$.\n\nThe power of induction lies in this: once we have the base case and the inductive step, we have implicitly covered *all* natural numbers. Starting from $p(0)$, we can derive $p(1)$, then $p(2)$, then $p(3)$, and so on, reaching any natural number $n$ we wish.\n\n### 1.3 Logos was Programmed in OCaml\n\nWe now arrive at one of the most remarkable discoveries in the foundations of computer science: the **Curry–Howard correspondence**, also known as \"propositions as types\" or the \"proofs-as-programs\" interpretation. In a pure, intuitionistic setting, this correspondence is not just a metaphor: proof rules and typing rules are the same kind of object.\n\nUnder this correspondence:\n\n- **Propositions** (logical statements) correspond to **types**\n- **Proofs** (derivations showing a proposition is true) correspond to **programs** (expressions of a given type)\n- **Introduction rules** correspond to **constructors** (ways to build values)\n- **Elimination rules** correspond to **destructors** (ways to use values)\n\nWhen you write a well-typed program, you are (implicitly) constructing a derivation tree that proves a typing judgement.\n\nThe following table shows how each logical connective corresponds to a programming construct in OCaml:\n\n| Logic | OCaml type (example) | Example program | Intuition |\n|-------|------|------------|-----------|\n| $\\top$ | `unit` | `()` | The trivially true proposition; the type with exactly one value |\n| $\\bot$ | `void` (an empty type) | `match v with _ -\u003e .` | Falsehood; a type with no values |\n| $\\wedge$ | `*` | `(,)` | Conjunction corresponds to pairs: having both A and B |\n| $\\vee$ | a variant type | `Left x` / `Right y` | Disjunction corresponds to sums: having either A or B |\n| $\\rightarrow$ | `-\u003e` | `fun` | Implication corresponds to functions: given A, produce B |\n| induction | - | `let rec` | Inductive proofs correspond to recursive definitions |\n\nFor example, the identity function corresponds to the tautology $a \\rightarrow a$:\n\n```ocaml env=ch1\n# fun x -\u003e x;;\n- : 'a -\u003e 'a = \u003cfun\u003e\n```\n\nLet us now see the precise typing rules for each OCaml construct, presented in the same style as our logical rules:\n\n**Typing rules for OCaml constructs:**\n\n- **Unit (truth):** $\\frac{}{\\texttt{()} : \\texttt{unit}}$\n\n  The unit value `()` always has type `unit`. This is like $\\top$ in logic: we can always produce it without any premises.\n\n- **Empty type (falsehood):** in OCaml we can *define* an empty type (a type with no constructors):\n\n  ```ocaml env=ch1\n  type void = |\n  ```\n\n  There is no way to construct a value of type `void` using ordinary, terminating code. But if we somehow have a `v : void`, then we can derive anything from it (falsity elimination):\n\n  ```ocaml env=ch1\n  let absurd (v : void) : 'a =\n    match v with _ -\u003e .\n  ```\n\n  This corresponds closely to the logical rule $\\frac{\\bot}{a}$.\n\n  OCaml also has *effects* (notably exceptions). Because `raise e` never returns normally, the type checker allows it to have any result type:\n  $$\n  \\frac{e : \\texttt{exn}}{\\texttt{raise } e : a}\n  $$\n  This is useful in practice, but it is also a good reminder that effects complicate the neat “proofs-as-programs” story.\n\n- **Pair (conjunction):**\n  - Introduction: $\\frac{s : a \\quad t : b}{(s, t) : a * b}$\n  - Elimination: from `p : a * b` we can extract either component (e.g. by pattern matching, or via `fst`/`snd`)\n\n  To construct a pair, you need both components. To use a pair, you can extract either component. This mirrors conjunction perfectly: to prove \"A and B\", you need proofs of both; given \"A and B\", you can conclude either A or B.\n\n- **Variant (disjunction):** first, we define a sum type (a two-way choice):\n\n  ```ocaml env=ch1\n  type ('a, 'b) either = Left of 'a | Right of 'b\n  ```\n\n  - Introduction: from `x : a` we get `Left x : (a, b) either`, and from `y : b` we get `Right y : (a, b) either`\n  - Elimination: given `t : (a, b) either` and a branch for each case, produce a result `c` (pattern matching)\n\n  The shape of the elimination rule is exactly “reasoning by cases”: to use an `either`, you must handle both `Left` and `Right`.\n\n  ```ocaml env=ch1\n  let either f g = function\n    | Left x -\u003e f x\n    | Right y -\u003e g y\n  ```\n\n  A built-in example is `bool`, which you can think of as a two-constructor variant; the `if ... then ... else ...` expression is just a specialized form of case analysis on a boolean.\n\n  ```ocaml env=ch1\n  let choose b x y =\n    if b then x else y\n\n  let choose' b x y =\n    match b with\n    | true -\u003e x\n    | false -\u003e y\n  ```\n\n  To construct a variant, you only need one of the alternatives. To use a variant, you must handle *all* possible cases (pattern matching). This mirrors disjunction: to prove \"A or B\", you only need one; to use \"A or B\", you must consider both possibilities.\n\n- **Function (implication):**\n  - Introduction: $\\frac{\\genfrac{}{}{0pt}{}{[x : a]}{\\vdots \\; e : b}}{\\texttt{fun}~x \\to e : a \\to b}$\n  - Elimination (application): $\\frac{f : a \\to b \\quad t : a}{f~t : b}$\n\n  To construct a function, you assume you have an input of type $a$ (the parameter $x$) and show how to produce a result of type $b$. To use a function, you apply it to an argument. This mirrors implication: to prove \"A implies B\", assume A and derive B; given \"A implies B\" and A, conclude B.\n\n- **Recursion (induction):** recursion is not a connective, but it matches the *shape* of induction: in a recursive definition you are allowed to assume the function being defined (the “induction hypothesis”) when defining its body.\n\n  In OCaml, recursion is introduced with `let rec` (there is no standalone `rec` expression).\n\n#### Definitions\n\nWriting out expressions and types repetitively quickly becomes tedious. More importantly, without definitions we cannot give names to our concepts, making code harder to understand and maintain. This is why we need definitions.\n\n**Type definitions** are written: `type ty =` some type.\n\n- In OCaml, disjunction-like types are not written as something like `a | b` directly; instead, you define a *variant type* and then use its constructors. For example:\n  ```ocaml env=ch1\n  type int_string_choice = A of int | B of string\n  ```\n  This allows us to write `A x : int_string_choice` for any `x : int`, and `B y : int_string_choice` for any `y : string`.\n\n- Why do we need to define variant types? The reasons are: exhaustiveness checks, performance of generated code, and ease of type inference. When OCaml sees `A 5`, it needs to figure out (or \"infer\") the type. Without a type definition, how would OCaml know whether this is `A of int | B of string` or `A of int | B of float | C of bool`? The definition tells OCaml exactly what variants exist. When you match `| A i -\u003e ...`, the compiler will warn you if you forgot to also cover `C b` in your match patterns.\n\n- OCaml does provide an alternative: *polymorphic variants*, written with a backtick. We can write `` `A x : [ `A of a | `B of b ] ``. With `` ` `` variants, OCaml does infer what other variants might exist based on usage. These types are powerful and flexible; we will discuss them in chapter 11.\n\n- Tuple elements do not need labels because we always know at which position a tuple element stands: the first element is first, the second is second, and so on. However, having labels makes code much clearer, especially when tuples have many components or components of the same type. For this reason, we can define a *record type*:\n\n  ```ocaml env=ch1\n  type int_string_record = { a : int; b : string }\n  ```\n\n  and create its values: `{a = 7; b = \"Mary\"}`. OCaml 5.4 and newer also support labeled tuples, we will not discuss these.\n\n- We access the *fields* of records using the dot notation: `{a = 7; b = \"Mary\"}.b = \"Mary\"`. Unlike tuples where you must remember \"the second element is the name\", with records you can write `.b` to get the field named `b`.\n\n#### Expression Definitions\n\nIn many presentations of the Curry–Howard correspondence (and in programming language theory), recursion is introduced via a standalone operator often called `fix`. OCaml does not have a standalone `fix` expression: recursion is introduced only as part of a `let rec` definition.\n\nThis brings us to **expression definitions**, which let us give names to values. The typing rules for definitions are a bit more complex than what we have seen so far:\n\n$$\n\\frac{e_1 : a \\quad \\genfrac{}{}{0pt}{}{[x : a]}{\\vdots \\; e_2 : b}}{\\texttt{let } x = e_1 \\texttt{ in } e_2 : b}\n$$\n\nThis rule says: if $e_1$ has type $a$, and assuming $x$ has type $a$ we can show that $e_2$ has type $b$, then the whole `let` expression has type $b$. Interestingly, this rule is equivalent to introducing a function and immediately applying it: `let x = e1 in e2` behaves the same as `(fun x -\u003e e2) e1`. This equivalence reflects a deep connection in the Curry–Howard correspondence.\n\nFor recursive definitions, we need an additional rule:\n\n$$\n\\frac{\\genfrac{}{}{0pt}{}{[x : a]}{\\vdots \\; e_1 : a} \\quad \\genfrac{}{}{0pt}{}{[x : a]}{\\vdots \\; e_2 : b}}{\\texttt{let rec } x = e_1 \\texttt{ in } e_2 : b}\n$$\n\nNotice the crucial difference: in the recursive case, $x$ can appear in $e_1$ itself! This is what allows functions to call themselves. The name $x$ is visible both in its own definition ($e_1$) and in the body that uses the definition ($e_2$).\n\nThese rules are slightly simplified. The full rules involve a concept called **polymorphism**, which we will cover in a later chapter. Polymorphism explains how the same function can work with different types.\n\n#### Scoping Rules\n\nUnderstanding *scope*—where names are visible—is essential for reading and writing OCaml programs.\n\n- **Type definitions** we have seen above are *global*: they need to be at the top-level (not nested in expressions), and they extend from the point they occur till the end of the source file or interactive session. You cannot define a type inside a function.\n\n- **`let`-`in` definitions** for expressions: `let x = e1 in e2` are *local*—the name $x$ is only visible within $e_2$. Once you exit the `in` part, $x$ no longer exists. This is useful for temporary values that should not pollute the global namespace.\n\n- **`let` definitions** without `in` are global: placing `let x = e1` at the top-level makes $x$ visible from after $e_1$ till the end of the source file or interactive session. This is how you define functions and values that the rest of your program can use.\n\n- In the interactive session (toplevel/REPL), we mark the end of a top-level \"sentence\" with `;;`. This tells OCaml \"I am done typing, please evaluate this.\" In source files compiled by the build system, `;;` is unnecessary because the end of each definition is clear from context.\n\n#### Operators\n\nOperators like `+`, `*`, `\u003c`, `=` are simply names of functions. In OCaml, there is nothing magical about operators; they are ordinary functions that happen to have special characters in their names and can be used in infix position (between their arguments).\n\nJust like other names, you can define your own operators:\n\n```ocaml env=ch1\n# let (+:) a b = String.concat \"\" [a; b];;\nval ( +: ) : string -\u003e string -\u003e string = \u003cfun\u003e\n# \"Alpha\" +: \"Beta\";;\n- : string = \"AlphaBeta\"\n```\n\nNotice the asymmetry here: when *defining* an operator, we wrap it in parentheses to tell OCaml \"this is the name I am defining\". When *using* the operator, we write it in the normal infix position between its arguments. This asymmetry exists because the definition syntax needs to distinguish between \"the name `+:`\" and \"the expression `a +: b`\".\n\nAn important feature of OCaml is that operators are **not overloaded**. This means that a single operator cannot work for multiple types. Each type needs its own set of operators:\n\n- `+`, `*`, `/` work for integers\n- `+.`, `*.`, `/.` work for floating point numbers\n\nThis design choice makes type inference simpler and more predictable. When you see `x + y`, OCaml knows immediately that `x` and `y` must be integers.\n\n**Exception:** The comparison operators `\u003c`, `=`, `\u003c=`, `\u003e=`, `\u003c\u003e` do work for all values other than functions. These are called *polymorphic comparisons*.\n\n### 1.4 Exercises\n\nThe following exercises are adapted from *Think OCaml: How to Think Like a Computer Scientist* by Nicholas Monje and Allen Downey. They will help you get comfortable with OCaml's syntax and type system.\n\n1. Assume that we execute the following assignment statements:\n   ```ocaml env=ch1\n   let width = 17\n   let height = 12.0\n   let delimiter = '.'\n   ```\n   For each of the following expressions, write the value of the expression and the type (of the value of the expression), or the resulting type error.\n   1. `width/2`\n   2. `width/.2.0`\n   3. `height/3`\n   4. `1 + 2 * 5`\n   5. `delimiter * 5`\n\n2. Practice using the OCaml interpreter as a calculator:\n   1. The volume of a sphere with radius $r$ is $\\frac{4}{3} \\pi r^3$. What is the volume of a sphere with radius 5? (*Hint:* 392.6 is wrong!)\n   2. Suppose the cover price of a book is \\$24.95, but bookstores get a 40% discount. Shipping costs \\$3 for the first copy and 75 cents for each additional copy. What is the total wholesale cost for 60 copies?\n   3. If I leave my house at 6:52 am and run 1 mile at an easy pace (8:15 per mile), then 3 miles at tempo (7:12 per mile) and 1 mile at easy pace again, what time do I get home for breakfast?\n\n3. You've probably heard of the Fibonacci numbers before, but in case you haven't, they're defined by the following recursive relationship:\n   $$\n   \\begin{cases}\n   f(0) = 0 \\\\\n   f(1) = 1 \\\\\n   f(n+1) = f(n) + f(n-1) \u0026 \\text{for } n = 2, 3, \\ldots\n   \\end{cases}\n   $$\n   Write a recursive function to calculate these numbers.\n\n4. A palindrome is a word that is spelled the same backward and forward, like \"noon\" and \"redivider\". Recursively, a word is a palindrome if the first and last letters are the same and the middle is a palindrome.\n\n   The following are functions that take a string argument and return the first, last, and middle letters:\n   ```ocaml env=ch1\n   let first_char word = word.[0]\n   let last_char word =\n     let len = String.length word - 1 in\n     word.[len]\n   let middle word =\n     let len = String.length word - 2 in\n     String.sub word 1 len\n   ```\n   1. Enter these functions into the toplevel and test them out. What happens if you call `middle` with a string with two letters? One letter? What about the empty string `\"\"`?\n   2. Write a function called `is_palindrome` that takes a string argument and returns `true` if it is a palindrome and `false` otherwise.\n\n5. The greatest common divisor (GCD) of $a$ and $b$ is the largest number that divides both of them with no remainder.\n\n   One way to find the GCD of two numbers is Euclid's algorithm, which is based on the observation that if $r$ is the remainder when $a$ is divided by $b$, then $\\gcd(a, b) = \\gcd(b, r)$. As a base case, we can consider $\\gcd(a, 0) = a$.\n\n   Write a function called `gcd` that takes parameters `a` and `b` and returns their greatest common divisor.\n\n   If you need help, see [http://en.wikipedia.org/wiki/Euclidean_algorithm](http://en.wikipedia.org/wiki/Euclidean_algorithm).\n\n\n## Chapter 2: Algebra\n\n*Algebraic data types and some curious analogies*\n\nIn this chapter, we will deepen our understanding of OCaml's type system by working through type inference examples by hand. Then we will explore algebraic data types---a cornerstone of functional programming that allows us to define rich, structured data. Along the way, we will discover a surprising and beautiful connection between these types and ordinary polynomials from high-school algebra.\n\n**In this chapter, you will:**\n\n- Practice type inference by hand (constraints, unification intuition)\n- Define and manipulate algebraic data types (variants, records, recursion, parameters)\n- Interpret types as polynomials (and learn what this analogy buys you)\n- Differentiate types to compute “one-hole contexts” (derivatives of data structures)\n\n### 2.1 A Glimpse at Type Inference\n\nFor a refresher, let us apply the type inference rules introduced in Chapter 1 to some simple examples. We will start with the identity function `fun x -\u003e x`---perhaps the simplest possible function, yet one that reveals important aspects of polymorphism. In the derivations below, $[?]$ means “unknown (to be inferred)”.\n\nWe begin with an incomplete derivation:\n\n$$\n\\frac{[?]}{\\texttt{fun x -\u003e x} : [?]}\n$$\n\nUsing the $\\rightarrow$ introduction rule, we need to derive the body `x` assuming `x` has some type $a$:\n\n$$\n\\frac{\\genfrac{}{}{0pt}{}{[x : a]^x}{\\vdots \\; \\texttt{x} : a}}{\\texttt{fun x -\u003e x} : [?] \\rightarrow [?]}\n$$\n\nThe premise is a hypothetical derivation: inside the body we are allowed to use the assumption `x : a`. Since the body is just `x`, the result type is also $a$, and we conclude:\n\n$$\n\\frac{\\genfrac{}{}{0pt}{}{[x : a]^x}{\\vdots \\; \\texttt{x} : a}}{\\texttt{fun x -\u003e x} : a \\rightarrow a}\n$$\n\nBecause $a$ is arbitrary (we made no assumptions constraining it), OCaml introduces a *type variable* `'a` to represent it. This is how polymorphism emerges naturally from the inference process---the identity function can work with values of any type:\n\n```ocaml env=ch2\n# fun x -\u003e x;;\n- : 'a -\u003e 'a = \u003cfun\u003e\n```\n\n#### A More Complex Example\n\nNow let us try something that will constrain the types more: `fun x -\u003e x+1`. This is the same as `fun x -\u003e ((+) x) 1` (try it in OCaml to verify!). The addition operator forces specific types upon us.\n\nWe will use the notation $[?\\alpha]$ to mean \"type unknown yet, but the same as in other places marked $[?\\alpha]$.\" This notation helps us track how constraints propagate through the derivation.\n\nStarting the derivation and applying $\\rightarrow$ introduction:\n\n$$\n\\frac{\\frac{[?]}{\\texttt{((+) x) 1} : [?\\alpha]}}{\\texttt{fun x -\u003e ((+) x) 1} : [?] \\rightarrow [?\\alpha]}\n$$\n\nApplying $\\rightarrow$ elimination (function application) to `((+) x) 1`:\n\n$$\n\\frac{\\frac{\\frac{[?]}{\\texttt{(+) x} : [?\\beta] \\rightarrow [?\\alpha]} \\quad \\frac{[?]}{\\texttt{1} : [?\\beta]}}{\\texttt{((+) x) 1} : [?\\alpha]}}{\\texttt{fun x -\u003e ((+) x) 1} : [?] \\rightarrow [?\\alpha]}\n$$\n\nWe know that `1 : int`, so $[?\\beta] = \\texttt{int}$:\n\n$$\n\\frac{\\frac{\\frac{[?]}{\\texttt{(+) x} : \\texttt{int} \\rightarrow [?\\alpha]} \\quad \\frac{\\,}{\\texttt{1} : \\texttt{int}}^{\\text{(constant)}}}{\\texttt{((+) x) 1} : [?\\alpha]}}{\\texttt{fun x -\u003e ((+) x) 1} : [?] \\rightarrow [?\\alpha]}\n$$\n\nApplying function application again to `(+) x`:\n\n$$\n\\frac{\\frac{\\frac{\\frac{[?]}{\\texttt{(+)} : [?\\gamma] \\rightarrow \\texttt{int} \\rightarrow [?\\alpha]} \\quad \\frac{[?]}{\\texttt{x} : [?\\gamma]}}{\\texttt{(+) x} : \\texttt{int} \\rightarrow [?\\alpha]} \\quad \\frac{\\,}{\\texttt{1} : \\texttt{int}}^{\\text{(constant)}}}{\\texttt{((+) x) 1} : [?\\alpha]}}{\\texttt{fun x -\u003e ((+) x) 1} : [?\\gamma] \\rightarrow [?\\alpha]}\n$$\n\nSince `(+) : int -\u003e int -\u003e int`, we have $[?\\gamma] = \\texttt{int}$ and $[?\\alpha] = \\texttt{int}$:\n\n$$\n\\frac{\\frac{\\frac{\\frac{\\,}{\\texttt{(+)} : \\texttt{int} \\rightarrow \\texttt{int} \\rightarrow \\texttt{int}}^{\\text{(constant)}} \\quad \\frac{\\,}{\\texttt{x} : \\texttt{int}}^x}{\\texttt{(+) x} : \\texttt{int} \\rightarrow \\texttt{int}} \\quad \\frac{\\,}{\\texttt{1} : \\texttt{int}}^{\\text{(constant)}}}{\\texttt{((+) x) 1} : \\texttt{int}}}{\\texttt{fun x -\u003e ((+) x) 1} : \\texttt{int} \\rightarrow \\texttt{int}}\n$$\n\n#### Curried Form\n\nWhen there are several arrows \"on the same depth\" in a function type, it means that the function returns a function. For example, `(+) : int -\u003e int -\u003e int` is just a shorthand for `(+) : int -\u003e (int -\u003e int)`. The arrow associates to the right, so we can omit the parentheses.\n\nThis is very different from:\n\n$$\n\\texttt{fun f -\u003e (f 1) + 1} : (\\texttt{int} \\rightarrow \\texttt{int}) \\rightarrow \\texttt{int}\n$$\n\nIn the first case, `(+)` is a function that takes an integer and returns a function from integers to integers. In the second case, we have a function that takes a function as an argument---a *higher-order function*. The parentheses around `int -\u003e int` are essential here; without them, the meaning would be completely different.\n\nThis style of defining multi-argument functions, where each function takes one argument and returns another function expecting the remaining arguments, is called *curried form* (named after logician Haskell Curry). It enables a powerful technique called *partial application*.\n\nFor example, instead of writing `(fun x -\u003e x+1)`, we can simply write `((+) 1)`. Here we apply `(+)` to just one argument, getting back a function that adds 1 to its input. What expanded form does `((+) 1)` correspond to exactly (computationally)?\n\n*Think about it before reading on...*\n\nIt corresponds to `fun y -\u003e 1 + y`. We have \"baked in\" the first argument, and the resulting function waits for the second.\n\nWe will become more familiar with functions returning functions when we study the *lambda calculus* in a later chapter.\n\n### 2.2 Algebraic Data Types\n\nIn Chapter 1, we learned about the `unit` type and variant types like:\n\n```ocaml env=ch2\ntype int_string_choice = A of int | B of string\n```\n\nWe also covered tuple types, record types, and type definitions. Now let us explore these concepts more deeply, building up to the powerful notion of *algebraic data types*.\n\n#### Variants Without Arguments\n\nVariants do not have to carry arguments. Instead of writing `A of unit`, we can simply use `A`. This is more convenient and idiomatic:\n\n```ocaml env=ch2\ntype color = Red | Green | Blue\n```\n\nThis defines a type with exactly three possible values---no more, no less. The compiler knows this, which enables exhaustive pattern matching checks.\n\n**A subtle point about OCaml:** In OCaml, variants take multiple arguments rather than taking tuples as arguments. This means `A of int * string` is different from `A of (int * string)`. The first takes two separate arguments, while the second takes a single tuple argument. This distinction is usually not important---until you get bitten by it in some corner case! For most purposes, you can ignore it.\n\n#### Recursive Type Definitions\n\nHere is where things get really interesting: type definitions can be recursive! This allows us to define data structures of arbitrary size using a finite definition:\n\n```ocaml env=ch2\ntype int_list = Empty | Cons of int * int_list\n```\n\nLet us see what values inhabit `int_list`. The definition tells us there are two ways to build an `int_list`:\n\n- `Empty` represents the empty list---a list with no elements\n- `Cons (5, Empty)` is a list containing just 5\n- `Cons (5, Cons (7, Cons (13, Empty)))` is a list containing 5, 7, and 13\n\nNotice how `Cons` takes an integer and another `int_list`, allowing us to chain together as many elements as we like. This recursive structure is the essence of how functional languages represent unbounded data.\n\nThe built-in type `bool` really does behave like a two-constructor variant with values `true` and `false`---but note a small OCaml wrinkle: user-defined constructors must start with a capital letter, while a few built-in constructors like `true`, `false`, `[]`, and `(::)` are special-cased.\n\nSimilarly, `int` can be *thought of* as a very large finite variant (“one constructor per integer”), even though the compiler implements it as an efficient machine integer rather than as a gigantic sum type.\n\n#### Parametric Type Definitions\n\nOur `int_list` type only works with integers. But what if we want a list of strings? Or a list of booleans? We would have to define separate types for each, duplicating the same structure.\n\nType definitions can be *parametric* with respect to the types of their components. This allows us to define generic data structures that work with any element type. OCaml already has a built-in parametric list type, so to avoid shadowing it we will define our own simplified list type:\n\n```ocaml env=ch2\ntype 'a my_list = Empty | Cons of 'a * 'a my_list\n```\n\nThe `'a` is a *type parameter*---a placeholder that gets filled in when we use the type. We can have a `string my_list`, an `int my_list`, or even an `(int my_list) my_list` (a list of lists of integers).\n\nSeveral conventions and syntax rules apply to parametric types:\n\n- Type variables must start with `'`. When printing inferred types, OCaml may rename these variables, so it is customary to stick to the standard names `'a`, `'b`, `'c`, `'d`, etc.\n\n- The OCaml syntax places the type parameter before the type name, mimicking English word order. A silly example that reads almost like English:\n  ```ocaml env=ch2\n  type 'white_color dog = Dog of 'white_color\n  ```\n\n  This defines a \"white-color dog\" type---the syntax reads naturally!\n\n- With multiple parameters, OCaml uses parentheses:\n  ```ocaml env=ch2\n  type ('a, 'b) choice = Left of 'a | Right of 'b\n  ```\n\n  Compare this to F# syntax: `type choice\u003c'a,'b\u003e = Left of 'a | Right of 'b`\n\n  And Haskell syntax: `data Choice a b = Left a | Right b`\n\n  Different languages have different conventions, but the underlying concept is the same.\n\n### 2.3 Syntactic Bread and Sugar\n\nOCaml provides various syntactic conveniences---sometimes called *syntactic sugar*---that make code more pleasant to write and read. Let us survey the most important ones.\n\n#### Constructor Naming\n\nNames of variants, called *constructors*, must start with a capital letter. If we wanted to define our own booleans, we would write:\n\n```ocaml env=ch2\ntype my_bool = True | False\n```\n\nOnly constructors and module names can start with capital letters in OCaml. Everything else (values, functions, type names) must start with a lowercase letter. This convention makes it easy to distinguish constructors at a glance.\n\n(As noted above, a few built-in constructors like `true`, `false`, `[]`, and `(::)` are special exceptions to the capitalization rule.)\n\n*Modules* are organizational units (like \"shelves\") containing related values. For example, the `List` module provides operations on lists, including `List.map` and `List.filter`. We will learn more about modules in later chapters.\n\n#### Accessing Record Fields\n\nDid we mention that we can use dot notation to access record fields? The syntax `record.field` extracts a field value. For example, if we have `let person = {name=\"Alice\"; age=30}`, we can write `person.name` to get `\"Alice\"`.\n\n#### Function Definition Shortcuts\n\nSeveral syntactic shortcuts make function definitions more concise. These are worth memorizing, as you will see them constantly in OCaml code:\n\n- `fun x y -\u003e e` stands for `fun x -\u003e fun y -\u003e e`. Note that `fun x -\u003e fun y -\u003e e` parses as `fun x -\u003e (fun y -\u003e e)`. This shorthand aligns with curried form---we can write multi-argument functions without nesting `fun` expressions.\n\n- `function A x -\u003e e1 | B y -\u003e e2` stands for `fun p -\u003e match p with A x -\u003e e1 | B y -\u003e e2`. The general form is: `function PATTERN-MATCHING` stands for `fun v -\u003e match v with PATTERN-MATCHING`. This is handy when you want to immediately pattern-match on a function's argument.\n\n- `let f ARGS = e` is a shorthand for `let f = fun ARGS -\u003e e`. This is probably the most common way to define functions in practice.\n\n### 2.4 Pattern Matching\n\nPattern matching is one of the most powerful features of OCaml and similar languages. It lets us examine the structure of data and extract components in a single, elegant construct.\n\nRecall that we introduced `fst` and `snd` as means to access elements of a pair. But what about larger tuples? There is no built-in `thd` for the third element. The fundamental way to access any tuple---or any algebraic data type---uses the `match` construct. In fact, `fst` and `snd` can easily be defined using pattern matching:\n\n```ocaml env=ch2\nlet fst p = match p with (a, b) -\u003e a\nlet snd p = match p with (a, b) -\u003e b\n```\n\nThe pattern `(a, b)` *destructures* the pair, binding its first component to `a` and its second to `b`. We then return whichever component we want.\n\n#### Matching on Records\n\nPattern matching also works with records, letting us extract multiple fields at once:\n\n```ocaml env=ch2\ntype person = { name : string; surname : string; age : int }\n\nlet greet_person () =\n  match { name = \"Walker\"; surname = \"Johnnie\"; age = 207 } with\n  | { name = _; surname = sn; age = _ } -\u003e \"Hi \" ^ sn ^ \"!\"\n```\n\nHere we match against a record pattern, binding each field to a variable. Note that we bind `name` to `n`, `surname` to `sn`, and `age` to `a`---then use `sn` in the greeting.\n\n#### Understanding Patterns\n\nThe left-hand sides of `-\u003e` in `match` expressions are called **patterns**. Patterns describe the structure of values we want to match against. They can include:\n\n- Constants (like `1`, `\"hello\"`, or `true`)\n- Variables (which bind to the matched value)\n- Constructors (like `None`, `Some x`, or `Cons (h, t)`)\n- Tuples and records\n- Nested combinations of all the above\n\nPatterns can be nested to arbitrary depth, allowing us to match complex structures in one go:\n\n```ocaml env=ch2\nmatch Some (5, 7) with\n| None -\u003e \"sum: nothing\"\n| Some (x, y) -\u003e \"sum: \" ^ string_of_int (x + y)\n```\n\nHere `Some (x, y)` is a nested pattern: we match `Some` of *something*, and that something must be a pair, whose components we bind to `x` and `y`.\n\n#### Simple Patterns and Wildcards\n\nA pattern can simply bind the entire value without destructuring. Writing `match f x with v -\u003e ...` is the same as `let v = f x in ...`. This is occasionally useful when you want the syntax of `match` but do not need to take the value apart.\n\nWhen we do not need a value in a pattern, it is good practice to use the underscore `_`, which is a *wildcard*. The wildcard matches anything but does not bind it to a name. This signals to the reader (and the compiler) that we are intentionally ignoring that part:\n\n```ocaml env=ch2\nlet fst (a, _) = a\nlet snd (_, b) = b\n```\n\nUsing `_` instead of an unused variable name avoids compiler warnings about unused bindings.\n\n#### Pattern Linearity\n\nA variable can only appear once in a pattern. This property is called *linearity*. You might think this is a limitation---what if we want to check that two parts of a structure are equal? We cannot write `(x, x)` to match pairs with equal components.\n\nHowever, we can add conditions to patterns using `when`, so linearity is not really a limitation in practice:\n\n```ocaml env=ch2\nlet describe_point p =\n  match p with\n  | (x, y) when x = y -\u003e \"diag\"\n  | _ -\u003e \"off-diag\"\n```\n\nThe `when` clause acts as a guard: the pattern matches only if both the structure matches *and* the condition is true.\n\nHere is a more elaborate example showing how to implement a comparison function (without shadowing the standard `compare`):\n\n```ocaml env=ch2\nlet compare_int a b =\n  match a, b with\n  | (x, y) when x \u003c y -\u003e -1\n  | (x, y) when x = y -\u003e 0\n  | _ -\u003e 1\n```\n\nNotice how we match against the tuple `(a, b)` in different ways, using guards to distinguish the cases.\n\n#### Partial Record Patterns\n\nWe can skip unused fields of a record in a pattern. Only the fields we care about need to be mentioned. This keeps patterns concise and means we do not have to update every pattern when we add a new field to a record type.\n\n#### Or-Patterns\n\nWe can compress patterns by using `|` inside a single pattern to match multiple alternatives. This is different from having multiple pattern clauses---it lets us share a single right-hand side for several patterns:\n\n```ocaml env=ch2\ntype month =\n  | Jan | Feb | Mar | Apr | May | Jun\n  | Jul | Aug | Sep | Oct | Nov | Dec\n\ntype weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun\n\ntype calendar_date =\n  { year : int; month : month; day : int; weekday : weekday }\n\nlet day =\n  { year = 2012; month = Feb; day = 14; weekday = Wed }\n\nlet day_kind =\n  match day with\n  | { weekday = Sat | Sun; _ } -\u003e \"Weekend!\"\n  | _ -\u003e \"Work day\"\n```\n\nThe pattern `Sat | Sun` matches either `Sat` or `Sun`. This is much cleaner than writing two separate clauses with the same right-hand side.\n\n#### Named Patterns with `as`\n\nSometimes we want to both destructure a value *and* keep a reference to the whole thing (or some intermediate part). We use `(pattern as v)` to name a nested pattern, binding the matched value to `v`:\n\n```\nmatch day with\n  | {weekday = (Mon | Tue | Wed | Thu | Fri as wday); _}\n      when not (day.month = Dec \u0026\u0026 day.day = 24) -\u003e\n    Some (work (get_plan wday))\n  | _ -\u003e None\n```\n\nThis example demonstrates several features working together:\n\n- An or-pattern matches any weekday from Monday to Friday\n- The `as wday` clause binds the matched weekday to the variable `wday`\n- A `when` guard checks that it is not Christmas Eve\n- The bound variable `wday` is then used in the expression `get_plan wday`\n\nThis combination of features makes OCaml's pattern matching remarkably expressive.\n\n### 2.5 Interpreting Algebraic Data Types as Polynomials\n\nNow we come to one of the most delightful aspects of algebraic data types: they really are *algebraic* in a precise mathematical sense. Let us explore a curious analogy between types and polynomials that turns out to be surprisingly deep.\n\nThe translation from types to mathematical expressions works as follows:\n\n- Replace `|` (variant choice) with $+$ (addition)\n- Replace `*` (tuple product) with $\\times$ (multiplication)\n- Treat record types as tuple types (erasing field names and translating `;` as $\\times$)\n\nWe also need translations for some special types:\n\n- The **void type** (a type with no constructors, hence no values):\n  ```ocaml env=ch2\n  type void = |\n  ```\n  Since no values can be constructed, it represents emptiness---translate it as $0$.\n\n- The **unit type** has exactly one value, so translate it as $1$. Since variants without arguments behave like variants `of unit`, translate them as $1$ as well.\n\n- The **bool type** has exactly two values (`true` and `false`), so translate it as $2$.\n\n- Types like `int`, `string`, `float`, and type parameters are treated as variables. We do not care about their exact number of values; we just give them symbolic names like $x$, $y$, etc.\n\n- Defined types translate according to their definitions (substituting variables as necessary).\n\nGive a name to the type being defined (representing a function of the introduced variables). Now interpret the result as an ordinary numeric polynomial! (Or a \"rational function\" if recursively defined.)\n\nThis might seem like a mere curiosity, but it leads to real insights. Let us have some fun with it!\n\n#### Example: Date Type\n\n```ocaml env=ch2\ntype ymd = { year : int; month : int; day : int }\n```\n\nA simple “year-month-day” record is a product of three `int` fields. Translating to a polynomial (using $x$ for `int`):\n\n$$D = x \\times x \\times x = x^3$$\n\nThe cube makes sense: this record is essentially a triple of integers.\n\n#### Example: Option Type\n\nThe built-in option type is defined as:\n\n```\ntype 'a option = None | Some of 'a\n```\n\nTranslating (using $x$ for the type parameter `'a`):\n\n$$O = 1 + x$$\n\nThis reads as: an option is either nothing (1) or something of type $x$. The polynomial $1 + x$ is beautifully simple!\n\n#### Example: List Type\n\n```ocaml skip\ntype 'a my_list = Empty | Cons of 'a * 'a my_list\n```\n\nTranslating (where $L$ represents the list type itself, and $x$ represents the element type):\n\n$$L = 1 + x \\cdot L$$\n\nThis is a recursive equation! A list is either empty ($1$) or an element times another list ($x \\cdot L$). If you solve this equation algebraically, you get $L = \\frac{1}{1-x} = 1 + x + x^2 + x^3 + \\ldots$, which corresponds to: a list is either empty, or has one element, or has two elements, etc.\n\n#### Example: Binary Tree Type\n\n```ocaml env=ch2\ntype btree = Tip | Node of int * btree * btree\n```\n\nTranslating:\n\n$$T = 1 + x \\cdot T \\cdot T = 1 + x \\cdot T^2$$\n\nA binary tree is either a tip ($1$) or a node containing a value and two subtrees ($x \\cdot T^2$).\n\n#### Type Isomorphisms\n\nHere is the remarkable payoff: when translations of two types are equal according to the laws of high-school algebra, the types are *isomorphic*. This means there exist bijective (one-to-one and onto) functions between them---you can convert from one type to the other and back without losing any information.\n\nLet us play with the binary tree polynomial and see where algebra takes us:\n\n$$\n\\begin{aligned}\nT \u0026= 1 + x \\cdot T^2 \\\\\n  \u0026= 1 + x \\cdot T + x^2 \\cdot T^3 \\\\\n  \u0026= 1 + x + x^2 \\cdot T^2 + x^2 \\cdot T^3 \\\\\n  \u0026= 1 + x + x^2 \\cdot T^2 \\cdot (1 + T) \\\\\n  \u0026= 1 + x \\cdot (1 + x \\cdot T^2 \\cdot (1 + T))\n\\end{aligned}\n$$\n\nEach step uses standard algebraic manipulations: substituting $T = 1 + xT^2$, expanding, factoring, and rearranging. The result is a different but algebraically equivalent expression.\n\nNow let us translate this resulting expression back to a type:\n\n```ocaml env=ch2\ntype repr =\n  (int * (int * btree * btree * btree option) option) option\n```\n\nReading the polynomial $1 + x \\cdot (1 + x \\cdot T^2 \\cdot (1 + T))$ from outside in: we have an option (the outermost $1 + \\ldots$), whose `Some` case contains an `int` times another option, and so on.\n\nThe challenge is to find isomorphism functions with signatures:\n\n```\nval iso1 : btree -\u003e repr\nval iso2 : repr -\u003e btree\n```\n\nThese functions should satisfy: for all trees `t`, `iso2 (iso1 t) = t`, and for all representations `r`, `iso1 (iso2 r) = r`. Can you write them?\n\n#### My First (Failed) Attempt\n\nHere is my first attempt, trying to guess the pattern directly:\n\n```\n# let iso1 (t : btree) : repr =\n  match t with\n    | Tip -\u003e None\n    | Node (x, Tip, Tip) -\u003e Some (x, None)\n    | Node (x, Node (y, t1, t2), Tip) -\u003e\n      Some (x, Some (y, t1, t2, None))\n    | Node (x, Node (y, t1, t2), t3) -\u003e\n      Some (x, Some (y, t1, t2, Some t3));;\n\nWarning 8: this pattern-matching is not exhaustive.\nHere is an example of a value that is not matched:\nNode (_, Tip, Node (_, _, _))\n```\n\nI forgot about one case! The case `Node (_, Tip, Node (_, _, _))`---a node with an empty left subtree and non-empty right subtree---was not covered. It seems difficult to guess the solution directly when trying to map the complex final form all at once.\n\nHave you found it on your first try? If so, congratulations! Most people do not. This illustrates an important principle: complex transformations are easier to get right when broken into smaller steps.\n\n#### Breaking Down the Problem\n\nLet us divide the task into smaller steps corresponding to intermediate points in the polynomial transformation. Instead of jumping from $T = 1 + xT^2$ directly to the final form, we will introduce intermediate types for each algebraic step:\n\n```ocaml env=ch2\ntype ('a, 'b) choice = Left of 'a | Right of 'b\n\ntype interm1 =\n  ((int * btree, int * int * btree * btree * btree) choice)\n  option\n\ntype interm2 =\n  ((int, int * int * btree * btree * btree option) choice)\n  option\n```\n\nNow we can define each step:\n\n```ocaml env=ch2\nlet step1r (t : btree) : interm1 =\n  match t with\n    | Tip -\u003e None\n    | Node (x, t1, Tip) -\u003e Some (Left (x, t1))\n    | Node (x, t1, Node (y, t2, t3)) -\u003e\n      Some (Right (x, y, t1, t2, t3))\n\nlet step2r (r : interm1) : interm2 =\n  match r with\n    | None -\u003e None\n    | Some (Left (x, Tip)) -\u003e Some (Left x)\n    | Some (Left (x, Node (y, t1, t2))) -\u003e\n      Some (Right (x, y, t1, t2, None))\n    | Some (Right (x, y, t1, t2, t3)) -\u003e\n      Some (Right (x, y, t1, t2, Some t3))\n\nlet step3r (r : interm2) : repr =\n  match r with\n    | None -\u003e None\n    | Some (Left x) -\u003e Some (x, None)\n    | Some (Right (x, y, t1, t2, t3opt)) -\u003e\n      Some (x, Some (y, t1, t2, t3opt))\n\nlet iso1 (t : btree) : repr =\n  step3r (step2r (step1r t))\n```\n\nEach step function handles one small transformation, and the compiler verifies that our pattern matching is exhaustive. No more missed cases!\n\n**Exercise:** Define `step1l`, `step2l`, `step3l`, and `iso2`.\n\n*Hint:* Now it is straightforward---each step is simply the inverse of its corresponding forward step. The left-going functions undo what the right-going functions do.\n\n#### Take-Home Lessons\n\nThis exploration of type isomorphisms teaches us two valuable principles:\n\n1. **Design for validity:** Try to define data structures so that only meaningful information can be represented---as long as it does not overcomplicate the data structures. Avoid catch-all clauses when defining functions. The compiler will then tell you if you have forgotten about a case. The exhaustiveness checker is your friend.\n\n2. **Divide and conquer:** Break solutions into small steps so that each step can be easily understood and verified. When I tried to write `iso1` directly, I made a mistake. When I broke it into three simple steps, each step was obviously correct, and composing them gave the right answer.\n\n### 2.6 Differentiating Algebraic Data Types\n\nOf course, you might object that the pompous title is wrong---we will differentiate the translated polynomials, not the types themselves. Fair enough! But what sense does differentiating a type's polynomial make?\n\nIt turns out that taking the partial derivative of a polynomial (translated from a data type), when translated back, gives a type representing a \"one-hole context\"---a data structure with one piece missing. This missing piece corresponds to the variable with respect to which we differentiated. The derivative tells us: \"Here are all the ways to point at one element of this type.\"\n\n#### Example: Differentiating a Simple Record\n\nLet us start with a simple record type:\n\n```ocaml env=ch2\ntype ymd = { year : int; month : int; day : int }\n```\n\nThe translation and its derivative:\n\n$$\n\\begin{aligned}\nD \u0026= x \\cdot x \\cdot x = x^3 \\\\\n\\frac{\\partial D}{\\partial x} \u0026= 3x^2 = x \\cdot x + x \\cdot x + x \\cdot x\n\\end{aligned}\n$$\n\nWe could have left it as $3 \\cdot x \\cdot x$, but expanding it as a sum shows the structure more clearly. The derivative $3x^2$ says: there are three ways to \"point at\" an `int` in a `ymd`, and each way leaves two other `int`s behind.\n\nTranslating the expanded form back to a type:\n\n```ocaml env=ch2\ntype ymd_ctx =\n  Year of int * int | Month of int * int | Day of int * int\n```\n\nEach variant represents a \"hole\" at a different position:\n\n- `Year (m, d)` means the year field is the hole (and we have the month `m` and day `d`)\n- `Month (y, d)` means the month field is the hole (and we have year `y` and day `d`)\n- `Day (y, m)` means the day field is the hole\n\nNow we can define functions to introduce and eliminate this derivative type:\n\n```ocaml env=ch2\nlet ymd_deriv ({ year = y; month = m; day = d } : ymd) =\n  [ Year (m, d); Month (y, d); Day (y, m) ]\n\nlet ymd_integr n = function\n  | Year (m, d) -\u003e { year = n; month = m; day = d }\n  | Month (y, d) -\u003e { year = y; month = n; day = d }\n  | Day (y, m) -\u003e { year = y; month = m; day = n }\n\nlet example =\n  List.map (ymd_integr 7) (ymd_deriv { year = 2012; month = 2; day = 14 })\n```\n\nThe `ymd_deriv` function produces all contexts (one for each field)---it \"differentiates\" a record into a list of one-hole contexts. The `ymd_integr` function fills in a hole with a new value---it \"integrates\" by putting a value back into the context. Notice how the naming follows the calculus analogy!\n\nThe example above takes the date February 14, 2012, produces three contexts (one for each field), and then fills each hole with the number 7, producing three modified dates.\n\n#### Example: Differentiating Binary Trees\n\nNow let us tackle the more challenging case of binary trees (using the same `btree` type as above):\n\n```\ntype btree = Tip | Node of int * btree * btree\n```\n\nThe translation and differentiation:\n\n$$\n\\begin{aligned}\nT \u0026= 1 + x \\cdot T^2 \\\\\n\\frac{\\partial T}{\\partial x} \u0026= 0 + T^2 + 2 \\cdot x \\cdot T \\cdot \\frac{\\partial T}{\\partial x} = T \\cdot T + 2 \\cdot x \\cdot T \\cdot \\frac{\\partial T}{\\partial x}\n\\end{aligned}\n$$\n\nSomething interesting happened: the derivative is recursive! It refers to itself via $\\frac{\\partial T}{\\partial x}$. This makes perfect sense when you think about it:\n\n- $T \\cdot T$ represents pointing at the root: the hole is at the current node, and we have the two subtrees.\n- $2 \\cdot x \\cdot T \\cdot \\frac{\\partial T}{\\partial x}$ represents pointing deeper in the tree: we choose left or right (the factor of 2), remember the current node's value ($x$), keep the other subtree ($T$), and then have a context in the chosen subtree ($\\frac{\\partial T}{\\partial x}$).\n\nInstead of translating $2$ as `bool`, we introduce a more descriptive type to make the code clearer:\n\n```ocaml env=ch2\ntype btree_dir = LeftBranch | RightBranch\n\ntype btree_deriv =\n  | Here of btree * btree\n  | Below of btree_dir * int * btree * btree_deriv\n```\n\nThe `Here` constructor means the hole is at the current position, and we have the left and right subtrees. The `Below` constructor means we go down one level, remembering which direction we went, the value at the node we passed, and the subtree we did not enter.\n\n(You might someday hear about *zippers*---they are \"inverted\" relative to our type. In a zipper, the hole comes first, and the context trails behind. Both representations are useful in different situations.)\n\n**Exercise:** Write a function that takes a number and a `btree_deriv`, and builds a `btree` by putting the number into the \"hole\" in `btree_deriv`.\n\n\u003cdetails\u003e\n\u003csummary\u003eSolution\u003c/summary\u003e\n\nThe integration function fills the hole with a value. It must be recursive because the derivative type is recursive---we may need to descend through multiple `Below` constructors before reaching the `Here` where the hole actually is:\n\n```ocaml env=ch2\nlet rec btree_integr n = function\n  | Here (ltree, rtree) -\u003e Node (n, ltree, rtree)\n  | Below (LeftBranch, m, rtree, deriv) -\u003e\n    Node (m, btree_integr n deriv, rtree)\n  | Below (RightBranch, m, ltree, deriv) -\u003e\n    Node (m, ltree, btree_integr n deriv)\n```\n\nWhen we reach `Here`, we create a node with the new value `n` and the two subtrees. When we see `Below`, we reconstruct the node we passed through and recursively integrate into the appropriate subtree.\n\n\u003c/details\u003e\n\n### 2.7 Exercises\n\n#### Exercise 1: Designing Valid Data Structures\n\n*Due to Yaron Minsky.*\n\nThis exercise practices the principle of \"making invalid states unrepresentable.\" Consider a datatype to store internet connection information. The time `when_initiated` marks the start of connecting and is not needed after the connection is established (it is only used to decide whether to give up trying to connect). The ping information is available for established connections but not straight away.\n\n```\ntype connectionstate = Connecting | Connected | Disconnected\n\ntype connectioninfo = {\n  state : connectionstate;\n  server : Inetaddr.t;\n  lastpingtime : Time.t option;\n  lastpingid : int option;\n  sessionid : string option;\n  wheninitiated : Time.t option;\n  whendisconnected : Time.t option;\n}\n```\n\n(The types `Time.t` and `Inetaddr.t` come from the *Core* library. You can replace them with `float` and `Unix.inet_addr`. Load the Unix library in the interactive toplevel with `#load \"unix.cma\";;`.)\n\nThe problem with this design is that it allows many nonsensical combinations: a `Connecting` state with ping information, a `Disconnected` state with a session ID, etc. The optional fields (all those `option` types) make it unclear which fields are valid in which states.\n\nRewrite the type definitions so that the datatype will contain only reasonable combinations of information. Use separate record types for each connection state, with only the fields that make sense for that state.\n\n#### Exercise 2: Labeled and Optional Arguments\n\nIn OCaml, functions can have labeled arguments and optional arguments (parameters with default values that can be omitted). This exercise explores these features.\n\nLabels can differ from the names of argument values:\n\n```ocaml env=ch2\nlet f ~meaningfulname:n = n + 1\nlet _ = f ~meaningfulname:5  (* We do not need the result so we ignore it. *)\n```\n\nWhen the label and value names are the same, the syntax is shorter:\n\n```ocaml env=ch2\nlet g ~pos ~len =\n  StringLabels.sub \"0123456789abcdefghijklmnopqrstuvwxyz\" ~pos ~len\n\nlet () =  (* A nicer way to mark computations that return unit. *)\n  let pos = Random.int 26 in\n  let len = Random.int 10 in\n  print_string (g ~pos ~len)\n```\n\nWhen some function arguments are optional, the function must take non-optional arguments after the last optional argument. Optional parameters with default values:\n\n```ocaml env=ch2\nlet h ?(len=1) pos = g ~pos ~len\nlet () = print_string (h 10)\n```\n\nOptional arguments are implemented as parameters of an option type. This allows checking whether the argument was provided:\n\n```ocaml env=ch2\nlet foo ?bar n =\n  match bar with\n    | None -\u003e \"Argument = \" ^ string_of_int n\n    | Some m -\u003e \"Sum = \" ^ string_of_int (m + n)\n```\n\nWe can use it in various ways:\n\n```ocaml env=ch2\nlet _ = foo 5\nlet _ = foo ~bar:5 7\n```\n\nWe can also provide the option value directly:\n\n```ocaml env=ch2\nlet test_foo () =\n  let bar = if Random.int 10 \u003c 5 then None else Some 7 in\n  foo ?bar 7\n```\n\n1. Observe the types that functions with labeled and optional arguments have. Come up with coding style guidelines for when to use labeled arguments. When might they improve readability? When might they be overkill?\n\n2. Write a rectangle-drawing procedure that takes three optional arguments: left-upper corner, right-lower corner, and a width-height pair. It should draw a correct rectangle whenever two of the three arguments are given (since any two determine the third), and raise an exception otherwise. Use the *Bogue* library.\n\n3. Write a function that takes an optional argument of arbitrary type and a function argument, and passes the optional argument to the function without inspecting it. This tests your understanding of how optional arguments work at the type level.\n\n#### Exercise 3: Type Inference Practice\n\n*From a past exam.*\n\nThese exercises help you internalize how type inference works. Try to work them out by hand before checking with the OCaml toplevel.\n\n1. Give the (most general) types of the following expressions, either by guessing or by inferring by hand:\n   1. `let double f y = f (f y) in fun g x -\u003e double (g x)`\n   2. `let rec tails l = match l with [] -\u003e [] | x::xs -\u003e xs::tails xs in fun l -\u003e List.combine l (tails l)`\n\n2. Give example expressions that have the following types (without using type constraints). There are many possible answers for each:\n   1. `(int -\u003e int) -\u003e bool`\n   2. `'a option -\u003e 'a list`\n\n#### Exercise 4: Types as Exponents\n\nWe have seen that algebraic data types can be related to analytic functions (the subset definable from polynomials via recursion)---by literally interpreting sum types (variant types) as sums and product types (tuple and record types) as products. We can extend this interpretation to function types by interpreting $a \\rightarrow b$ as $b^a$ (i.e., $b$ to the power of $a$). Note that the $b^a$ notation is actually used to denote functions in set theory.\n\nThis interpretation makes sense: a function from a set with $a$ elements to a set with $b$ elements is choosing, for each of the $a$ inputs, one of $b$ outputs---giving $b^a$ possible functions.\n\n1. Translate $a^{b + cd}$ and $a^b \\cdot (a^c)^d$ into OCaml types, using any distinct types for $a, b, c, d$, and using `type ('a,'b) choice = Left of 'a | Right of 'b` for $+$. Write the bijection functions in both directions. Verify algebraically that $a^{b + cd} = a^b \\cdot (a^c)^d$ using the laws of exponents.\n\n2. Come up with a type `'t exp` that shares with the exponential function the following property: $\\frac{\\partial \\exp(t)}{\\partial t} = \\exp(t)$, where we translate a derivative of a type as a context (i.e., the type with a \"hole\"), as in this chapter. In other words, the derivative of the type should be isomorphic to the type itself! Explain why your answer is correct. *Hint:* in computer science, our logarithms are mostly base 2.\n\n*Further reading:* [Algebraic Type Systems - Combinatorial Species](http://bababadalgharaghtakamminarronnkonnbro.blogspot.com/2012/10/algebraic-type-systems-combinatorial.html)\n\n#### Exercise 5 (Homework): Finding Contexts\n\nWrite a function `btree_deriv_at` that takes a predicate over integers (i.e., a function `f: int -\u003e bool`) and a `btree`, and builds a `btree_deriv` whose \"hole\" is in the first position for which the predicate returns true. It should return a `btree_deriv option`, with `None` if the predicate does not hold for any node.\n\nThis function lets you \"search\" a tree and get back a context pointing to the found element. Think about what order you want to search in (pre-order, in-order, or post-order) and what \"first\" means in that context.\n\n\n## Chapter 3: Computation\n\n*Reduction semantics and operational reasoning*\n\n**In this chapter, you will:**\n\n- Use function composition to build reusable “pipelines”\n- Learn reduction semantics to reason about evaluation step by step\n- Recognize and write tail-recursive programs (and understand what TCO buys you)\n- Get a first working intuition for continuation-passing style (CPS)\n\n**References:**\n\n- \"Using, Understanding and Unraveling the OCaml Language\" by Didier Remy, Chapter 1\n- \"The OCaml system\" manual, the tutorial part, Chapter 1\n\nIn this chapter, we explore how functional programs actually execute. We will learn how to reason about computation step by step using *reduction semantics*, and discover important optimization techniques like *tail call optimization* that make functional programming practical. Along the way, we will encounter our first taste of *continuation passing style*, a powerful programming technique that will reappear throughout this book.\n\n### 3.1 Function Composition\n\nFunction composition is one of the most fundamental operations in functional programming. It allows us to build complex transformations by combining simpler functions. The usual way function composition is defined in mathematics is \"backward\"---the notation follows the convention of mathematical function application:\n\n$$\n(f \\circ g)(x) = f(g(x))\n$$\n\nThis means that when we write $f \\circ g$, we first apply $g$ and then apply $f$ to the result. The function written on the left is applied last---hence the term \"backward\" composition. Here is how this is expressed in different functional programming languages:\n\n| Language | Definition |\n|----------|-----------|\n| Math | $(f \\circ g)(x) = f(g(x))$ |\n| OCaml | `let (-|) f g x = f (g x)` |\n| F# | `let (\u003c\u003c) f g x = f (g x)` |\n| Haskell | `(.) f g = \\x -\u003e f (g x)` |\n\nThis backward composition looks like function application but needs fewer parentheses. Do you recall the functions `iso1` and `iso2` from the previous chapter on type isomorphisms? Using backward composition, we could write:\n\n```ocaml skip\nlet iso2 = step1l -| step2l -| step3l\n```\n\nWhile backward composition matches traditional mathematical notation, many programmers find a \"forward\" composition more intuitive. Forward composition follows the order in which computation actually proceeds---data flows from left to right, matching how we typically read code in most programming languages:\n\n| Language | Definition |\n|----------|-----------|\n| OCaml | `let (\\|-) f g x = g (f x)` |\n| F# | `let (\u003e\u003e) f g x = g (f x)` |\n\nWith forward composition, you can read a pipeline of transformations in the natural order:\n\n```ocaml skip\nlet iso1 = step1r |- step2r |- step3r\n```\n\nHere, the data first passes through `step1r`, then the result goes to `step2r`, and finally to `step3r`. This \"pipeline\" style of programming is particularly popular in languages like F# and has influenced the design of many modern programming languages.\n\nIn the table above, the operator is written as `\\|-` because Markdown tables use `|` to separate columns. In actual OCaml code, the operator name is `(|-)`.\n\n```ocaml env=ch3\nlet (|-) f g x = g (f x)\n```\n\nTwo related (but distinct) tools are also worth knowing:\n\n- The standard library provides backward composition as `Fun.compose`, where `Fun.compose f g x = f (g x)`.\n- OCaml also provides the forward *application* operator `(|\u003e)` (a pipeline): `x |\u003e f |\u003e g` means `g (f x)`. Unlike `(|-)`, this is not composition of functions but immediate application to a value.\n\n#### Partial Application\n\nBoth composition examples above rely on **partial application**, a technique we introduced in the previous chapter. Recall that `((+) 1)` is a function that adds 1 to its argument---we have provided only one of the two arguments that `(+)` requires. Partial application occurs whenever we supply fewer arguments than a function expects; the result is a new function that waits for the remaining arguments.\n\nConsider the composition `step1r |- step2r |- step3r`. How exactly does partial application come into play here? The composition operator `(|-)` is defined as `let (|-) f g x = g (f x)`, which means it takes *three* arguments: two functions `f` and `g`, and a value `x`. When we write `step1r |- step2r`, we are partially applying `(|-)` with just two arguments. The result is a function that still needs the final argument `x`.\n\n*Exercise:* Think about the types involved. If `step1r` has type `'a -\u003e 'b` and `step2r` has type `'b -\u003e 'c`, what is the type of `step1r |- step2r`?\n\n*Check:* `step1r |- step2r` has type `'a -\u003e 'c`. (Composition “cancels” the middle type `'b`.)\n\n#### Power Function\n\nNow we define iterated function composition---applying a function to itself repeatedly. This is written mathematically as:\n\n$$\nf^n(x) := \\underbrace{(f \\circ \\cdots \\circ f)}_{n \\text{ times}}(x)\n$$\n\nIn other words, $f^0$ is the identity function, $f^1 = f$, $f^2 = f \\circ f$, and so on. In OCaml, we first define the backward composition operator, then use it to implement `power`:\n\n```ocaml env=ch3\nlet (-|) f g x = f (g x)\n\nlet rec power f n =\n  if n \u003c= 0 then (fun x -\u003e x) else f -| power f (n-1)\n```\n\nWhen `n \u003c= 0`, we return the identity function `fun x -\u003e x`. Otherwise, we compose `f` with `power f (n-1)`, which gives us one more application of `f`. Notice how elegantly this definition expresses the mathematical concept---we are literally composing `f` with itself `n` times.\n\nThis `power` function is surprisingly versatile. For example, we can use it to define addition in terms of the successor function:\n\n```ocaml env=ch3\nlet add n = power ((+) 1) n\n```\n\nHere `add 5 7` would compute $7 + 1 + 1 + 1 + 1 + 1 = 12$. We could even define multiplication:\n\n```ocaml env=ch3\nlet mult k n = power ((+) k) n 0\n```\n\nThis computes $0 + k + k + \\ldots + k$ (adding $k$ a total of $n$ times), giving us $k \\times n$. While not the most efficient implementation, these examples show how higher-order functions like `power` can express fundamental mathematical operations.\n\n#### Numerical Derivative\n\nA beautiful application of `power` is computing higher-order derivatives. First, let us define a numerical approximation of the derivative using the standard finite difference formula:\n\n```ocaml env=ch3\nlet derivative dx f = fun x -\u003e (f (x +. dx) -. f x) /. dx\n```\n\nThis definition computes $\\frac{f(x + dx) - f(x)}{dx}$, which approximates $f'(x)$ when `dx` is small. Notice the explicit `fun x -\u003e ...` syntax, which emphasizes that `derivative dx f` is itself a function---we are transforming a function `f` into its derivative function.\n\nWe can write the same definition more concisely using OCaml's curried function syntax:\n\n```ocaml env=ch3\nlet derivative dx f x = (f (x +. dx) -. f x) /. dx\n```\n\nBoth definitions are equivalent, but the first makes the \"function returning a function\" structure more explicit, while the second is more compact.\n\n**A note on OCaml's numeric operators:** OCaml uses different operators for floating-point arithmetic than for integers. The type of `(+)` is `int -\u003e int -\u003e int`, so we cannot use `+` with `float` values. Instead, operators followed by a dot work on `float` numbers: `+.`, `-.`, `*.`, and `/.`. This might seem inconvenient at first, but it catches type errors at compile time and avoids the implicit conversions that cause subtle bugs in other languages.\n\n#### Computing Higher-Order Derivatives\n\nNow comes the payoff. With `power` and `derivative`, we can elegantly compute higher-order derivatives:\n\n```ocaml env=ch3\nlet pi = 4.0 *. atan 1.0\nlet sin''' = (power (derivative 1e-5) 3) sin\nlet _approx = sin''' pi\n```\n\nHere `sin'''` is the third derivative of sine. The expression `(power (derivative 1e-5) 3)` creates a function that applies the derivative operation three times---exactly what we need for the third derivative.\n\nMathematically, the third derivative of $\\sin(x)$ is $-\\cos(x)$, so `sin''' pi` should give us $-\\cos(\\pi) = 1$. The actual result will be close to 1, with some numerical error due to the finite difference approximation (the error compounds with each derivative we take).\n\nThis example demonstrates the power of treating functions as first-class values. We have built a general-purpose derivative operator and combined it with our `power` function to create an $n$th-derivative calculator---all in just a few lines of code.\n\n### 3.2 Evaluation Rules (Reduction Semantics)\n\nSo far, we have written OCaml programs and observed their results, but we have not precisely described *how* those results are computed. To understand how OCaml programs execute, we need to formalize the evaluation process. This section presents **reduction semantics** (also called *operational semantics*), which describes computation as a series of rewriting steps that transform expressions until we reach a final value.\n\nUnderstanding reduction semantics is valuable for several reasons. It helps us predict what our programs will do, reason about their efficiency, and understand subtle behaviors like infinite loops and non-termination. The ideas here also form the foundation for understanding more advanced topics like type systems and program verification.\n\n#### Expressions\n\nPrograms consist of **expressions**. Here is the grammar of expressions for a simplified version of OCaml (we omit some features for clarity):\n\n| | | |\n|:--|:--|:--|\n| $a \\; ::=$ | $x$ | variables |\n| $\\quad \\mid$ | `fun` $x$ `-\u003e` $a$ | (defined) functions |\n| $\\quad \\mid$ | $a \\; a$ | applications |\n| $\\quad \\mid$ | $C^0$ | value constructors of arity 0 |\n| $\\quad \\mid$ | $C^n(a, \\ldots, a)$ | value constructors of arity $n$ |\n| $\\quad \\mid$ | $f^n$ | built-in values (primitives) of arity $n$ |\n| $\\quad \\mid$ | `let` $x$ `=` $a$ `in` $a$ | name bindings (local definitions) |\n| $\\quad \\mid$ | `match` $a$ `with` $p$ `-\u003e` $a$ $\\mid \\cdots \\mid$ $p$ `-\u003e` $a$ | pattern matching |\n| $p \\; ::=$ | $x$ | pattern variables |\n| $\\quad \\mid$ | $(p, \\ldots, p)$ | tuple patterns |\n| $\\quad \\mid$ | $C^0$ | variant patterns of arity 0 |\n| $\\quad \\mid$ | $C^n(p, \\ldots, p)$ | variant patterns of arity $n$ |\n\n**Arity** means how many arguments something requires. For constructors, arity tells us how many components the constructor holds; for functions (primitives), it tells us how many arguments they need before they can compute a result. For tuple patterns, arity is simply the length of the tuple.\n\n**Meta-syntax note.** In the grammar and rules below, we write constructors as if they were truly $n$-ary, e.g. $C^3(a_1,a_2,a_3)$. In actual OCaml syntax, constructors take exactly one argument; “multiple arguments” are represented by a tuple, e.g. `Node (v1, v2, v3)`. The $n$-ary presentation is a convenient mathematical shorthand.\n\n**Evaluation-order note.** The small-step rules below are intentionally simplified. In particular, the “context” rules allow reducing subexpressions in more than one place. Real OCaml is *strict* (call-by-value) and evaluates subexpressions in a deterministic order (in current OCaml implementations this is often right-to-left); the details matter when you have effects (exceptions, printing, mutation), but are usually irrelevant for purely functional code.\n\n#### The `fix` Primitive\n\nOur grammar above includes functions defined with `fun`, but what about recursive functions defined with `let rec`? To keep our semantics simple, we introduce a primitive `fix` that captures the essence of recursion:\n\n$$\n\\texttt{let rec } f \\; x = e_1 \\texttt{ in } e_2 \\equiv \\texttt{let } f = \\texttt{fix (fun } f \\; x \\texttt{ -\u003e } e_1 \\texttt{) in } e_2\n$$\n\nThe `fix` primitive is a *fixpoint combinator*. It takes a function that expects to receive \"itself\" as its first argument and produces a function that, when called, behaves as if it has access to itself for recursive calls. This might seem mysterious now, but we will see exactly how it works when we examine its reduction rule below.\n\n#### Values\n\nExpressions evaluate (i.e., compute) to **values**. Values are expressions that cannot be reduced further---they are the \"final answers\" of computation:\n\n$$\n\\begin{array}{lcll}\nv \u0026 := \u0026 \\texttt{fun } x \\texttt{ -\u003e } a \u0026 \\text{(defined) functions} \\\\\n  \u0026 |  \u0026 C^n(v_1, \\ldots, v_n) \u0026 \\text{constructed values} \\\\\n  \u0026 |  \u0026 f^n \\; v_1 \\; \\cdots \\; v_k \u0026 k \u003c n \\text{ (partially applied primitives)}\n\\end{array}\n$$\n\nNote that functions are values: `fun x -\u003e x + 1` is already fully evaluated---there is nothing more to compute until the function is applied to an argument. Similarly, constructed values like `Some 42` or `(1, 2, 3)` are values when all their components are values.\n\nPartially applied primitives like `(+) 3` are also values. The expression `(+) 3` has received one argument but needs another before it can compute a sum. Until that second argument arrives, there is nothing more to do, so `(+) 3` is a value.\n\n#### Substitution\n\nThe heart of evaluation is **substitution**. To substitute a value $v$ for a variable $x$ in expression $a$, we write $a[x := v]$. This notation means that every occurrence of $x$ in $a$ is replaced by $v$.\n\nFor example, if $a$ is the expression `x + x * y` and we substitute 3 for `x`, we get `3 + 3 * y`. In our notation: `(x + x * y)[x := 3] = 3 + 3 * y`.\n\nIn the presence of binders like `fun x -\u003e ...` (and pattern-bound variables), substitution must be **capture-avoiding**: we are allowed to rename bound variables so we do not accidentally change which occurrence refers to which binder.\n\n**Implementation note:** Although we describe substitution as \"replacing\" variables with values, the actual implementation in OCaml does not duplicate the value $v$ in memory each time it appears. Instead, OCaml uses closures and sharing to ensure that values are stored once and referenced wherever needed. This is both more efficient and essential for handling recursive data structures.\n\n#### Reduction Rules (Redexes)\n\nNow we can describe how computation actually proceeds. Reduction works by finding reducible expressions called **redexes** (short for \"reducible expressions\") and applying reduction rules that rewrite them into simpler forms. We write $e_1 \\rightsquigarrow e_2$ to mean \"expression $e_1$ reduces to expression $e_2$ in one step.\"\n\nHere are the fundamental reduction rules:\n\n**Function application (beta reduction):**\n$$\n(\\texttt{fun } x \\texttt{ -\u003e } a) \\; v \\rightsquigarrow a[x := v]\n$$\n\nThis is the most important rule. When we apply a function `fun x -\u003e a` to a value $v$, we substitute $v$ for the parameter $x$ throughout the function body $a$. This rule is traditionally called \"beta reduction\" in the lambda calculus literature.\n\nFor example: `(fun x -\u003e x + 1) 5` $\\rightsquigarrow$ `5 + 1` $\\rightsquigarrow$ `6`.\n\n**Let binding:**\n$$\n\\texttt{let } x = v \\texttt{ in } a \\rightsquigarrow a[x := v]\n$$\n\nA let binding works similarly: once the bound expression has been evaluated to a value $v$, we substitute it into the body. Notice that `let x = e in a` is essentially equivalent to `(fun x -\u003e a) e`---both bind $x$ to the result of evaluating $e$ within the expression $a$.\n\n**Primitive application:**\n$$\nf^n \\; v_1 \\; \\cdots \\; v_n \\rightsquigarrow f(v_1, \\ldots, v_n)\n$$\n\nWhen a primitive (like `+` or `*`) receives all the arguments it needs (determined by its arity $n$), it computes the result. Here $f(v_1, \\ldots, v_n)$ denotes the actual result of the primitive operation---for example, `(+) 2 3` $\\rightsquigarrow$ `5`.\n\n**Pattern matching with a variable pattern:**\n$$\n\\texttt{match } v \\texttt{ with } x \\texttt{ -\u003e } a \\texttt{ | } \\cdots \\rightsquigarrow a[x := v]\n$$\n\nA variable pattern always matches, binding the entire value to the variable.\n\n**Pattern matching with a non-matching constructor:**\n$$\n\\frac{C_1 \\neq C_2}{\\begin{array}{c}\\texttt{match } C_1^n(v_1, \\ldots, v_n) \\texttt{ with } C_2^k(p_1, \\ldots, p_k) \\texttt{ -\u003e } a \\texttt{ | } pm \\\\ \\rightsquigarrow \\texttt{match } C_1^n(v_1, \\ldots, v_n) \\texttt{ with } pm\\end{array}}\n$$\n\nIf the constructor in the value ($C_1$) does not match the constructor in the pattern ($C_2$), we skip this branch and try the remaining patterns ($pm$). This is how OCaml searches through pattern match cases from top to bottom.\n\n**Pattern matching with a matching constructor:**\n$$\n\\texttt{match } C_1^n(v_1, \\ldots, v_n) \\texttt{ with } C_1^n(x_1, \\ldots, x_n) \\texttt{ -\u003e } a \\texttt{ | } \\cdots \\rightsquigarrow a[x_1 := v_1; \\ldots; x_n := v_n]\n$$\n\nIf the constructor matches, we substitute all the values from inside the constructor for the corresponding pattern variables. For example, `match Some 42 with Some x -\u003e x + 1 | None -\u003e 0` reduces to `42 + 1` because `Some` matches `Some` and we substitute 42 for `x`.\n\nIf $n = 0$, then $C_1^n(v_1, \\ldots, v_n)$ stands for simply $C_1^0$, a constructor with no arguments (like `None` or `[]`). We omit the more complex cases of nested pattern matching for brevity.\n\n#### Rule Variables\n\nIn these rules, we use *metavariables*---placeholders that can be replaced with actual expressions. Understanding them is key to applying the rules:\n\n- $x$ matches any variable name (like `foo`, `n`, or `result`)\n- $a, a_1, \\ldots, a_n$ match any expression (not necessarily a value)\n- $v, v_1, \\ldots, v_n$ match any *value* (expressions that are fully evaluated)\n\nTo apply a rule, find substitutions for these metavariables that make the left-hand side of the rule match your expression. Then the right-hand side (with the same substitutions applied) gives you the reduced expression.\n\nFor example, to apply the beta reduction rule to `(fun n -\u003e n * 2) 5`:\n1. Match `fun x -\u003e a` with `fun n -\u003e n * 2`, giving us $x = \\texttt{n}$ and $a = \\texttt{n * 2}$\n2. Match $v$ with `5`\n3. The right-hand side $a[x := v]$ becomes `(n * 2)[n := 5]` which equals `5 * 2`\n\n#### Evaluation Context Rules\n\nThe reduction rules above only apply when the arguments are already values. But what if we have `(fun x -\u003e x + 1) (2 + 3)`? The argument `2 + 3` is not a value, so we cannot directly apply beta reduction. We need rules that tell us evaluation can proceed inside subexpressions.\n\nIf $a_i \\rightsquigarrow a_i'$ (meaning $a_i$ can take a reduction step), then:\n\n$$\n\\begin{array}{lcl}\na_1 \\; a_2 \u0026 \\rightsquigarrow \u0026 a_1' \\; a_2 \\\\\na_1 \\; a_2 \u0026 \\rightsquigarrow \u0026 a_1 \\; a_2' \\\\\nC^n(a_1, \\ldots, a_i, \\ldots, a_n) \u0026 \\rightsquigarrow \u0026 C^n(a_1, \\ldots, a_i', \\ldots, a_n) \\\\\n\\texttt{let } x = a_1 \\texttt{ in } a_2 \u0026 \\rightsquigarrow \u0026 \\texttt{let } x = a_1' \\texttt{ in } a_2 \\\\\n\\texttt{match } a_1 \\texttt{ with } pm \u0026 \\rightsquigarrow \u0026 \\texttt{match } a_1' \\texttt{ with } pm\n\\end{array}\n$$\n\nThese rules describe *where* reduction can happen:\n\n- In a function application $a_1 \\; a_2$, the rules allow reducing either the function ($a_1$) or the argument ($a_2$). This is a common simplification in textbook semantics; OCaml itself uses a fixed evaluation order.\n- In a constructor application, any argument can be evaluated.\n- In a let binding `let x = a1 in a2`, the bound expression $a_1$ must be evaluated to a value before we can proceed. Notice there is no rule for evaluating $a_2$ directly---the body is only evaluated after the substitution happens.\n- In a match expression, the scrutinee (the expression being matched) must be evaluated before pattern matching can proceed.\n\n#### The `fix` Rule\n\nFinally, the rule for the `fix` primitive, which enables recursion:\n\n$$\n\\texttt{fix}^2 \\; v_1 \\; v_2 \\rightsquigarrow v_1 \\; (\\texttt{fix}^2 \\; v_1) \\; v_2\n$$\n\nThis rule is subtle but powerful. Let us unpack it:\n\n1. `fix` is a binary primitive (arity 2), meaning it needs two arguments before it computes.\n2. When we apply `fix` to two values $v_1$ and $v_2$, it \"unrolls\" one level of recursion by calling $v_1$ with two arguments: `(fix v1)` (which represents \"the recursive function itself\") and $v_2$ (the actual argument to the recursive call).\n3. Because `fix` has arity 2, the expression `(fix v1)` is a *partially applied primitive*---and partially applied primitives are values! This is crucial: it means `(fix v1)` will not be evaluated further until it is applied to another argument inside $v_1$.\n\nThis delayed evaluation is what prevents infinite loops. If `(fix v1)` were evaluated immediately, we would get an infinite chain of expansions. Instead, evaluation only continues when the recursive function actually makes a recursive call.\n\n`fix` is not an OCaml primitive; it is a pedagogical device. If you *did* want to define it directly in OCaml, you could (ironically) do so using `let rec`:\n\n```ocaml env=ch3\nlet fix f =\n  let rec self x = f self x in\n  self\n```\n\n#### Practice\n\nThe best way to understand reduction semantics is to work through examples by hand. Trace the evaluation of these expressions step by step:\n\n**Exercise 1:** Evaluate `let double x = x + x in double 3`\n\n**Exercise 2:** Evaluate `(fun f -\u003e fun x -\u003e f (f x)) (fun y -\u003e y + 1) 0`\n\n**Exercise 3:** Define the factorial function using `fix` and trace the evaluation of `factorial 3`\n\n### 3.3 Symbolic Derivation Example\n\nLet us see the reduction rules in action with a more substantial example. We will build a small computer algebra system that can represent mathematical expressions symbolically, evaluate them, and even compute their derivatives symbolically.\n\nConsider the symbolic expression type from `Lec3.ml`:\n\n```ocaml env=ch3\ntype expression =\n  | Const of float\n  | Var of string\n  | Sum of expression * expression    (* e1 + e2 *)\n  | Diff of expression * expression   (* e1 - e2 *)\n  | Prod of expression * expression   (* e1 * e2 *)\n  | Quot of expression * expression   (* e1 / e2 *)\n\nexception Unbound_variable of string\n\nlet rec eval env exp =\n  match exp with\n  | Const c -\u003e c\n  | Var v -\u003e\n    (try List.assoc v env with Not_found -\u003e raise (Unbound_variable v))\n  | Sum(f, g) -\u003e eval env f +. eval env g\n  | Diff(f, g) -\u003e eval env f -. eval env g\n  | Prod(f, g) -\u003e eval env f *. eval env g\n  | Quot(f, g) -\u003e eval env f /. eval env g\n```\n\nThe `expression` type represents mathematical expressions as a tree structure. Each constructor corresponds to a different kind of expression: constants, variables, and the four basic arithmetic operations. The `eval` function takes an environment `env` (a list of variable-value pairs) and recursively evaluates an expression to a floating-point number.\n\nWe can also define *symbolic differentiation*---computing the derivative of an expression without evaluating it numerically:\n\n```ocaml env=ch3\nlet rec deriv exp dv =\n  match exp with\n  | Const _ -\u003e Const 0.0\n  | Var v -\u003e if v = dv then Const 1.0 else Const 0.0\n  | Sum(f, g) -\u003e Sum(deriv f dv, deriv g dv)\n  | Diff(f, g) -\u003e Diff(deriv f dv, deriv g dv)\n  | Prod(f, g) -\u003e Sum(Prod(f, deriv g dv), Prod(deriv f dv, g))\n  | Quot(f, g) -\u003e Quot(Diff(Prod(deriv f dv, g), Prod(f, deriv g dv)),\n                       Prod(g, g))\n```\n\nThe `deriv` function implements the standard rules of calculus:\n\n- The derivative of a constant is 0.\n- The derivative of the variable we are differentiating with respect to is 1; any other variable is treated as a constant (derivative 0).\n- The sum and difference rules: $(f + g)' = f' + g'$ and $(f - g)' = f' - g'$.\n- The product rule: $(f \\cdot g)' = f \\cdot g' + f' \\cdot g$.\n- The quotient rule: $(f / g)' = (f' \\cdot g - f \\cdot g') / g^2$.\n\nFor convenience, let us define some operators and variables so we can write expressions more naturally:\n\n```ocaml env=ch3\nlet x = Var \"x\"\nlet y = Var \"y\"\nlet z = Var \"z\"\nlet (+:) f g = Sum (f, g)\nlet (-:) f g = Diff (f, g)\nlet ( *: ) f g = Prod (f, g)\nlet (/:) f g = Quot (f, g)\nlet (!:) i = Const i\n```\n\nThese custom operators (ending in `:`) let us write symbolic expressions that look almost like regular mathematical notation.\n\nNow let us evaluate the expression $3x + 2y + x^2 y$ at $x = 1, y = 2$:\n\n```ocaml env=ch3\nlet example = !:3.0 *: x +: !:2.0 *: y +: x *: x *: y\nlet env = [\"x\", 1.0; \"y\", 2.0]\n```\n\nFor nicer output, it is helpful to define a pretty-printer that displays expressions in infix notation (this is adapted from `Lec3.ml`):\n\n```ocaml env=ch3\nlet print_expr ppf exp =\n  let open_paren prec op_prec =\n    if prec \u003e op_prec then Format.fprintf ppf \"(@[\"\n    else Format.fprintf ppf \"@[\" in\n  let close_paren prec op_prec =\n    if prec \u003e op_prec then Format.fprintf ppf \"@])\"\n    else Format.fprintf ppf \"@]\" in\n  let rec print prec exp =\n    match exp with\n    | Const c -\u003e Format.fprintf ppf \"%.2f\" c\n    | Var v -\u003e Format.fprintf ppf \"%s\" v\n    | Sum(f, g) -\u003e\n      open_paren prec 0;\n      print 0 f; Format.fprintf ppf \"@ +@ \"; print 0 g;\n      close_paren prec 0\n    | Diff(f, g) -\u003e\n      open_paren prec 0;\n      print 0 f; Format.fprintf ppf \"@ -@ \"; print 1 g;\n      close_paren prec 0\n    | Prod(f, g) -\u003e\n      open_paren prec 2;\n      print 2 f; Format.fprintf ppf \"@ *@ \"; print 2 g;\n      close_paren prec 2\n    | Quot(f, g) -\u003e\n      open_paren prec 2;\n      print 2 f; Format.fprintf ppf \"@ /@ \"; print 3 g;\n      close_paren prec 2\n  in\n  print 0 exp\n```\n\nAnd for tracing, we define a specialized evaluator `eval_1_2` with the environment baked in (so the trace focuses on the expression structure):\n\n```ocaml env=ch3\nlet rec eval_1_2 exp =\n  match exp with\n  | Const c -\u003e c\n  | Var v -\u003e\n    (try List.assoc v env with Not_found -\u003e raise (Unbound_variable v))\n  | Sum(f, g) -\u003e eval_1_2 f +. eval_1_2 g\n  | Diff(f, g) -\u003e eval_1_2 f -. eval_1_2 g\n  | Prod(f, g) -\u003e eval_1_2 f *. eval_1_2 g\n  | Quot(f, g) -\u003e eval_1_2 f /. eval_1_2 g\n```\n\nIn the toplevel, you can now install the printer and trace the evaluation:\n\n```ocaml skip\n# #install_printer print_expr;;\n# #trace eval_1_2;;\n# eval_1_2 example;;\n```\n\nThe trace output makes the recursive structure of the computation very concrete:\n\n```\neval_1_2 \u003c-- 3.00 * x + 2.00 * y + x * x * y\n  eval_1_2 \u003c-- x * x * y\n    eval_1_2 \u003c-- y\n    eval_1_2 --\u003e 2.\n    eval_1_2 \u003c-- x * x\n      eval_1_2 \u003c-- x\n      eval_1_2 --\u003e 1.\n      eval_1_2 \u003c-- x\n      eval_1_2 --\u003e 1.\n    eval_1_2 --\u003e 1.\n  eval_1_2 --\u003e 2.\n  eval_1_2 \u003c-- 3.00 * x + 2.00 * y\n    eval_1_2 \u003c-- 2.00 * y\n      eval_1_2 \u003c-- y\n      eval_1_2 --\u003e 2.\n      eval_1_2 \u003c-- 2.00\n      eval_1_2 --\u003e 2.\n    eval_1_2 --\u003e 4.\n    eval_1_2 \u003c-- 3.00 * x\n      eval_1_2 \u003c-- x\n      eval_1_2 --\u003e 1.\n      eval_1_2 \u003c-- 3.00\n      eval_1_2 --\u003e 3.\n    eval_1_2 --\u003e 3.\n  eval_1_2 --\u003e 7.\neval_1_2 --\u003e 9.\n- : float = 9.\n```\n\nThe arrows `\u003c--` and `--\u003e` show function calls and returns, respectively. Each level of indentation represents a nested function call. These indentation levels correspond to **stack frames**---the runtime structures that store the state of each function call. Each time `eval_1_2` is called recursively, a new stack frame is created to remember where to return and what computation remains.\n\nThe final result is $3 \\cdot 1 + 2 \\cdot 2 + 1 \\cdot 1 \\cdot 2 = 3 + 4 + 2 = 9$, as expected.\n\nThis trace visualization brings us to an important question: what happens when we have very deep recursion? This leads us to our next topic.\n\n### 3.4 Tail Calls and Tail Recursion\n\nThe call stack is finite, and each recursive call typically adds a new frame to it. This means that deeply recursive functions can exhaust the stack and crash---a notorious problem known as \"stack overflow.\" Fortunately, functional language implementations have a trick to avoid this problem in many cases.\n\nExcuse me for not formally defining what a *function call* is... Computers normally evaluate programs by creating **stack frames** on the call stack for each function call. A stack frame stores the local variables, the return address (where to continue after the function returns), and other bookkeeping information. The trace in the previous section illustrates this: each level of indentation represents a new stack frame.\n\n#### What is a Tail Call?\n\nThe key insight is that not all function calls require a new stack frame. A **tail call** is a function call that is performed as the very last action when computing a function---there is nothing more to do after the call returns except to return that value. For example:\n\n```ocaml skip\nlet f x = g (x + 1)\n```\n\nThe call to `g` is a tail call. Once `g` returns some value, `f` simply returns that same value---no further computation is needed.\n\nIn contrast:\n\n```ocaml skip\nlet f x = 1 + g x\n```\n\nThe call to `g` is *not* a tail call. After `g` returns, we still need to add 1 to the result before `f` can return. This means we need to remember to do the addition, which requires keeping the stack frame around.\n\n#### Tail Call Optimization\n\nFunctional language compilers (including OCaml's) recognize tail calls and optimize them by performing **tail call optimization** (TCO). Instead of creating a new stack frame, the compiler generates code that reuses the current frame by performing a \"jump\" to the called function. This means tail calls use constant stack space, no matter how deep the call chain goes.\n\nThis optimization is not just a nice-to-have; it is *essential* for functional programming. Without TCO, many natural recursive algorithms would be impractical because they would overflow the stack on moderately large inputs.\n\n#### Tail Recursive Functions\n\nA function is **tail recursive** if all of its recursive calls (including calls to mutually recursive functions it depends on) are tail calls.\n\nWriting tail recursive functions requires a shift in thinking. Instead of building up the result as recursive calls return, we build it up as we *make* the calls. This typically requires an extra **accumulator** argument that carries the partial result through the recursion.\n\nThe key insight is that with an accumulator, results are computed in \"reverse order\"---we do the work while climbing *into* the recursion (making calls) rather than while climbing *out* (returning from calls).\n\n#### Example: Counting\n\nLet us see this in action with a simple counting function. Compare these two versions:\n\n```ocaml env=ch3\nlet rec count n =\n  if n \u003c= 0 then 0 else 1 + (count (n-1))\n```\n\nThis version is *not* tail recursive. Look at the recursive case: after `count (n-1)` returns, we still need to add 1 to the result. Each recursive call must remember to do this addition, consuming a stack frame.\n\nNow compare with the tail recursive version:\n\n```ocaml env=ch3\nlet rec count_tcall acc n =\n  if n \u003c= 0 then acc else count_tcall (acc+1) (n-1)\n```\n\nHere, the recursive call `count_tcall (acc+1) (n-1)` is the very last thing the function does---its result becomes our result directly. The accumulator `acc` carries the running count: we add 1 to it *before* the recursive call rather than *after* it returns. To count to 1000000, we call `count_tcall 0 1000000`.\n\n#### Example: Building Lists\n\nThe counting example does not really show the practical impact because the numbers are so small. Let us see a more dramatic example with lists:\n\n```ocaml env=ch3\nlet rec unfold n = if n \u003c= 0 then [] else n :: unfold (n-1)\n```\n\nThis function builds a list counting down from `n` to 1. It is not tail recursive because after the recursive call `unfold (n-1)` returns, we must cons `n` onto the front of the result.\n\n```ocaml skip\n# unfold 100000;;\n- : int list = [100000; 99999; 99998; 99997; ...]\n\n# unfold 1000000;;\nStack overflow during evaluation (looping recursion?).\n```\n\nWith 100,000 elements, it works. But with a million elements, we run out of stack space and the program crashes! This is a serious problem for practical programming.\n\nNow consider the tail-recursive version:\n\n```ocaml env=ch3\nlet rec unfold_tcall acc n =\n  if n \u003c= 0 then acc else unfold_tcall (n::acc) (n-1)\n```\n\nThe accumulator `acc` collects the list as we go. We cons each element onto the accumulator *before* the recursive call. However, there is a catch: because we are building the list as we descend into the recursion (rather than as we return), the list comes out in reverse order:\n\n```ocaml skip\n# unfold_tcall [] 100000;;\n- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; ...]\n\n# unfold_tcall [] 1000000;;\n- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; ...]\n```\n\nThe tail-recursive version handles a million elements effortlessly. The trade-off is that we get `[1; 2; 3; ...]` instead of `[1000000; 999999; ...]`. If we need the original order, we could reverse the result at the end (which is an O(n) operation but uses only constant stack space).\n\n#### A Challenge: Tree Depth\n\nNot all recursive functions can be easily converted to tail recursive form. Consider this problem: can we find the depth of a binary tree using a tail-recursive function?\n\n```ocaml env=ch3\ntype btree = Tip | Node of int * btree * btree\n```\n\nHere is the natural recursive approach:\n\n```ocaml env=ch3\nlet rec depth tree = match tree with\n  | Tip -\u003e 0\n  | Node(_, left, right) -\u003e 1 + max (depth left) (depth right)\n```\n\nThis is not tail recursive: after both recursive calls return, we still need to compute `1 + max ...`. The fundamental challenge is that we have *two* recursive calls that we need to make. A simple accumulator will not work---we cannot proceed with one subtree until we know the result of the other.\n\nThis seems like an impossible situation. How can we make a function tail recursive when it inherently needs to explore two branches? The answer involves a technique called *continuation passing style*, which we explore in the next section.\n\n#### Note on Lazy Languages\n\nThe issue of tail recursion is more nuanced for **lazy** programming languages like Haskell. In a lazy language, expressions are only evaluated when their values are actually needed. The cons operation `(:)` does not immediately evaluate its arguments---it just builds a \"promise\" to compute them later.\n\nThis means that building a list with `n : unfold (n-1)` does not consume stack space in the same way as in OCaml. The `unfold (n-1)` is not evaluated immediately; it is just stored as an unevaluated expression (called a \"thunk\"). Stack space is only consumed later, when you actually traverse the list. This gives lazy languages different performance characteristics and trade-offs.\n\n### 3.5 First Encounter of Continuation Passing Style\n\nWe can solve the tree depth problem using **Continuation Passing Style (CPS)**. This is a powerful technique that transforms programs in a surprising way: instead of returning values, functions receive an extra argument---a *continuation*---that tells them what to do with their result.\n\nThe key idea is to postpone doing actual work until the very last moment by passing around a continuation---a function that represents \"what to do next with this result.\"\n\n```ocaml env=ch3\nlet rec depth_cps tree k = match tree with\n  | Tip -\u003e k 0\n  | Node(_, left, right) -\u003e\n    depth_cps left (fun dleft -\u003e\n      depth_cps right (fun dright -\u003e\n        k (1 + (max dleft dright))))\n\nlet depth tree = depth_cps tree (fun d -\u003e d)\n```\n\nLet us understand how this works step by step:\n\n1. **The continuation parameter:** The function takes an extra parameter `k`, called the **continuation**. Instead of returning a value directly, `depth_cps` will call `k` with its result. You can think of `k` as meaning \"and then do this with the answer.\"\n\n2. **The base case (`Tip`):** When we reach a leaf, the depth is 0. Instead of returning 0, we call `k 0`---\"give 0 to whoever is waiting for our answer.\"\n\n3. **The recursive case (`Node`):** This is where CPS shines. We need to compute depths of both subtrees and combine them. Here is how we do it:\n   - First, recursively compute the depth of the left subtree. But instead of waiting for the result, we pass a continuation: `fun dleft -\u003e ...`\n   - This continuation says \"when you have the left depth (call it `dleft`), then...\"\n   - ...compute the depth of the right subtree, passing another continuation: `","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukstafi%2Fcurious-ocaml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukstafi%2Fcurious-ocaml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukstafi%2Fcurious-ocaml/lists"}