From 6bce4fbb86836ea095eb987598697b4400e12a16 Mon Sep 17 00:00:00 2001 From: Cuihtlauac ALVARADO Date: Wed, 29 Nov 2023 10:38:18 +0100 Subject: [PATCH] Include some feedback from @silene See discuss thread: https://discuss.ocaml.org/t/draft-tutorial-on-mutability-loops-and-imperative-programming/13504/2 Only easy items, more to come --- data/tutorials/language/0it_06_imperative.md | 37 ++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/data/tutorials/language/0it_06_imperative.md b/data/tutorials/language/0it_06_imperative.md index 8ffe547ad1..879ab1577a 100644 --- a/data/tutorials/language/0it_06_imperative.md +++ b/data/tutorials/language/0it_06_imperative.md @@ -154,12 +154,21 @@ The type `'a ref` is a record with a single field `contents` which is marked wit Since references are single field records, we can define functions `assign` and `deref` using the mutable record field update syntax: ```ocaml -# let assign a x = a.contents <- x;; +# let create v = { contents = v };; +val create : 'a -> 'a ref = + +# let assign a v = a.contents <- v;; val assign : 'a ref -> 'a -> unit = # let deref a = a.contents;; val deref : 'a ref -> 'a = +# let a = create 0;; +val a : int ref = {contents = 0} + +# deref a;; +- : int = 0 + # assign a 2;; - : unit = () @@ -167,8 +176,10 @@ val deref : 'a ref -> 'a = - : int = 2 ``` -The function `assign` does the same as the operator `( := )`, while the function `deref` does the same as the `( ! )` operator. - +The functions: +* `create` does the same as the `ref` function provided by the standard library +* `assign` does the same as the `( := )` operator +* `deref` does the same as the `( ! )` operator. ## Arrays @@ -218,6 +229,8 @@ You can think of byte sequences as either: * updatable strings that can't be printed, or * `char` arrays without syntactic sugar for indexed read and update. +**Note**: the `bytes` type uses a much more compact memory representation than `char array`. As of writing this tutorial, there is a factor 8 between `bytes` and `char array`. The former should always be preferred, except when `array` is required by polymorphic functions handling arrays. + ## Example: `get_char` Function @@ -282,6 +295,19 @@ OCaml provides a sequence operator `;` that allows chaining expressions, as well ### Sequence Operator +**`let … in`** + +```ocaml +# let () = print_string "This is" in print_endline " really Disco!";; +This is really Disco! +- : unit = () +``` + +Using the `let … in` construct means two things: +* Names may be bound (in the example, no name is bound since the ) +* Side effects take place in sequence, bound expression (here `print_string "This is"`) is evaluated first, and referring expression (here `print_endline " really Disco!"`) is evaluated second. + +**Semicolon** The single semicolon `;` operator is known as the _sequence_ operator. It allows you to evaluate multiple expressions in order, with the value of the last expression being the value of the entire sequence. The values of any previous expressions are discarded. Thus, it makes sense to use expressions with side effects, except for the last expression of the sequence which could be free of side effects. @@ -467,11 +493,8 @@ This is a possible way to handle application-wide state. As in the [Function-Enc Let's imagine you store angles as fractions of the circle in 8-bit unsigned integers, storing them as `char` values. In this system, 64 is 90 degrees, 128 is 180 degrees, 192 is 270 degrees, 256 is full circle and so on. If you need to compute cosine on those values, an implementation might look like this: ```ocaml -# let pi = 3.14159265358979312 /. 128.0;; -pi : float = 0.0245436926061702587 - # let char_cos c = - c |> int_of_char |> float_of_int |> ( *. ) (pi /. 128.0) |> cos;; + c |> int_of_char |> float_of_int |> ( *. ) (Float.pi /. 128.0) |> cos;; val char_cos : char -> float = ```