/ Readme.org
Readme.org
  1  #+title: Ocaml Programming: Correct + Efficient + Beautiful
  2  #+author: HaQadosch
  3  #+date: [2023-12-02 Sat]
  4  #+startup: indent
  5  #+property: header-args :results output
  6  #+link playlist https://www.youtube.com/playlist?list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU
  7  #+link opam https://opam.ocaml.org/
  8  #+link docs https://ocaml.org/docs/your-first-program
  9  #+link course https://cs3110.github.io/textbook/cover.html
 10  * Org mode shortcuts
 11  - tangle :: ~org-babel-tangle~, ~C-c C-v C-t~
 12  
 13  ** Config
 14  - ~C-c C-c~ :: Refresh local setup for that file
 15  
 16  ** Dates:
 17  - ~C-c .~ :: active timestamps
 18    creates an entry in the agenda
 19  - ~C-c !~ :: inactive timestamps
 20    doesnΒ΄t create an entry in the agenda
 21  - link :: [[https://orgmode.org/orgguide.html#Timestamps][timestamps]]
 22  
 23  ** Links:
 24  - ~C-c C-l~ :: create link
 25  - link :: [[https://orgmode.org/orgguide.html#Hyperlinks][hyperlinks]]
 26  
 27  ** Tables
 28  - ~C-c }~ :: display cells references
 29  - ~C-c ?~ :: display ref for that cell
 30    references are =@ROW$COLUMN=
 31  - link :: [[https://orgmode.org/manual/References.html][table references]]
 32  - formula :: =@I..II=
 33    select all the rows between horizontal lines (hline) 1 and 2
 34    =vmean(@I..II);EN= column range mean, treats empty values as null (0)
 35  
 36  ** Whitespace
 37  - ~M-x whitespace-mode~ :: Activates a better whitespace mode
 38  - ~M-x auto-fill-mode~ :: Auto-fill, enforce max size limit
 39  - ~M-q~ :: Force auto-fill on current paragraph
 40  
 41  ** Feetnotes
 42  - ~C-c C-x f~ :: Creates a footnote, see [[https://orgmode.org/guide/Creating-Footnotes.html][guide]].
 43  - ~C-c C-c~ :: to jump between definition and refs.
 44  
 45  ** Todos
 46  - ~C-c C-t~ :: cycling throught the states of the todos
 47  - ~C-u C-c C-t~ :: Log the change of status
 48  
 49  ** Clocking work
 50  - ~C-c C-x C-i~ :: Clock in
 51  - ~C-c C-x C-o~ :: Clock out
 52  - ~C-c C-x C-d~ :: Display clocks
 53  
 54  ** Includes files
 55  Start with the directive ~INCLUDE~ and the location of the file
 56    - ~C-c '~ :: Visit the included file
 57    - ~C-c &~ :: Go back to the original doc
 58    🟑 The included doc start at the hierarchy of the inclusion
 59    See [[https://orgmode.org/manual/Include-Files.html][the manual]]
 60  
 61  ** Code Block - Structure Template
 62  - ~C-c C-,~ :: Insert structure template
 63  See [[https://orgmode.org/manual/Structure-Templates.html][17.2 Structure Templates]]
 64  and [[https://orgmode.org/manual/Structure-of-Code-Blocks.html][16.2 Structure of Code Blocks]]
 65  
 66  * Emacs Shortcut
 67  - Toggle display of quick help buffer :: ~C-h C-q~ or ~M-x cheat-sheet~
 68  
 69  * Install
 70  ** Opam
 71  Making a search via *guix* to see if I can install it easily
 72  #+name: search opam2 :results script
 73  #+begin_src shell
 74    guix search opam
 75  #+end_src
 76  
 77  #+RESULTS: search opam
 78  | name:         | opam                                     |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 79  | version:      | 2.1.3                                    |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 80  | outputs:      |                                          |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 81  | +             | out:                                     | everything                   |                  |                    |            |              |              |                |       |          |          |     |     |        |
 82  | systems:      | x86_64-linux                             |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 83  | dependencies: | bubblewrap@0.8.0                         | curl@8.4.0                   | dune@3.6.1       | git-minimal@2.33.1 |            |              |              |                |       |          |          |     |     |        |
 84  | +             | ncurses@6.2.20210619                     | ocaml-cmdliner@1.1.1         | ocaml-cppo@1.6.9 | ocaml-dose3@5.0.1  |            |              |              |                |       |          |          |     |     |        |
 85  | +             | ocaml-mccs@1.1+14                        | ocaml-opam-file-format@2.1.4 | ocaml-re@1.10.4  | ocaml@4.14.0       |            |              |              |                |       |          |          |     |     |        |
 86  | +             | openssl@3.0.8                            | python-wrapper@3.10.7        | rsync@3.2.7      | unzip@6.0          | which@2.21 |              |              |                |       |          |          |     |     |        |
 87  | location:     | gnu/packages/ocaml.scm:850:2             |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 88  | homepage:     | https://opam.ocamlpro.com/               |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 89  | license:      | LGPL                                     | 3                            |                  |                    |            |              |              |                |       |          |          |     |     |        |
 90  | synopsis:     | Package                                  | manager                      | for              | OCaml              |            |              |              |                |       |          |          |     |     |        |
 91  | description:  | OPAM                                     | is                           | a                | tool               | to         | manage       | OCaml        | packages.      | It    | supports | multiple |     |     |        |
 92  | +             | simultaneous                             | compiler                     | installations,   | flexible           | package    | constraints, | and          | a              |       |          |          |     |     |        |
 93  | +             | Git-friendly                             | development                  | workflow.        |                    |            |              |              |                |       |          |          |     |     |        |
 94  | relevance:    | 32                                       |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 95  |               |                                          |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 96  | name:         | ocaml-opam-file-format                   |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 97  | version:      | 2.1.4                                    |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 98  | outputs:      |                                          |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
 99  | +             | out:                                     | everything                   |                  |                    |            |              |              |                |       |          |          |     |     |        |
100  | systems:      | x86_64-linux                             | i686-linux                   |                  |                    |            |              |              |                |       |          |          |     |     |        |
101  | dependencies: |                                          |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
102  | location:     | gnu/packages/ocaml.scm:822:2             |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
103  | homepage:     | https://opam.ocaml.org                   |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
104  | license:      | LGPL                                     | 2.1+                         |                  |                    |            |              |              |                |       |          |          |     |     |        |
105  | synopsis:     | Parser                                   | and                          | printer          | for                | the        | opam         | file         | syntax         |       |          |          |     |     |        |
106  | description:  | This                                     | package                      | contains         | a                  | parser     | and          | a            | pretty-printer | for   | the      | opam     |     |     |        |
107  | +             | file                                     | format.                      |                  |                    |            |              |              |                |       |          |          |     |     |        |
108  | relevance:    | 11                                       |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
109  |               |                                          |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
110  | name:         | ocaml-opam-monorepo                      |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
111  | version:      | 0.3.5                                    |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
112  | outputs:      |                                          |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
113  | +             | out:                                     | everything                   |                  |                    |            |              |              |                |       |          |          |     |     |        |
114  | systems:      | x86_64-linux                             |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
115  | dependencies: | ocaml-odoc@2.2.0                         | pkg-config@0.29.2            |                  |                    |            |              |              |                |       |          |          |     |     |        |
116  | location:     | gnu/packages/ocaml.scm:987:2             |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
117  | homepage:     | https://github.com/tarides/opam-monorepo |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
118  | license:      | ISC                                      |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
119  | synopsis:     | Assemble                                 | and                          | manage           | fully              | vendored   | Dune         | repositories |                |       |          |          |     |     |        |
120  | description:  | The                                      | opam                         | monorepo         | plugin             | provides   | a            | convenient   | interface      | to    |          |          |     |     |        |
121  | +             | bridge                                   | the                          | opam             | package            | manager    | with         | having       | a              | local | copy     | of       | all | the | source |
122  | +             | code                                     | required                     | to               | build              | a          | project      | using        | the            | dune  | build    | tool.    |     |     |        |
123  | relevance:    | 10                                       |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
124  |               |                                          |                              |                  |                    |            |              |              |                |       |          |          |     |     |        |
125  
126  There is *opam 2.1.3*.
127  #+name: install opam
128  #+begin_src shell
129    guix install opam
130  #+end_src
131  
132  Cheking if the installation is successful.
133  #+name: check opam install
134  #+begin_src shell
135    opam --version
136  #+end_src
137  
138  #+RESULTS: check opam install
139  : 2.1.3
140  *** Initialisation
141  ~opam init~ will create the =.profile= and set up the =.bashrc= with
142  your environment. See https://opam.ocaml.org/doc/Usage.html#opam-init
143  
144  #+name: init opam
145  #+begin_src shell
146    opam init --bare -a -y
147  #+end_src
148  
149  #+RESULTS: init opam
150  | No        | configuration  | file       | found,      | using                                       | built-in | defaults. |           |              |        |     |         |     |       |         |    |      |         |
151  | Checking  | for            | available  | remotes:    | rsync                                       | and      | local,    | git.      |              |        |     |         |     |       |         |    |      |         |
152  | -         | you            | won't      | be          | able                                        | to       | use       | mercurial | repositories | unless | you | install | the | hg    | command | on | your | system. |
153  | -         | you            | won't      | be          | able                                        | to       | use       | darcs     | repositories | unless | you | install | the | darcs | command | on | your | system. |
154  |           |                |            |             |                                             |          |           |           |              |        |     |         |     |       |         |    |      |         |
155  |           |                |            |             |                                             |          |           |           |              |        |     |         |     |       |         |    |      |         |
156  | <><>      | Fetching       | repository | information | ><><><><><><><><><><><><><><><><><><><><><> |          |           |           |              |        |     |         |     |       |         |    |      |         |
157  | [default] | Initialised    |            |             |                                             |          |           |           |              |        |     |         |     |       |         |    |      |         |
158  |           |                |            |             |                                             |          |           |           |              |        |     |         |     |       |         |    |      |         |
159  | User      | configuration: |            |             |                                             |          |           |           |              |        |     |         |     |       |         |    |      |         |
160  | Updating  | ~/.profile.    |            |             |                                             |          |           |           |              |        |     |         |     |       |         |    |      |         |
161  
162  The advice is to make sure =.profile= and =.bashrc= knows each other.
163  ** Version of Ocaml
164  Called a switch, it is very much like using ~nvm~ for node projects
165  See https://opam.ocaml.org/doc/Usage.html#opam-switch
166  
167  Nothing has been installed before
168  #+name: check previous switch
169  #+begin_src shell
170    opam switch list
171  #+end_src
172  
173  #+RESULTS: check previous switch
174  : #  switch  compiler  description
175  
176  The list returned is empty. To see what is available in the remote
177  repo:
178  #+name: list switches
179  #+begin_src shell
180    opam switch list-available ocaml-base-compiler
181  #+end_src
182  
183  #+RESULTS: list switches
184  #+begin_example
185  # Listing available compilers from repositories: default
186  # Name              # Version # Synopsis
187  ocaml-base-compiler 4.10.2    Official release 4.10.2
188  ocaml-base-compiler 4.12.0    Official release 4.12.0
189  ocaml-base-compiler 4.12.1    Official release 4.12.1
190  ocaml-base-compiler 4.13.0    Official release 4.13.0
191  ocaml-base-compiler 4.13.1    Official release 4.13.1
192  ocaml-base-compiler 4.14.0    Official release 4.14.0
193  ocaml-base-compiler 4.14.1    Official release 4.14.1
194  ocaml-base-compiler 4.14.2    Official release 4.14.2
195  ocaml-base-compiler 5.0.0     Official release 5.0.0
196  ocaml-base-compiler 5.1.0     Official release 5.1.0
197  ocaml-base-compiler 5.1.1     Official release 5.1.1
198  ocaml-base-compiler 5.2.0     Official release 5.2.0
199  ocaml-base-compiler 5.2.1     Official release 5.2.1
200  ocaml-base-compiler 5.3.0     Official release of OCaml 5.3.0
201  #+end_example
202  
203  We can go with the version *5.3.0*
204  #+name: create switch
205  #+begin_src shell
206    opam switch create ocaml-book ocaml-base-compiler.5.3.0
207  #+end_src
208  
209  #+RESULTS: create switch
210  <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><>  🐫
211  Switch invariant: ["ocaml-base-compiler" {= "5.3.0"}]
212  
213  <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><>  🐫
214  ⬇ retrieved ocaml-config.3  (cached)
215  βˆ— installed base-bigarray.base
216  βˆ— installed base-threads.base
217  βˆ— installed base-unix.base
218  βˆ— installed ocaml-options-vanilla.1
219  ⬇ retrieved ocaml-compiler.5.3.0  (cached)
220  βˆ— installed ocaml-compiler.5.3.0
221  βˆ— installed ocaml-base-compiler.5.3.0
222  βˆ— installed ocaml-config.3
223  βˆ— installed ocaml.5.3.0
224  βˆ— installed base-domains.base
225  βˆ— installed base-effects.base
226  βˆ— installed base-nnp.base
227  Done.
228  : # Run eval $(opam env --switch=ocaml-book) to update the current shell environment
229  
230  As detailed in the output
231  #+name:s post switch update
232  #+begin_src shell
233    eval $(opam env --switch=ocaml-book)
234  #+end_src
235  
236  #+RESULTS: s post switch update
237  
238  Checking the installation
239  #+name: list switch
240  #+begin_src shell
241    opam switch
242  #+end_src
243  
244  #+RESULTS: list switch
245  : #  switch         compiler                                           description
246  :    cs3110-2025sp  ocaml-base-compiler.5.2.0,ocaml-options-vanilla.1  ocaml-base-compiler = 5.2.0
247  :    default        ocaml-base-compiler.5.3.0,ocaml-options-vanilla.1  ocaml >= 4.05.0
248  : β†’  ocaml-book     ocaml-base-compiler.5.3.0,ocaml-options-vanilla.1  ocaml-base-compiler = 5.3.0
249  
250  ** Packages
251  Install those:
252  ~opam install -y utop odoc ounit2 qcheck bisect_ppx menhir ocaml-lsp-server ocamlformat~
253  
254  And now calling ~utop~ from an *interactive shell* opens a REPL with
255  OCaml.
256  ** Emacs mode
257  #+name: install merlin mode
258  #+begin_src shell
259  opam install merlin user-setup
260  opam user-setup install
261  #+end_src
262  
263  This will write in the wrong config file =~/.emacs=.
264  Move all the config in =/.config/emacs/init.el=
265  Install *Tuareg* mode and *dune* from melpa.
266  * Project Creation
267  with Dune Scaffolding
268  ** Create a new project
269  #+name: dune project
270  #+begin_src shell
271    dune init project my-project
272    cd my-project
273    dune exec bin/main.exe
274  #+end_src
275  
276  This will print "Hello, World!"
277  **** Alternatively...
278  Based on the [[https://ocaml.org/docs/your-first-program][ocaml doc]] you can also
279  #+name: alt dune project
280  #+begin_src shell
281    dune init proj hello
282    cd hello
283    dune build
284    dune exec hello                 # for watch mode, dune exec hello -w
285  #+end_src
286  ** File structure
287  =lib/= and =bin/= contain source code files, for libraries and
288  programs respectively. =_build/= is generated and shouldn't been
289  manually modified. =test/= is where tests resides:
290  - bin :: executable programs
291  - lib :: libraries
292  - test :: tests
293  
294  ** Formatting
295  Dune does not install the format file.
296  In the root project, same folder as =dune-project=,
297  create the file =.ocamlformat=
298  
299  The format of the file 😎 should be like the below:
300  #+begin_src txt
301  version=0.26.1
302  profile=default
303  #+end_src
304  
305  Possible profiles are:
306  - default, or conventional
307  - ocamlformat
308  - janestreet
309  
310  The ~version~ is the version of =ocamlformat=. You can get it via the
311  command ~ocamlformat --version~.
312  
313  Based on the [[https://dune.readthedocs.io/en/stable/howto/formatting.html][doc]] Dune first makes a diff and then let's you apply a
314  promote to validate. First step is:
315  - ~dune build @fmt~ :: Format and then display the diff
316  - ~dune promote~ :: Accept the format and apply it
317  
318  To apply the formatting in one go, type ~dune fmt~, this is the
319  equivalent of ~dune build @fmt --auto-promote~. Make sure to revert or
320  auto-revert the buffers.
321  
322  See Emacs install and config [[https://ocaml.org/p/ocamlformat/latest/doc/editor_setup.html#emacs-setup][in the manual]].
323  
324  You can setup a =.ocamlformat-ignore= to list the files that shoult
325  not be formatted.
326  **** Auto format on save
327  Add this in your =.config/emacs/init.el=
328  #+name: init.el
329  #+begin_src elisp
330    (use-package ocamlformat
331      :custom (ocamlformat-enable 'enable-outside-detected-project)
332      :hook (before-save . ocamlformat-before-save)
333      )
334  #+end_src
335  ** Watch mode
336  #+name: watch mode
337  #+begin_src shell
338    dune build --watch
339    # or dune exec proj-name -w
340  #+end_src
341  ** Start a new library
342  #+begin_src shell
343    dune init lib yo ./lib
344  #+end_src
345  ** Create a new exec in the current project
346  #+begin_src shell
347    dune init exec new_bin ./bin
348  #+end_src
349  ** Create a new test in the current project
350  #+begin_src shell
351    dune init test new_test ./test
352  #+end_src
353  * Documentation
354  See [[https://cs3110.github.io/textbook/chapters/basics/documentation.html][2.5. Documentation]] *ocamldoc* can generate documentation based on
355  the comments. A good comment will be crucial. The recommended style is
356  #+begin_src ocaml
357       (** [random_int bound] is a random integer between 0 (inclusive)
358           and [bound] (exclusive).
359           Requires: [bound] is greater than 0 and less than 2^30.
360           Raises: [Invalid_argument "bound"] otherwise. *)
361    let random_int bound = ...
362  #+end_src
363  
364  #+begin_src ocaml
365    (** [index s c] is the index of the first occurrence of
366        character [c] in string [s].
367        Raises: [Not_found] if [c] does not occur in [s]. *)
368    let index s c = ...
369  #+end_src
370  
371  See [[https://ocaml.org/manual/5.2/ocamldoc.html][the manual]]
372  
373  To create the documentation, in the root folder
374  #+begin_src shell
375    cd project
376    mkdir doc
377    ocamldoc -html bin/main.ml -d doc/
378  #+end_src
379  
380  Documentation using *dune*. install *odoc* with ~opam install odoc~.
381  In the root folder do ~dune build @doc~, this will generate the
382  documentation in =_build/default/_doc/_html/index.html=
383  
384  ⚠️ Only the public facing libs will be documented. This doc is
385  generated on the fly in the =_build= folder. It will not be saved in
386  the repo.It's fine, it can be generated in the cicd.
387  
388  * Modules and their Interfaces
389  
390  ** Module
391  Each OCaml files defines a module. To create a module, you create a
392  file. Based on the default =hello= template, let's create a new file:
393  
394  #+name: en.ml
395  #+description: very short library module
396  #+begin_src ocaml :tangle lib/en.ml
397    let v = "Hello, World."
398  #+end_src
399  
400  This creates a module *En* inside the module *Hello*. To access the
401  string ~v~, you call it via ~Hello.En.v~. The ~main.ml~ file becomes
402  
403  #+name: main with module
404  #+description: how to use variables define in a different module
405  #+begin_src ocaml :tangle bin/main.ml
406    let () = Printf.printf "%s\n" Hello.En.v
407  #+end_src
408  
409  ~dune exec hello~ will display the string as defined in the module.
410  
411  ** Interface
412  An interface file list the elements of the module available to the
413  outside world.
414  #+name: en.mli
415  #+description: interface for the en.ml module
416  #+begin_src ocaml :tangle lib/en.mli
417    val v : string
418  #+end_src
419  
420  No matter what is being created in the module, only ~v~ is callable.
421  #+name: en.mli w/ hello
422  #+description: module en with a private variable
423  #+begin_src ocaml :tangle lib/en.ml
424    let hi = "Hello"
425    let v = hi ^ ", World."
426  #+end_src
427  Here ~hi~ is not visible in =main.ml=.
428  
429  #+begin_src ocaml :tangle bin/main.ml
430    let () = Printf.printf "%s\n" Hello.En.hi
431  #+end_src
432  
433  Running will cause a compilation error
434  #+begin_src bash
435    File "bin/main.ml", line 1, characters 30-41:
436    1 | let () = Printf.printf "%s\n" Hello.En.hi
437                                      ^^^^^^^^^^^
438    Error: Unbound value "Hello.En.hi"
439  #+end_src
440  
441  ** Multiple modules in one library
442  Let's add the French version in its own module.
443  #+name: fr.ml
444  #+description: module fr
445  #+begin_src ocaml :tangle lib/fr.ml
446    let v = "Bonjour tout le monde"
447  #+end_src
448  
449  #+name: main.ml with 2 modules
450  #+description: main is calling 2 modules
451  #+begin_src ocaml :tangle bin/main.ml
452    let () = Printf.printf "%s\n" Hello.En.v
453    let () = Printf.printf "%s\n" Hello.Fr.v
454  #+end_src
455  
456  To run it, first build and then execute
457  #+begin_src shell
458    dune build
459    dune exec hello
460  #+end_src
461  
462  * Ways of Working
463  ** Debugging
464  There are 3 possibilities to deal with wrong arguments being passed.
465  #+name: wrong arguments
466  #+begin_src ocaml
467    (** [random_int bound] is a random integer between 0 (inclusive)
468        and [bound] (exclusive).
469        Requires: [bound] is greater than 0 and less than 2^30. *)
470    let random_int_1 bound =
471      assert (bound > 0 && bound < 1 lsl 30);
472      1
473  
474    let random_int_2 bound =
475      if not (bound > 0 && bound < 1 lsl 30)
476      then invalid_arg "bound";
477      2
478  
479    let random_int_3 bound =
480      if not (bound > 0 && bound < 1 lsl 30)
481      then failwith "bound";
482      3
483  #+end_src
484  *** random_int_1
485  The ~assert~ is probably most useful when you're trying to debug your own code,
486  rather than choosing to expose a failed assertion to a client.
487  *** random_int_2
488  This is probably the most informative to the client, because it uses the
489  built-in function ~invalid_arg~ to raise the exception *Invalid_argument*.
490  In fact, that's exactly what the standard library implementation of this
491  function does.
492  The function definition becomes
493  #+name: random_int definition
494  #+begin_src ocaml
495    (** [random_int bound] is a random integer between 0 (inclusive)
496        and [bound] (exclusive).
497        @raise [Invalid_argument "bound"] unless [bound] is greater than 0
498        and less than 2^30. *)
499    let random_int bound =
500      if not (bound > 0 && bound < 1 lsl 30)
501      then invalid_arg "bound";
502      1
503  #+end_src
504  
505  Instead of being free to do whatever when ~bound~ is out of range, ~random_int~
506  *must* raise an exception.
507  *** random_int_3
508  Raises the exception *Failure*. It might be useful is situation where the
509  precondition involves more than just a single invalid argument.
510  ** Failures
511  There are several predefined *exceptions* in the StdLib:
512  - Exit :: can be used to terminate an iteration, like a break
513    statement
514  - Not_found :: should be raised when searching failed because there
515    isn't anything satisfactory to be found
516  - Invalid_argument :: should be raised when a parameter can't be
517    accepted
518  - Failure :: should be raised when a result can't be produced
519  
520  *** Catching Failures
521  with ~try with~:
522  
523  #+begin_src ocaml
524    try random_int (-1) with Invalid_argument _ -> do_something_else
525  #+end_src
526  
527  *** Keeping control of the workflow
528  Because handling exceptions interrupts normal control flow, using them
529  can complicate the tasks that requires a strict order. ~Fun.protect~
530  ensure some actions are *always* executed.
531  
532  #+begin_src ocaml
533    let safe_foo arg =
534      let finally () = always_bar in
535      let work () = try baz_might_fail arg with WhateverError _ -> failed_foo in
536      Fun.protect ~finally work
537  #+end_src
538  
539  *** Handling failure directly in the data
540  https://ocaml.org/docs/error-handling#using-the-option-type-for-errors