Side-effects and top-level expressions in OCaml
ocaml, side-effects
Solution
When you write `let tmp = ref foo`, the expression `foo` is evaluated once, to produce a value which is stored in the reference. Accessing the reference returns this value, without re-evaluating the original expression.
The way to provoke re-evaluation is to use a function instead: if you write a function `(fun () -> foo)`, this is a value: it is returned as is, passed to functions, stored in references. And each time you apply an argument to this value, the expression `foo` is evaluated.
Clément's solution is good. The idea of
let counter =
let count = ref (-1) in
fun () -> incr count; !count
Is that the reference is allocated once, but incremented each time the function `fun () -> incr count; !count` is called. Having the reference local to the function avoids some of the pitfall of global variables. You can think of it as a "static variable" of the function `counter`, only it is a natural result of OCaml scoping and evaluation rules and not an additional, function-specific concept.
You can even write an even more general `vargen` generator, that creates fresh, independent counters each time it's called:
let make_vargen prefix =
let count = ref (-1) in
fun () ->
incr count;
prefix ^ string_of_int !count
let fresh_t = make_vargen "t"
let () = print_endline (fresh_t ()) (* t0 *)
let () = print_endline (fresh_t ()) (* t1 *)
let fresh_u = make_vargen "u"
let () = print_endline (fresh_u ()) (* u0 *)
let () = print_endline (fresh_t ()) (* t2 *)
let () = print_endline (fresh_u ()) (* u1 *)
Problem
I am in trouble with ocaml. I want to make a function that will increment my counter every time I call it and concat my vargen string with the counter number and return this new string. What I did without success is: ``` let (counter : int ref) = ref 0;; let (vargen : string) = "_t";; let tmp = incr counter;ref (vargen ^ string_of_int !counter);; Printf.printf "%s\n" !tmp;; Printf.printf "%s\n" !tmp;; Printf.printf "%s\n" !tmp;; Printf.printf "%s\n" !tmp;; ``` But my output are always: ``` _t1 _t1 _t1 _t1 ``` And what my output should be: ``` _t0 _t1 _t2 _t3 ``` Any ideas to solve my problem guyz? Thks all.