From a899e260f7b3b7104e65418d5b9c6d8bf28f2b50 Mon Sep 17 00:00:00 2001 From: PoorlyDefinedBehaviour Date: Thu, 18 Jan 2024 00:41:57 -0300 Subject: [PATCH 01/14] (feat) add prerequisites_tutorials capability --- .../language/0it_01_basic_datatypes.md | 5 +++++ data/tutorials/language/0it_04_labels.md | 6 ++++-- src/ocamlorg_data/data.mli | 4 +++- src/ocamlorg_frontend/pages/tutorial.eml | 17 +++++++++++++++++ src/ocamlorg_web/lib/handler.ml | 11 ++++++++++- tool/ood-gen/lib/tutorial.ml | 11 +++++++++-- 6 files changed, 48 insertions(+), 6 deletions(-) diff --git a/data/tutorials/language/0it_01_basic_datatypes.md b/data/tutorials/language/0it_01_basic_datatypes.md index 972ca751b0..e252a2d581 100644 --- a/data/tutorials/language/0it_01_basic_datatypes.md +++ b/data/tutorials/language/0it_01_basic_datatypes.md @@ -5,6 +5,11 @@ short_title: Basic Data Types and Pattern Matching description: | Predefined Types, Variants, Records, and Pattern Matching category: "Introduction" +prerequisites_tutorials: + [ + "tour-of-ocaml", + "values-and-functions", + ] --- ## Introduction diff --git a/data/tutorials/language/0it_04_labels.md b/data/tutorials/language/0it_04_labels.md index 682988de5a..52f43d5a88 100644 --- a/data/tutorials/language/0it_04_labels.md +++ b/data/tutorials/language/0it_04_labels.md @@ -5,14 +5,16 @@ short_title: Labelled and Optional Arguments description: > Provide labels to your functions arguments category: "Introduction" +prerequisites_tutorials: + [ + "values-and-functions" + ] --- It is possible to give names and default values to function parameters. This is broadly known as labels. In this tutorial, we learn how to use labels. Throughout this tutorial, the code is written in UTop. In this document parameters that are not labelled are called _positional parameters_. -**Prerequisites**: [Values and Functions](/docs/values-and-functions) - ## Passing Labelled Arguments The function `Option.value` from the standard library has a parameter labelled `default`. diff --git a/src/ocamlorg_data/data.mli b/src/ocamlorg_data/data.mli index 70b9bbb117..e3c7f1ccd0 100644 --- a/src/ocamlorg_data/data.mli +++ b/src/ocamlorg_data/data.mli @@ -216,6 +216,7 @@ module Tutorial : sig } type recommended_next_tutorials = string list + type prerequisite_tutorials = string list type t = { title : string; @@ -229,7 +230,8 @@ module Tutorial : sig body_md : string; toc : toc list; body_html : string; - recommended_next_tutorials : recommended_next_tutorials; + recommended_next_tutorials : recommended_next_tutorials option; + prerequisite_tutorials : prerequisite_tutorials option; } val all : t list diff --git a/src/ocamlorg_frontend/pages/tutorial.eml b/src/ocamlorg_frontend/pages/tutorial.eml index d8c4cf2bd8..6a6e9ea954 100644 --- a/src/ocamlorg_frontend/pages/tutorial.eml +++ b/src/ocamlorg_frontend/pages/tutorial.eml @@ -40,11 +40,27 @@ let render_related_exercises exercises = else "" +let render_prerequisites_tutorials tutorials = + if List.length tutorials > 0 then +
+

Prerequisites

