Skip to content

Commit 5390c93

Browse files
committed
reto24
1 parent 3b32781 commit 5390c93

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
open Printf
2+
3+
(******************************************************************************)
4+
(* *)
5+
(* Decorators *)
6+
(* *)
7+
(* A {b decorator} is, in essence, a function that wraps another function *)
8+
(* in order to grant it additional behaviour without modifying the original *)
9+
(* code, oftentimes even preserving the function's signature where the only *)
10+
(* noticeable change is a side-effect that doesn't alter the return type. *)
11+
(* The most popular language that uses this technique is Python, which has *)
12+
(* dedicated syntax for decorators ({[ @decorator_name(arguments...) ]}), *)
13+
(* however, this pattern can be applied by any language that can return *)
14+
(* functions (Higher Order Functions). *)
15+
(* *)
16+
(* In OCaml this is easy to achieve, and there are already some functions *)
17+
(* in the standard library that can be considered "decorators", one example *)
18+
(* is [Fun.protect] which accepts a (potentially failing) function and a *)
19+
(* function that frees the used resources in case the function fails. *)
20+
(* *)
21+
(* Another potential use case of decorators is to introduce new code into *)
22+
(* the project based on existing code that has been "annotated" with *)
23+
(* decorators. Java annotations are a good example of this practise and we *)
24+
(* can achieve a similar behaviour using custom pre-processors (PPX). It is *)
25+
(* fairly complex but a simple demonstration wouldn't hurt. *)
26+
(* *)
27+
(******************************************************************************)
28+
29+
module Decorators : sig
30+
val tap : f:('a -> unit) -> ('a -> 'b) -> 'a -> 'b
31+
(** [tap ~f g x] runs the consumer function [f] with [x] as argument
32+
before returning whatever it is that [g x] returned. *)
33+
34+
val timed : (unit -> 'a) -> 'a
35+
(** [timed f] measures the execution time of [f ()] and prints it to the
36+
console (in seconds) while also returning the value it produced. *)
37+
38+
val counted : ('a -> 'b) -> 'a -> 'b
39+
(** [counted f x] returns the result of invoking [f] with argument [x] after
40+
printing the amount of times it's been invoked with any argument.
41+
42+
{b NOTE}: In order for this to work, you need to partially apply
43+
[counted] with a function [f] and then keep running the same partially
44+
applied function; otherwise the closure counter will be lost. *)
45+
end = struct
46+
let tap ~f g x =
47+
f x;
48+
g x
49+
;;
50+
51+
let timed f =
52+
let start_time = Sys.time () in
53+
let result = f () in
54+
let end_time = Sys.time () in
55+
printf "Execution time in seconds: %f\n" @@ (end_time -. start_time);
56+
result
57+
;;
58+
59+
let counted f =
60+
let i : int ref = ref 0 in
61+
fun x ->
62+
incr i;
63+
printf "Function has been invoked [%d] times!\n" !i;
64+
f x
65+
;;
66+
end
67+
68+
let rec fib = function
69+
| 0 -> 0
70+
| 1 -> 1
71+
| n -> fib (n - 1) + fib (n - 2)
72+
;;
73+
74+
let _ =
75+
let open Decorators in
76+
print_endline "Decorator [tap] example:";
77+
[ 1; 2; 3; 4; 5 ]
78+
|> List.map (tap ~f:(printf "[succ] input: %d\n") succ)
79+
|> List.iter (printf "After increment: %d\n");
80+
print_endline "Decorator [timed] example (performance measure):";
81+
printf "fib n=45 is equal to: %d\n" @@ timed (fun () -> fib 45);
82+
print_endline "Decorator [counted] example:";
83+
(******************************************************************)
84+
(* *)
85+
(* Dificultad Extra (Opcional) *)
86+
(* *)
87+
(* Crear un decorador que sea acpaz de contabilizar cuántas *)
88+
(* veces se ha llamado a una función y aplícalo a una función *)
89+
(* de tu elección. *)
90+
(* *)
91+
(******************************************************************)
92+
let run_me () = print_endline "I keep running" in
93+
let run_me = counted run_me in
94+
for i = 1 to 5 do
95+
run_me ()
96+
done
97+
;;
98+
99+
(* Output:
100+
-------
101+
Decorator [tap] example:
102+
[succ] input: 1
103+
[succ] input: 2
104+
[succ] input: 3
105+
[succ] input: 4
106+
[succ] input: 5
107+
After increment: 2
108+
After increment: 3
109+
After increment: 4
110+
After increment: 5
111+
After increment: 6
112+
Decorator [timed] example (performance measure):
113+
Execution time in seconds: 8.358457
114+
fib n=45 is equal to: 1134903170
115+
Decorator [counted] example:
116+
Function has been invoked [1] times!
117+
I keep running
118+
Function has been invoked [2] times!
119+
I keep running
120+
Function has been invoked [3] times!
121+
I keep running
122+
Function has been invoked [4] times!
123+
I keep running
124+
Function has been invoked [5] times!
125+
I keep running
126+
*)

0 commit comments

Comments
 (0)