simple-learning

Simple learning web program
git clone git://git.laack.co/simple-learning.git
Log | Files | Refs | README | LICENSE

commit dbca09ccc0c77b7722983ff4eef805c066bb7558
parent 0c964c7fb55bf58554baaf03c83d07648eae325a
Author: Andrew Laack <andrew@laack.co>
Date:   Fri, 28 Aug 2026 12:43:15 -0500

Continued conversion process; I should make a converter md -> sl

Diffstat:
Acourses/ocaml/0_installation.sl | 300+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dcourses/ocaml/0_ocaml.sl | 29-----------------------------
Acourses/ocaml/1.0_better_programming_through_ocaml.sl | 24++++++++++++++++++++++++
Acourses/ocaml/1.1_the_past_of_ocaml.sl | 13+++++++++++++
Acourses/ocaml/1.2_the_present_of_ocaml.sl | 43+++++++++++++++++++++++++++++++++++++++++++
Dcourses/ocaml/1_ocaml.sl | 3---
Mdocs/sl.sl | 4++--
7 files changed, 382 insertions(+), 34 deletions(-)

diff --git a/courses/ocaml/0_installation.sl b/courses/ocaml/0_installation.sl @@ -0,0 +1,300 @@ +# Installing OCaml + +If all you need is a way to follow along with the code examples in this book, you don’t actually have to install OCaml! The code on each page is executable in your browser, as described earlier in this Preface. + +If you want to take it a step further but aren’t ready to spend time installing OCaml yourself, we provide a virtual machine with OCaml pre-installed inside a Linux OS. + +But if you want to do OCaml development on your own, you’ll need to install it on your machine. There’s no universally “right” way to do that. The instructions below are for Cornell’s CS 3110 course, which has goals and needs beyond just OCaml. Nonetheless, you might find them to be useful even if you’re not a student in the course. + +Here’s what we’re going to install: + +- A Unix development environment +- OPAM, the OCaml Package Manager +- An OPAM switch with the OCaml compiler and some packages +- The Visual Studio Code editor, with OCaml support + +The installation process will rely heavily on the terminal, or text interface to your computer. If you’re not too familiar with it, you might want to brush up with a terminal tutorial. + +Let’s get started! + +# Unix Development Environment + +## Linux + +If you’re already running Linux, you’re done with this step. Proceed to the Install OPAM section below. + +## Mac + +Beneath the surface, macOS is already a Unix-based OS. But you’re going to need some developer tools and a Unix package manager. There are two to pick from: Homebrew and MacPorts. From the perspective of this textbook and CS 3110, it doesn’t matter which you choose: + +- If you’re already accustomed to one, feel free to keep using it. Make sure to run its update command before continuing with these instructions. +- Otherwise, pick one and follow the installation instructions on its website. The installation process for Homebrew is typically easier and faster, which might nudge you in that direction. If you do choose MacPorts, make sure to follow all the detailed instructions on its page, including XCode and an X11 server. Do not install both Homebrew and MacPorts; they aren’t meant to co-exist. If you change your mind later, make sure to uninstall one before installing the other. + +After you’ve finished installing/updating either Homebrew or MacPorts, proceed to the Install OPAM section below. +Windows + +Unix development in Windows is made possible by the Windows Subsystem for Linux (WSL). If you have a recent version of Windows (build 20262, released November 2020, or newer), WSL is easy to install. If you don’t have that recent of a version, try running Windows Update to get it. + +## Windows + +Unix development in Windows is made possible by the Windows Subsystem for Linux (WSL). If you have a recent version of Windows (build 20262, released November 2020, or newer), WSL is easy to install. If you don’t have that recent of a version, try running Windows Update to get it. + +With a recent version of Windows, and assuming you’ve never installed WSL before, here’s all you have to do: + +- Open Windows PowerShell as Administrator. To do that, click Start, type PowerShell, and it should come up as the best match. Click “Run as Administrator”, and click Yes to allow changes. +- Run wsl --install. (Or, if you have already installed WSL but not Ubuntu before, then instead run wsl --install -d Ubuntu.) When the Ubuntu download is completed, it will likely ask you to reboot. Do so. The installation will automatically resume after the reboot. +- You will be prompted to create a Unix username and password. You can use any username and password you wish. It has no bearing on your Windows username and password (though you are free to re-use those). Do not put a space in your username. Do not forget your password. You will need it in the future. + +Now skip to the “Ubuntu setup” paragraph below. + +Without a recent version of Windows, you will need to follow Microsoft’s manual installation instructions. WSL2 is preferred over WSL1 by OCaml (and WSL2 offers performance and functionality improvements), so install WSL2 if you can. + +Ubuntu setup. These rest of these instructions assume that you installed Ubuntu (22.04) as the Linux distribution. That is the default distribution in WSL. In principle other distributions should work, but might require different commands from this point forward. + +Open the Ubuntu app. (It might already be open if you just finished installing WSL.) You will be at the Bash prompt, which looks something like this: + +``` +user@machine:~$ +``` + +In the current version of the Windows terminal, Ctrl+Shift+C will copy and Ctrl+Shift+V will paste into the terminal. Note that you have to include Shift as part of that keystroke. In older versions of the terminal, you might need to find an option in the terminal settings to enable those keyboard shortcuts. + +Run the following command to update the APT package manager, which is what helps to install Unix packages: + +``` +sudo apt update +``` + +You will be prompted for the Unix password you chose. The prefix sudo means to run the command as the administrator, aka “super user”. In other words, do this command as super user, hence, “sudo”. + +Now run this command to upgrade all the APT software packages: + +``` +sudo apt upgrade -y +``` + +Then install some useful packages that we will need: + +``` +sudo apt install -y zip unzip build-essential +``` + +File Systems. WSL has its own filesystem that is distinct from the Windows file system, though there are ways to access each from the other. + +- When you launch Ubuntu and get the $ prompt, you are in the WSL file system. Your home directory there is named ~, which is a built-in alias for /home/your_ubuntu_user_name. You can run explorer.exe . (note the dot at the end of that) to open your Ubuntu home directory in Windows explorer. + +- From Ubuntu, you can access your Windows home directory at the path /mnt/c/Users/your_windows_user_name/. + +- From Windows Explorer, you can access your Ubuntu home directory under the Linux icon in the left-hand list (near “This PC” and “Network”), then navigating to Ubuntu → home → your_ubuntu_user_name. Or you can go there directly by typing into the Windows Explorer path bar: \\wsl$\Ubuntu\home\your_ubuntu_user_name. + +Practice accessing your Ubuntu and Windows home directories now, and make sure you can recognize which you are in. For advanced information, see Microsoft’s guide to Windows and Linux file systems. + +=> https://learn.microsoft.com/en-us/windows/wsl/filesystems + +We recommend storing your OCaml development work in your Ubuntu home directory, not your Windows home directory. By implication, Microsoft also recommends that in the guide just linked. + +# Install OPAM + +Mac. If you’re using Homebrew, run this command: + +``` +brew install opam +``` + +If you’re using MacPorts, run this command: + +``` +sudo port install opam +``` + +Windows. Run this command from Ubuntu: + +``` +sudo apt install opam +``` + +Linux. Follow the instructions for your distribution. + +# Initialize OPAM + +Linux, Mac, and WSL2. Run: + +``` +opam init --bare -a -y +``` + +Don’t worry if you get a note about making sure .profile is “well-sourced” in .bashrc. You don’t need to do anything about that. + +If you get a warning that OPAM is out of date, update it by running: + +``` +opam update +``` + +WSL1. Hopefully you are running WSL2, not WSL1. But on WSL1, run: + +``` +opam init --bare -a -y --disable-sandboxing +``` + +It is necessary to disable sandboxing because of an issue involving OPAM and WSL1. + +# Create an OPAM Switch + +A switch is a named installation of OCaml with a particular compiler version and set of packages. You can have many switches and, well, switch between them —whence the name. Create a switch for this semester’s CS 3110 by running this command: + +``` +opam switch create cs3110-2026fa ocaml-base-compiler.5.3.0 +``` + + +You might be prompted to run the next command. It won’t matter whether you do or not, because of the very next step we’re going to do (i.e., logging out). + +``` +eval $(opam env) +``` + +Now we need to make sure your OCaml environment was configured correctly. Logout from your OS (or just reboot). Then re-open your terminal and run this command: + +``` +opam switch list +``` + +You should get output like this: + +``` +# switch compiler +→ cs3110-2026fa ocaml-base-compiler.5.3.0,ocaml-options-vanilla.1 +``` + +There might be other lines if you happen to have done OCaml development before. There will be another column named “description” whose contents are not shown here. Double check the following: + +- You must not get a warning that “The environment is not in sync with the current switch. You should run eval $(opam env)”. If either of the two issues below also occur, you need to resolve this issue first. +- There must be a right arrow in the first column next to the current semester’s switch. +- That switch must have the right name and the right compiler version. + +Continue by installing the OPAM packages we need: + +``` +opam install -y utop odoc ounit2 qcheck bisect_ppx menhir ocaml-lsp-server ocamlformat +``` + +Make sure to grab that whole line above when you copy it. You will get some output about editor configuration. Unless you intend to use Emacs or Vim for OCaml development, you can safely ignore that output. We’re going to use VS Code as the editor in these instructions, so let’s ignore it. + +You should now be able to launch utop, the OCaml Universal Toplevel. + +``` +utop +``` + +Enter 3110 followed by two semicolons. Press return. The # is the utop prompt; you do not type it yourself. + +``` +# 3110;; +- : int = 3110 +``` + +Stop to appreciate how lovely 3110 is. Then quit utop. Note that this time you must enter the extra # before the quit directive. + +``` +# #quit;; +``` + +A faster way to quit is to type Control+D. + +# Double-Check OCaml + +If you’re having any trouble with your installation, follow these double-check instructions. Some of them repeat the tips we provided above, but we’ve put them all here in one place to help diagnose any issues. + +First, reboot your computer. We need a clean slate for this double-check procedure. + +Second, run utop, and make sure it works. If it does not, here are some common issues: + +- Are you in the right Unix prompt? On Mac, make sure you are in whatever Unix shell is the default for your Terminal: don’t run bash or zsh or anything else manually to change the shell. On Windows, make sure you are in the Ubuntu app, not PowerShell or Cmd. +- Is the OPAM environment set? If utop isn’t a recognized command, run eval $(opam env) then try running utop again. If utop now works, your login shell is somehow not running the right commands to automatically activate the OPAM environment; you shouldn’t have to manually activate the environment with the eval command. Probably something went wrong earlier when you ran the opam init command. To fix it, follow the “redo” instructions below. +- Is your switch listed? Run opam switch list and make sure a switch named cs3110-2026fa is listed, that it has the 5.3.0 compiler, and that it is the active switch (which is indicated with an arrow beside it). If that switch is present but not active, run opam switch cs3110-2026fa then see whether utop works. If that switch is not present, follow the “redo” instructions below. + +Redo Instructions: Remove the OPAM directory by running rm -r ~/.opam. Then go back to the OPAM initialization step in the instructions way above, and proceed forward. Be extra careful to use the exact OPAM commands given above; sometimes mistakes occur when parts of them are omitted. Finally, double-check again: reboot and see whether utop still works. + +# Visual Studio Code + +Visual Studio Code is a great choice as a code editor for OCaml. (Though if you are already a power user of Emacs or Vim those are great, too.) + +First, download and install Visual Studio Code (henceforth, VS Code) following Microsoft’s instructions for your OS: Mac instructions, Windows instructions, Linux instructions. + +Launch VS Code. Open the extensions pane, either by going to View → Extensions, or by clicking on the icon for it in the column of icons on the left — it looks like four little squares, the top-right of which is separated from the other three. + +At various points in the following instructions you will be asked to “open the Command Palette.” To do that, go to View → Command Palette. There is also an operating system specific keyboard shortcut, which you will see to the right of the words “Command Palette” in that View menu. + +Second, follow one of these steps if you are on Windows or Mac: + +- Windows only: Install the “WSL” extension. +- Mac only: Open the Command Palette and type “shell command” to find the “Shell Command: Install ‘code’ command in PATH” command. Run it. + +Third, regardless of your OS, close any open terminals — or just logout or reboot — to let the new path settings take effect, so that you will later be able to launch VS Code from the terminal. + +Fourth, on Windows only, open the Command Palette and run the command “WSL: Connect to WSL”. (If you’re on Mac, skip ahead to the next step.) The first time you do this, it will install some additional software. After that completes, you will see a “WSL: Ubuntu” indicator in the bottom-left of the VS Code window. Make sure that you see “WSL: Ubuntu” there before proceeding with the next step below. If you see just an icon that looks like >< then click it, and choose “Connect to WSL” from the Command Palette that opens. + +Fifth, again open the VS Code extensions pane. Search for and install the “OCaml Platform” extension from OCaml Labs. Be careful to install the extension with exactly that name. + +## Double-Check VS Code + +Let’s make sure VS Code’s OCaml support is working. + +- Reboot your computer again. (Yeah, that really shouldn’t be necessary. But it will detect so many potential mistakes now that it’s worth the effort.) +- Open a fresh new Unix shell. Windows: remember that’s the Ubuntu, not PowerShell or Cmd. Mac: remember that you shouldn’t be manually switching to a different shell by typing zsh or bash. +- Navigate to a directory of your choice, preferably a subdirectory of your home directory. For example, you might create a directory for your 3110 work inside your home directory: + +``` +mkdir ~/3110 +cd ~/3110 +``` + +In that directory open VS Code by running: + +``` +code . +``` + +Go to File → New File. Save the file with the name test.ml. VS Code should give it an orange camel icon. + +Type the following OCaml code then press Return/Enter: + +``` +let x : int = 3110 +``` + +As you type, VS Code should colorize the syntax, suggest some completions, and add a little annotation above the line of code. Try changing the int you typed to string. A squiggle should appear under 3110. Hover over it to see the error message. Go to View → Problems to see it there, too. Add double quotes around the integer to make it a string, and the problem will go away. + +If you don’t observe those behaviors, something is wrong with your installation. Here’s how to proceed: + +- Make sure that, from the same Unix prompt as which you launched VS Code, you can successfully complete the double-check instructions for your OPAM switch: Can you run utop? Is the right switch active? If not, that’s the problem you need to solve first. Then return to the VS Code issue. It might be fixed now. +- Make sure that you are on the most current version of VS Code. Run the VS Code palette command “Code: Check for Updates”. If you cannot get VS Code to update and you are on Mac, make sure that you followed Microsoft’s instructions to install VS Code in your Application folder. +- If you’re on WSL and VS Code does add syntax highlighting but does not add squiggles as described above, and/or you get an error about “Sandbox initialization failed”, then double-check that you see a “WSL” indicator in the bottom left of the VS Code window. If you do, make sure that the “OCaml Platform” extension is installed. If you do not, make sure you installed the “WSL” extension as described above, and that you are launching VS Code from Ubuntu rather than PowerShell or from the Windows GUI. + +If you’re still stuck with an issue, try uninstalling VS Code, rebooting, and re-doing all the installation instructions above from scratch. Pay close attention to any warnings or errors. + +## VS Code Settings + +We recommend tweaking a few editor settings. Open the user settings JSON file by (i) going to View → Command Palette, (ii) typing “user settings json”, and (iii) selecting Open User Settings (JSON). You will see a JSON file that might already have some settings in it. If so, it will look like this: + +``` +{ + (your pre-existing settings here) +} +``` + +Add these new settings into that outermost set of braces: + +``` +{ + "[ocaml][ocaml.interface]": { + "editor.tabSize": 2, + "editor.rulers": [ 80 ], + "editor.formatOnSave": true + }, + (your pre-existing settings here) +} +``` + +Save the file and close the tab. diff --git a/courses/ocaml/0_ocaml.sl b/courses/ocaml/0_ocaml.sl @@ -1,29 +0,0 @@ -# OCaml - -## History - -OCaml is the acronym for Objective Categorical Abstract Machine Language. - -## Syntax - -In OCaml we use the 'let' keyword to bind a expressions to names (variables). Shown below is an example of this: - -``` -let factorial x = - let rec go acc current = - if current = 0 - then acc - else - go (acc * current) (current - 1) - in go 1 x;; -print_endline (string_of_int(factorial 6));; -``` - - -=>v assets/out.webm - -=>i assets/em.png - -When was ocaml created? - -?? OCaml was created in 1984 diff --git a/courses/ocaml/1.0_better_programming_through_ocaml.sl b/courses/ocaml/1.0_better_programming_through_ocaml.sl @@ -0,0 +1,24 @@ +# Better Programming Through OCaml + +Do you already know how to program in a mainstream language like Python or Java? Good. This book is for you. It's time to learn how to program better. It's time to learn a functional language, OCaml. + +=>e https://www.youtube.com/embed/MUcka_SvhLw + +Functional programming provides a different perspective on programming than what you have experienced so far. Adapting to that perspective requires letting go of old ideas: assignment statements, loops, classes and objects, among others. That won't be easy. + +I believe that learning OCaml will make you a better programmer. Here's why: + +- You will experience the freedom of immutability, in which the values of so-called "variables" cannot change. Goodbye, debugging. +- You will improve at abstraction, which is the practice of avoiding repetition by factoring out commonality. Goodbye, bloated code. +- You will be exposed to a type system that you will at first hate because it rejects programs you think are correct. But you will come to love it, because you will humbly realize it was right and your programs were wrong. Goodbye, failing tests. +- You will be exposed to some of the theory and implementation of programming languages, helping you to understand the foundations of what you are saying to the computer when you write code. Goodbye, mysterious and magic incantations. + +All of those ideas can be learned in other contexts and languages. But OCaml provides an incredible opportunity to bundle them all together. OCaml will change the way you think about programming. + +> A language that doesn't affect the way you think about programming is not worth knowing. + +-- Alan J. Perlis (1922-1990), first recipient of the Turing Award + +Moreover, OCaml is beautiful. OCaml is elegant, simple, and graceful. Aesthetics do matter. Code isn't written just to be executed by machines. It's also written to communicate to humans. Elegant code is easier to read and maintain. It isn't necessarily easier to write. + +The OCaml code you write can be stylish and tasteful. At first, this might not be apparent. You are learning a new language after all -- you wouldn't expect to appreciate Sanskrit poetry on day 1 of Introductory Sanskrit. In fact, you'll likely feel frustrated for a while as you struggle to express yourself in a new language. So give it some time. After you've mastered OCaml, you might be surprised at how ugly those other languages you already know end up feeling when you return to them. diff --git a/courses/ocaml/1.1_the_past_of_ocaml.sl b/courses/ocaml/1.1_the_past_of_ocaml.sl @@ -0,0 +1,13 @@ +# The Past of OCaml + +Genealogically, OCaml comes from the line of programming languages whose grandfather is Lisp and includes other modern languages such as Clojure, F#, Haskell, and Racket. + +OCaml originates from work done by Robin Milner and others at the Edinburgh Laboratory for Computer Science in Scotland. They were working on theorem provers in the late 1970s and early 1980s. Traditionally, theorem provers were implemented in languages such as Lisp. Milner kept running into the problem that the theorem provers would sometimes put incorrect "proofs" (i.e., non-proofs) together and claim that they were valid. So he tried to develop a language that only allowed you to construct valid proofs. ML, which stands for "Meta Language", was the result of that work. The type system of ML was carefully constructed so that you could only construct valid proofs in the language. A theorem prover was then written as a program that constructed a proof. Eventually, this "Classic ML" evolved into a full-fledged programming language. + +In the early '80s, there was a schism in the ML community with the French on one side and the British and US on another. The French went on to develop CAML and later Objective CAML (OCaml) while the Brits and Americans developed Standard ML. The two dialects are quite similar. Microsoft introduced its own variant of OCaml called F# in 2005. + +Milner received the Turing Award in 1991 in large part for his work on ML. The includes this praise: + +=> https://amturing.acm.org/award_winners/milner_1569367.cfm + +> ML was way ahead of its time. It is built on clean and well-articulated mathematical ideas, teased apart so that they can be studied independently and relatively easily remixed and reused. ML has influenced many practical languages, including Java, Scala, and Microsoft’s F#. Indeed, no serious language designer should ignore this example of good design. diff --git a/courses/ocaml/1.2_the_present_of_ocaml.sl b/courses/ocaml/1.2_the_present_of_ocaml.sl @@ -0,0 +1,43 @@ +# The Present of OCaml + +=>e https://www.youtube.com/embed/JTEwC3HihFc + +OCaml is a functional programming language. The key linguistic abstraction of functional languages is the mathematical function. A function maps an input to an output; for the same input, it always produces the same output. That is, mathematical functions are *stateless*: they do not maintain any extra information or *state* that persists between usages of the function. Functions are *first-class*: you can use them as input to other functions, and produce functions as output. Expressing everything in terms of functions enables a uniform and simple programming model that is easier to reason about than the procedures and methods found in other families of languages. + +*Imperative* programming languages such as C and Java involve *mutable* state that changes throughout execution. *Commands* specify how to compute by destructively changing that state. Procedures (or methods) can have *side effects* that update state in addition to producing a return value. + +The **fantasy of mutability** is that it's easy to reason about: the machine does this, then this, etc. + +The **reality of mutability** is that whereas machines are good at complicated manipulation of state, humans are not good at understanding it. The essence of why that's true is that mutability breaks *referential transparency*: the ability to replace an expression with its value without affecting the result of a computation. In math, if $f(x)=y$, then you can substitute $y$ anywhere you see $f(x)$. In imperative languages, you cannot: $f$ might have side effects, so computing $f(x)$ at time $t$ might result in a different value than at time $t'$. + +It's tempting to believe that there's a single state that the machine manipulates, and that the machine does one thing at a time. Computer systems go to great lengths in attempting to provide that illusion. But it's just that: an illusion. In reality, there are many states, spread across threads, cores, processors, and networked computers. And the machine does many things concurrently. Mutability makes reasoning about distributed state and concurrent execution immensely difficult. + +*Immutability*, however, frees the programmer from these concerns. It provides powerful ways to build correct and concurrent programs. OCaml is primarily an immutable language, like most functional languages. It does support imperative programming with mutable state, but we won't use those features until many chapters into the book&mdash;in part because we simply won't need them, and in part to get you to quit "cold turkey" from a dependence you might not have known that you had. This freedom from mutability is one of the biggest changes in perspective that OCaml can give you. + +## The Features of OCaml + +=>e https://www.youtube.com/embed/T-DIW1dhYzo + +OCaml is a *statically-typed* and *type-safe* programming language. A statically-typed language detects type errors at compile time; if a type error is detected, the language won't allow execution of the program. A type-safe language limits which kinds of operations can be performed on which kinds of data. In practice, this prevents a lot of silly errors (e.g., treating an integer as a function) and also prevents a lot of security problems: over half of the reported break-ins at the Computer Emergency Response Team (CERT, a US government agency tasked with cybersecurity) were due to buffer overflows, something that's impossible in a type-safe language. + +Some languages, like Python and Racket, are type-safe but *dynamically typed*. That is, type errors are caught only at run time. Other languages, like C and C++, are statically typed but not type safe: they check for some type errors, but don't guarantee the absence of all type errors. That is, there's no guarantee that a type error won't occur at run time. And still other languages, like Java, use a combination of static and dynamic typing to achieve type safety. + +OCaml supports a number of advanced features, some of which you will have encountered before, and some of which are likely to be new: + +- **Algebraic data types:** You can build sophisticated data structures in OCaml easily, without fussing with pointers and memory management. *Pattern matching*&mdash;a feature we'll soon learn about that enables examining the shape of a data structure&mdash;makes them even more convenient. +- **Type inference:** You do not have to write type information down everywhere. The compiler automatically figures out most types. This can make the code easier to read and maintain. +- **Parametric polymorphism:** Functions and data structures can be parameterized over types. This is crucial for being able to re-use code. +- **Garbage collection:** Automatic memory management relieves you from the burden of memory allocation and deallocation, a common source of bugs in languages such as C. +- **Modules:** OCaml makes it easy to structure large systems through the use of modules. Modules are used to encapsulate implementations behind interfaces. OCaml goes well beyond the functionality of most languages with modules by providing functions (called *functors*) that manipulate modules. + +## OCaml in Industry + +=>e https://www.youtube.com/embed/eNLm5Xbgmd0 + +OCaml and other functional languages are nowhere near as popular as Python, C, or Java. OCaml's real strength lies in language manipulation (i.e., compilers, analyzers, verifiers, provers, etc.). This is not surprising, because OCaml evolved from the domain of theorem proving. + +That's not to say that functional languages aren't used in industry. There are many industry projects using OCaml and Haskell, among other languages. Yaron Minsky (Cornell PhD '02) even wrote a paper about using OCaml in the financial industry. It explains how the features of OCaml make it a good choice for quickly building complex software that works. + +=> https://ocaml.org/learn/companies.html +=> https://wiki.haskell.org/Haskell_in_industry +=> http://dx.doi.org/10.1017/S095679680800676X diff --git a/courses/ocaml/1_ocaml.sl b/courses/ocaml/1_ocaml.sl @@ -1,3 +0,0 @@ -# 1) OCaml - -this is the second page. diff --git a/docs/sl.sl b/docs/sl.sl @@ -14,8 +14,8 @@ Outside of preformatted blocks, there are eight line types: - Text lines - Text link lines -- Video link lines -- Image link lines +- Embedded link lines + - Renders an iframe - Heading lines - List items - Quote lines