|
| 1 | +--- |
| 2 | +id: Sequences |
| 3 | +title: Sequences |
| 4 | +description: > |
| 5 | + Learn about one of OCaml's must used, built-in data types |
| 6 | +category: "data-structures" |
| 7 | +date: 2023-01-12T09:00:00-01:00 |
| 8 | +--- |
| 9 | + |
| 10 | +# Sequences |
| 11 | + |
| 12 | +A sequence looks a lot like a list. However from a pragmatic perspective, one |
| 13 | +should imagine it may be infinite. One way to look at a value of type `'a Seq.t` |
| 14 | +is to consider it as an icicle, a frozen stream of data. To understand this |
| 15 | +analogy, consider how sequences are defined in the standard libary: |
| 16 | +```ocaml |
| 17 | +type 'a node = |
| 18 | + | Nil |
| 19 | + | Cons of 'a * 'a t |
| 20 | +and 'a t = unit -> 'a node |
| 21 | +``` |
| 22 | +This is the mutually recursive definition of two types; `Seq.node` which is almost |
| 23 | +the same as `list`: |
| 24 | +```ocaml |
| 25 | +type 'a list = |
| 26 | + | [] |
| 27 | + | (::) of 'a * 'a list |
| 28 | +``` |
| 29 | +and `Seq.t` which is merely a type alias for `unit -> 'a Seq.node`. The whole |
| 30 | +point of this definition is the type of second argument of `Seq.Cons`, in `list` |
| 31 | +it is a list while in `Seq.t` it is function. Empty lists and empty sequence are |
| 32 | +defined the same way (`Seq.Nil` and `[]`). Non-empty lists are non-empty |
| 33 | +sequences values are both pairs those former member is a piece of data. But non |
| 34 | +empty sequence values have a sequence returning function as latter member |
| 35 | +instead of a list. That function is the frozen part of the sequence. When a |
| 36 | +non-empty sequence is processed, access to data at the tip of the sequence is |
| 37 | +immediate, but access to the rest of the sequence is deferred. To access the |
| 38 | +tail of non-empty sequence, it has to be microwaved, that is, the tail returning |
| 39 | +function must be passed a `unit` value. |
| 40 | + |
| 41 | +Having frozen-by-function tails explains why sequences should be considered |
| 42 | +potentially infinite. Unless a `Seq.Nil` has been found in the sequence, one |
| 43 | +can't say for sure if some will ever appear. The tail could be a stream of |
| 44 | +client requests in a server, readings from an embedded sensor or logs. All have |
| 45 | +unforseenable termination and should be considered infinite. |
| 46 | + |
| 47 | +Here is how to build seemingly infinite sequences of integers. |
| 48 | +```ocaml |
| 49 | +# let rec ints_from n : int Seq.t = fun () -> Seq.Cons (n, ints_from (n + 1));; |
| 50 | +val ints_from : int -> int Seq.t = <fun> |
| 51 | +# let ints = ints_from 0;; |
| 52 | +val ints : ints Seq.t = <fun> |
| 53 | +``` |
| 54 | +The function `ints_from n` looks as if building the infinite sequence $(n; n + |
| 55 | +1; n + 2; n + 3;...)$ while the value `ints` looks as if representing the |
| 56 | +infinite sequence $(0; 1; 2; 3; ...)$. In reality, since there isn't an infinite |
| 57 | +amount of distinct values of type `int`, those sequences are not increasing, |
| 58 | +when reaching `max_int` the values will circle down to `min_int`, actually they |
| 59 | +are ultimately periodic. |
| 60 | + |
| 61 | +The OCaml standard library contains a module on sequences called `Seq`. It contains an `Seq.iter` function, which has the same behaviour as `List.iter`. Writting this |
| 62 | +```ocaml |
| 63 | +# Seq.iter print_int ints;; |
| 64 | +``` |
| 65 | +in an OCaml toplevel actually means: “print integers forever” and you have to |
| 66 | +type `Crtl-C` to interrupt the execution. Perhaps more interestingly, the |
| 67 | +following code is an infinite loop: |
| 68 | +```ocaml |
| 69 | +# Seq.iter ignore ints;; |
| 70 | +``` |
| 71 | +But the key point is: it doesn't leak memory. |
0 commit comments