Skip to content

Commit be1be73

Browse files
authored
Merge pull request mouredev#3074 from luishendrix92/main
#17 - OCaml
2 parents deead19 + 46ac7ec commit be1be73

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
open Moure.Io
2+
3+
(*****************************************************************************)
4+
(* *)
5+
(* Iteration *)
6+
(* *)
7+
(* OCaml offers many ways to iterate through a condition or over a defined *)
8+
(* sequence of values (finite or lazily infinite) such a [List], [Array], *)
9+
(* or [Seq] ([Sequence] in {b Jane Street's [Core]}). *)
10+
(* *)
11+
(* 1. Recursion: as a functional language, the most idiomatic way of doing *)
12+
(* iteration through a recursive function (preferably TC optimized). *)
13+
(* 2. Lazy Sequences: [Seq] offers a way to declaratively define finite or *)
14+
(* infinite sequences of values that are only evaluated on-demand. *)
15+
(* 3. Lists and Arrays: Iterating over linked lists is possible through *)
16+
(* recursive functions that make use of their head and tail. Whereas *)
17+
(* iterating over arrays can be done through Stdlib functions or loops *)
18+
(* (imperative) while accessing their values by index. *)
19+
(* 4. Imperative Loops: OCaml offers [while] and [for] just like any other *)
20+
(* language; it's very useful for running imperative code (IO). *)
21+
(* *)
22+
(* Other functional languages (and Python) offere something called {e list *)
23+
(* comprehensions} which transforms a list or sequence into a new one. *)
24+
(* Sadly, OCaml doesn't offer list comprehensions but it can be achieved *)
25+
(* with [Seq] and its many transformative functions. *)
26+
(* *)
27+
(*****************************************************************************)
28+
29+
let recursive_tco a b =
30+
let rec aux i =
31+
if i <= b
32+
then begin
33+
print_int_endl i;
34+
aux (i + 1)
35+
end
36+
in
37+
print_endline "Iteration with TCO recursion:";
38+
aux a
39+
;;
40+
41+
let lazy_seq_iter a b =
42+
print_endline "Iteration with infinite lazy sequences:";
43+
Seq.(ints a |> take_while (fun n -> n <= b) |> iter print_int_endl)
44+
;;
45+
46+
let list_iter a b =
47+
let rec aux = function
48+
| hd :: tl ->
49+
print_int_endl hd;
50+
aux tl
51+
| [] -> ()
52+
in
53+
print_endline "1-10 Count with list iteration (TCO):";
54+
(* Alternative: [List.iter print_int_endl my_range]. *)
55+
aux @@ Core.List.range ~stop:`inclusive a b
56+
;;
57+
58+
let array_iter a b =
59+
let range = Core.List.range ~stop:`inclusive a b |> Array.of_list in
60+
let i = ref 0 in
61+
print_endline "1-10 Count with array iteration:";
62+
(* Alternative 1: [Array.iter print_int_endl range].
63+
Alternative 2: Get the length of the array and use [for] instead:
64+
65+
{[
66+
for i = 0 to Array.length range - 1 do
67+
print_int_endl range.(i)
68+
done
69+
]}
70+
*)
71+
try
72+
while true do
73+
print_int_endl range.(!i);
74+
incr i
75+
done
76+
with
77+
| Invalid_argument _ -> ()
78+
;;
79+
80+
let for_loop_iter a b =
81+
print_endline "Iteration with a bound for-loop:";
82+
for i = a to b do
83+
print_int_endl i
84+
done
85+
;;
86+
87+
(** [dispenser] is a funny function that I thought of after remembering
88+
ES6 Javascript generators, which return values by requesting them with
89+
the [.next()] method and the [yield] keyword.
90+
91+
While OCaml doesn't offer something directly similar, it can be achieved
92+
with mutable lazy sequences or lists, or a mutable data structure.
93+
[dispenser n] returns a runnable function that returns [n+1] every time
94+
it's called (starting with [n] itself). *)
95+
let dispenser n =
96+
let i : int ref = ref (n - 1) in
97+
let dispense () =
98+
incr i;
99+
!i
100+
in
101+
dispense
102+
;;
103+
104+
(* In recent versions of Ocaml that provide OOP syntax for classes, we can
105+
achieve the same effect with an object or a class:
106+
107+
{[
108+
class countup (start : int) =
109+
object (self)
110+
val mutable i = start - 1
111+
method private inc = i <- i + 1
112+
113+
method next =
114+
self#inc;
115+
i
116+
end
117+
;;
118+
119+
let counter = new countup 1 in
120+
for i = 0 to 9 do
121+
print_int_endl counter#next
122+
done
123+
]}
124+
*)
125+
126+
let _ =
127+
recursive_tco 1 10;
128+
print_newline ();
129+
lazy_seq_iter 1 10;
130+
print_newline ();
131+
list_iter 1 10;
132+
print_newline ();
133+
array_iter 1 10;
134+
print_newline ();
135+
for_loop_iter 1 10;
136+
print_newline ();
137+
let dispense = dispenser 1 in
138+
print_endline "1-10 Count with a closure function:";
139+
for i = 0 to 9 do
140+
print_int_endl @@ dispense ()
141+
done
142+
;;
143+
144+
(* Total: 6 Ways of Iterating from 1 to 10. Could be more, but there is no
145+
point anyway. I already covered the most important ones. *)

0 commit comments

Comments
 (0)