+ +
+ else + "" + let render (tutorial : Data.Tutorial.t) ~tutorials ~related_exercises ~recommended_next_tutorials +~prerequisites_tutorials ~canonical = let href, description = match tutorial.external_tutorial with @@ -71,6 +87,7 @@ Learn_layout.three_column_layout ~right_sidebar_html:(Some(right_sidebar tutorial)) ~current:(of_tutorial_section tutorial.section) @@
+ <%s! render_prerequisites_tutorials prerequisites_tutorials %> <%s! render_external_tutorial_banner tutorial.external_tutorial %> <%s! render_title tutorial %> <%s! tutorial.body_html %> diff --git a/src/ocamlorg_web/lib/handler.ml b/src/ocamlorg_web/lib/handler.ml index fb2481b831..2b18bae033 100644 --- a/src/ocamlorg_web/lib/handler.ml +++ b/src/ocamlorg_web/lib/handler.ml @@ -408,10 +408,19 @@ let tutorial req = all_tutorials |> List.filter is_in_recommended_next in + let is_prerequisite (tested : Data.Tutorial.t) = + List.exists + (fun r -> r = tested.slug) + (Option.value tutorial.prerequisites_tutorials ~default:[]) + in + + let prerequisites_tutorials = all_tutorials |> List.filter is_prerequisite in + Dream.html (Ocamlorg_frontend.tutorial ~tutorials ~canonical:(Url.tutorial tutorial.slug) - ~related_exercises ~recommended_next_tutorials tutorial) + ~related_exercises ~recommended_next_tutorials ~prerequisites_tutorials + tutorial) let exercises req = let all_exercises = Data.Exercise.all in diff --git a/tool/ood-gen/lib/tutorial.ml b/tool/ood-gen/lib/tutorial.ml index b24935bf57..b1e1b1fb99 100644 --- a/tool/ood-gen/lib/tutorial.ml +++ b/tool/ood-gen/lib/tutorial.ml @@ -29,6 +29,9 @@ type external_tutorial = { type recommended_next_tutorials = string list [@@deriving of_yaml, show { with_path = false }] +type prerequisite_tutorials = string list +[@@deriving of_yaml, show { with_path = false }] + type metadata = { id : string; title : string; @@ -37,6 +40,7 @@ type metadata = { category : string; external_tutorial : external_tutorial option; recommended_next_tutorials : recommended_next_tutorials option; + prerequisite_tutorials : prerequisite_tutorials option; } [@@deriving of_yaml] @@ -52,7 +56,8 @@ type t = { toc : toc list; body_md : string; body_html : string; - recommended_next_tutorials : recommended_next_tutorials; + recommended_next_tutorials : recommended_next_tutorials option; + prerequisite_tutorials : prerequisite_tutorials option; } [@@deriving stable_record ~version:metadata ~add:[ id ] @@ -184,6 +189,7 @@ type external_tutorial = ; contribute_link : contribute_link } type recommended_next_tutorials = string list +type prerequisite_tutorials = string list type t = { title : string ; short_title: string @@ -196,7 +202,8 @@ type t = ; body_md : string ; toc : toc list ; body_html : string - ; recommended_next_tutorials : recommended_next_tutorials + ; recommended_next_tutorials : recommended_next_tutorials option + ; prerequisite_tutorials : prerequisite_tutorials option } let all = %a From 810d8a55ff6b0875b466b43a63b5ebd6bec3b928 Mon Sep 17 00:00:00 2001 From: Bruno Date: Fri, 19 Jan 2024 00:28:51 -0300 Subject: [PATCH 02/14] Update data/tutorials/language/0it_01_basic_datatypes.md Co-authored-by: Cuihtlauac Alvarado --- data/tutorials/language/0it_01_basic_datatypes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/tutorials/language/0it_01_basic_datatypes.md b/data/tutorials/language/0it_01_basic_datatypes.md index e252a2d581..6e0fa51c1f 100644 --- a/data/tutorials/language/0it_01_basic_datatypes.md +++ b/data/tutorials/language/0it_01_basic_datatypes.md @@ -5,7 +5,7 @@ short_title: Basic Data Types and Pattern Matching description: | Predefined Types, Variants, Records, and Pattern Matching category: "Introduction" -prerequisites_tutorials: +prerequisite_tutorials: [ "tour-of-ocaml", "values-and-functions", From a91d52bb43e5e7ef0da1e817740599b506745f44 Mon Sep 17 00:00:00 2001 From: Bruno Date: Fri, 19 Jan 2024 00:28:58 -0300 Subject: [PATCH 03/14] Update data/tutorials/language/0it_04_labels.md Co-authored-by: Cuihtlauac Alvarado --- data/tutorials/language/0it_04_labels.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/tutorials/language/0it_04_labels.md b/data/tutorials/language/0it_04_labels.md index 52f43d5a88..fe766bf8be 100644 --- a/data/tutorials/language/0it_04_labels.md +++ b/data/tutorials/language/0it_04_labels.md @@ -5,7 +5,7 @@ short_title: Labelled and Optional Arguments description: > Provide labels to your functions arguments category: "Introduction" -prerequisites_tutorials: +prerequisite_tutorials: [ "values-and-functions" ] From 2bfdfbe43fd501b5210356ec7100c96446188bcb Mon Sep 17 00:00:00 2001 From: Bruno Date: Fri, 19 Jan 2024 00:29:32 -0300 Subject: [PATCH 04/14] Update src/ocamlorg_frontend/pages/tutorial.eml Co-authored-by: Cuihtlauac Alvarado --- src/ocamlorg_frontend/pages/tutorial.eml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ocamlorg_frontend/pages/tutorial.eml b/src/ocamlorg_frontend/pages/tutorial.eml index 6a6e9ea954..930f62275c 100644 --- a/src/ocamlorg_frontend/pages/tutorial.eml +++ b/src/ocamlorg_frontend/pages/tutorial.eml @@ -40,7 +40,7 @@ let render_related_exercises exercises = else "" -let render_prerequisites_tutorials tutorials = +let render_prerequisite_tutorials tutorials = if List.length tutorials > 0 then

Prerequisites

From d852b73d1280d7fca24cdd0b52e8d9838c2b3a9f Mon Sep 17 00:00:00 2001 From: Bruno Date: Fri, 19 Jan 2024 00:29:53 -0300 Subject: [PATCH 05/14] Update src/ocamlorg_web/lib/handler.ml Co-authored-by: Cuihtlauac Alvarado --- src/ocamlorg_web/lib/handler.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ocamlorg_web/lib/handler.ml b/src/ocamlorg_web/lib/handler.ml index 2b18bae033..b7a2b26b1b 100644 --- a/src/ocamlorg_web/lib/handler.ml +++ b/src/ocamlorg_web/lib/handler.ml @@ -411,7 +411,7 @@ let tutorial req = let is_prerequisite (tested : Data.Tutorial.t) = List.exists (fun r -> r = tested.slug) - (Option.value tutorial.prerequisites_tutorials ~default:[]) + (Option.value tutorial.prerequisite_tutorials ~default:[]) in let prerequisites_tutorials = all_tutorials |> List.filter is_prerequisite in From 3ec8a7ed75b7f77296d2bcf7ecd04ba4c3db5522 Mon Sep 17 00:00:00 2001 From: Bruno Date: Fri, 19 Jan 2024 00:30:00 -0300 Subject: [PATCH 06/14] Update src/ocamlorg_web/lib/handler.ml Co-authored-by: Cuihtlauac Alvarado --- src/ocamlorg_web/lib/handler.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ocamlorg_web/lib/handler.ml b/src/ocamlorg_web/lib/handler.ml index b7a2b26b1b..7be504ba42 100644 --- a/src/ocamlorg_web/lib/handler.ml +++ b/src/ocamlorg_web/lib/handler.ml @@ -419,7 +419,7 @@ let tutorial req = Dream.html (Ocamlorg_frontend.tutorial ~tutorials ~canonical:(Url.tutorial tutorial.slug) - ~related_exercises ~recommended_next_tutorials ~prerequisites_tutorials + ~related_exercises ~recommended_next_tutorials ~prerequisite_tutorials tutorial) let exercises req = From c6b0d39ce9fdcb97cbfe416a760a8a3fc44c9302 Mon Sep 17 00:00:00 2001 From: PoorlyDefinedBehaviour Date: Fri, 19 Jan 2024 00:38:59 -0300 Subject: [PATCH 07/14] fix typos --- src/ocamlorg_frontend/pages/tutorial.eml | 4 ++-- src/ocamlorg_web/lib/handler.ml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ocamlorg_frontend/pages/tutorial.eml b/src/ocamlorg_frontend/pages/tutorial.eml index 930f62275c..426b9c18c8 100644 --- a/src/ocamlorg_frontend/pages/tutorial.eml +++ b/src/ocamlorg_frontend/pages/tutorial.eml @@ -60,7 +60,7 @@ let render ~tutorials ~related_exercises ~recommended_next_tutorials -~prerequisites_tutorials +~prerequisite_tutorials ~canonical = let href, description = match tutorial.external_tutorial with @@ -87,7 +87,7 @@ Learn_layout.three_column_layout ~right_sidebar_html:(Some(right_sidebar tutorial)) ~current:(of_tutorial_section tutorial.section) @@
- <%s! render_prerequisites_tutorials prerequisites_tutorials %> + <%s! render_prerequisite_tutorials prerequisite_tutorials %> <%s! render_external_tutorial_banner tutorial.external_tutorial %> <%s! render_title tutorial %> <%s! tutorial.body_html %> diff --git a/src/ocamlorg_web/lib/handler.ml b/src/ocamlorg_web/lib/handler.ml index 7be504ba42..eae2e9bd49 100644 --- a/src/ocamlorg_web/lib/handler.ml +++ b/src/ocamlorg_web/lib/handler.ml @@ -414,7 +414,7 @@ let tutorial req = (Option.value tutorial.prerequisite_tutorials ~default:[]) in - let prerequisites_tutorials = all_tutorials |> List.filter is_prerequisite in + let prerequisite_tutorials = all_tutorials |> List.filter is_prerequisite in Dream.html (Ocamlorg_frontend.tutorial ~tutorials From 9fa3942dc7f96ede360470bbb658f5a80786dc67 Mon Sep 17 00:00:00 2001 From: PoorlyDefinedBehaviour Date: Fri, 19 Jan 2024 00:41:45 -0300 Subject: [PATCH 08/14] fix merge conflict --- tool/ood-gen/lib/tutorial.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/ood-gen/lib/tutorial.ml b/tool/ood-gen/lib/tutorial.ml index b1e1b1fb99..5289eab1e6 100644 --- a/tool/ood-gen/lib/tutorial.ml +++ b/tool/ood-gen/lib/tutorial.ml @@ -56,7 +56,7 @@ type t = { toc : toc list; body_md : string; body_html : string; - recommended_next_tutorials : recommended_next_tutorials option; + recommended_next_tutorials : recommended_next_tutorials; prerequisite_tutorials : prerequisite_tutorials option; } [@@deriving From 44ec2ae27da7e58e93634f94707bfd8ead943311 Mon Sep 17 00:00:00 2001 From: PoorlyDefinedBehaviour Date: Fri, 19 Jan 2024 00:46:41 -0300 Subject: [PATCH 09/14] make prerequisite_tutorials a string list instead of string list option --- src/ocamlorg_data/data.mli | 4 ++-- src/ocamlorg_web/lib/handler.ml | 4 +--- tool/ood-gen/lib/tutorial.ml | 14 +++++++------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/ocamlorg_data/data.mli b/src/ocamlorg_data/data.mli index e3c7f1ccd0..505fc03d71 100644 --- a/src/ocamlorg_data/data.mli +++ b/src/ocamlorg_data/data.mli @@ -230,8 +230,8 @@ module Tutorial : sig body_md : string; toc : toc list; body_html : string; - recommended_next_tutorials : recommended_next_tutorials option; - prerequisite_tutorials : prerequisite_tutorials option; + recommended_next_tutorials : recommended_next_tutorials; + prerequisite_tutorials : prerequisite_tutorials; } val all : t list diff --git a/src/ocamlorg_web/lib/handler.ml b/src/ocamlorg_web/lib/handler.ml index eae2e9bd49..fbbc0637e6 100644 --- a/src/ocamlorg_web/lib/handler.ml +++ b/src/ocamlorg_web/lib/handler.ml @@ -409,9 +409,7 @@ let tutorial req = in let is_prerequisite (tested : Data.Tutorial.t) = - List.exists - (fun r -> r = tested.slug) - (Option.value tutorial.prerequisite_tutorials ~default:[]) + List.exists (fun r -> r = tested.slug) tutorial.prerequisite_tutorials in let prerequisite_tutorials = all_tutorials |> List.filter is_prerequisite in diff --git a/tool/ood-gen/lib/tutorial.ml b/tool/ood-gen/lib/tutorial.ml index 5289eab1e6..6278f9fbc7 100644 --- a/tool/ood-gen/lib/tutorial.ml +++ b/tool/ood-gen/lib/tutorial.ml @@ -57,18 +57,18 @@ type t = { body_md : string; body_html : string; recommended_next_tutorials : recommended_next_tutorials; - prerequisite_tutorials : prerequisite_tutorials option; + prerequisite_tutorials : prerequisite_tutorials; } [@@deriving stable_record ~version:metadata ~add:[ id ] - ~modify:[ recommended_next_tutorials ] + ~modify:[ recommended_next_tutorials; prerequisite_tutorials ] ~remove:[ slug; fpath; section; toc; body_md; body_html ], show { with_path = false }] let of_metadata m = - of_metadata m ~slug:m.id ~modify_recommended_next_tutorials:(function - | None -> [] - | Some u -> u) + of_metadata m ~slug:m.id + ~modify_recommended_next_tutorials:(function None -> [] | Some u -> u) + ~modify_prerequisite_tutorials:(function None -> [] | Some u -> u) let id_to_href id = match id with @@ -202,8 +202,8 @@ type t = ; body_md : string ; toc : toc list ; body_html : string - ; recommended_next_tutorials : recommended_next_tutorials option - ; prerequisite_tutorials : prerequisite_tutorials option + ; recommended_next_tutorials : recommended_next_tutorials + ; prerequisite_tutorials : prerequisite_tutorials } let all = %a From 33335542832ebff2f1567d6ea8d508bed6523dec Mon Sep 17 00:00:00 2001 From: PoorlyDefinedBehaviour Date: Mon, 29 Jan 2024 22:57:10 -0300 Subject: [PATCH 10/14] render prerequisite tutorials after title --- src/ocamlorg_frontend/pages/tutorial.eml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ocamlorg_frontend/pages/tutorial.eml b/src/ocamlorg_frontend/pages/tutorial.eml index 426b9c18c8..03eddf0d9e 100644 --- a/src/ocamlorg_frontend/pages/tutorial.eml +++ b/src/ocamlorg_frontend/pages/tutorial.eml @@ -43,7 +43,7 @@ let render_related_exercises exercises = let render_prerequisite_tutorials tutorials = if List.length tutorials > 0 then
-

Prerequisites

+

Prerequisites

    <% tutorials |> List.iter (fun (tutorial : Data.Tutorial.t) -> %>
  • @@ -87,9 +87,9 @@ Learn_layout.three_column_layout ~right_sidebar_html:(Some(right_sidebar tutorial)) ~current:(of_tutorial_section tutorial.section) @@
    - <%s! render_prerequisite_tutorials prerequisite_tutorials %> <%s! render_external_tutorial_banner tutorial.external_tutorial %> <%s! render_title tutorial %> + <%s! render_prerequisite_tutorials prerequisite_tutorials %> <%s! tutorial.body_html %> <%s! render_related_exercises related_exercises %> <%s! Learn_components.contribute_footer ~href ~description ~recommended_next_tutorials %> From ba9e9f268d965320bc9eafc4dcfc897d0174ede6 Mon Sep 17 00:00:00 2001 From: Bruno Date: Tue, 30 Jan 2024 22:18:13 -0300 Subject: [PATCH 11/14] Update data/tutorials/language/0it_04_labels.md Co-authored-by: Cuihtlauac Alvarado --- data/tutorials/language/0it_04_labels.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/data/tutorials/language/0it_04_labels.md b/data/tutorials/language/0it_04_labels.md index fe766bf8be..a7320babd9 100644 --- a/data/tutorials/language/0it_04_labels.md +++ b/data/tutorials/language/0it_04_labels.md @@ -5,10 +5,8 @@ short_title: Labelled and Optional Arguments description: > Provide labels to your functions arguments category: "Introduction" -prerequisite_tutorials: - [ - "values-and-functions" - ] +prerequisite_tutorials: + - "values-and-functions" --- It is possible to give names and default values to function parameters. This is broadly known as labels. In this tutorial, we learn how to use labels. From 3daef2c94b95284fea21760931c801b31225903d Mon Sep 17 00:00:00 2001 From: Bruno Date: Tue, 30 Jan 2024 22:18:30 -0300 Subject: [PATCH 12/14] Update data/tutorials/language/0it_01_basic_datatypes.md Co-authored-by: Cuihtlauac Alvarado --- data/tutorials/language/0it_01_basic_datatypes.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/data/tutorials/language/0it_01_basic_datatypes.md b/data/tutorials/language/0it_01_basic_datatypes.md index 6e0fa51c1f..075747237b 100644 --- a/data/tutorials/language/0it_01_basic_datatypes.md +++ b/data/tutorials/language/0it_01_basic_datatypes.md @@ -6,10 +6,8 @@ description: | Predefined Types, Variants, Records, and Pattern Matching category: "Introduction" prerequisite_tutorials: - [ - "tour-of-ocaml", - "values-and-functions", - ] + - tour-of-ocaml" + - "values-and-functions" --- ## Introduction From 346d5457a013c3068e9a8a06bbded214d8417f55 Mon Sep 17 00:00:00 2001 From: PoorlyDefinedBehaviour Date: Tue, 30 Jan 2024 22:29:26 -0300 Subject: [PATCH 13/14] use prerequisite_tutorials metadata in the tutorials --- data/tutorials/language/0it_00_values_functions.md | 7 +++---- data/tutorials/language/0it_01_basic_datatypes.md | 2 +- data/tutorials/language/0it_05_imperative.md | 7 +++++-- data/tutorials/language/3ds_05_seq.md | 7 +++---- data/tutorials/language/5rt_00_memory_representation.md | 4 ++-- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/data/tutorials/language/0it_00_values_functions.md b/data/tutorials/language/0it_00_values_functions.md index 29483eb8ce..08b57e12b7 100644 --- a/data/tutorials/language/0it_00_values_functions.md +++ b/data/tutorials/language/0it_00_values_functions.md @@ -5,6 +5,9 @@ short_title: Values and Functions description: | Functions, values, definitions, environments, scopes, closures, and shadowing. This tutorial will help you master the fundamentals. category: "Introduction" +prerequisite_tutorials: + - "toplevel-introduction" + - "installing-ocaml" --- ## Introduction @@ -13,10 +16,6 @@ In OCaml, functions are treated as values, so you can use functions as arguments We use UTop to understand these concepts by example. You are encouraged to modify the examples to gain a better understanding. -**Prerequisites**: -- The [Introduction to the OCaml Toplevel](https://ocaml.org/docs/toplevel-introduction) guide covers how to use UTop. -- Ensure you have completed the [Get Started](https://ocaml.org/docs/installing-ocaml) series before proceeding with this tutorial. - ## What is a Value? Like most functional programming languages, OCaml is an [expression-oriented](https://en.wikipedia.org/wiki/Expression-oriented_programming_language) programming language. That means programs are expressions. Actually, almost everything is an expression. In OCaml, statements don't specify actions to be taken on data. All computations are made through expression evaluation. Computing expressions produce values. Below, you'll find a few examples of expressions, their types, and the resulting values. Some include computation and some do not: diff --git a/data/tutorials/language/0it_01_basic_datatypes.md b/data/tutorials/language/0it_01_basic_datatypes.md index 075747237b..9d5cf3fd73 100644 --- a/data/tutorials/language/0it_01_basic_datatypes.md +++ b/data/tutorials/language/0it_01_basic_datatypes.md @@ -18,7 +18,7 @@ In OCaml, there are no type checks at runtime, and values don't change type unle -**Prerequisites**: Before proceeding, it's necessary to have completed the [Get Started](https://ocaml.org/docs/get-started) series of tutorials as well as [Functions and Values](/docs/values-and-functions). As in previous tutorials, expressions after `#` and ending with `;;` are for the toplevel, like UTop. +**Note**: As in previous tutorials, expressions after `#` and ending with `;;` are for the toplevel, like UTop. - **Note**: As in previous tutorials, expressions after `#` and ending with `;;` are for the toplevel, like UTop.