Reputation: 1270
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.
Upvotes: 5
Views: 3029
Reputation: 2379
If you need the counter to be optionally read without incrementing it, you can add an argument:
let counter =
let count = ref (-1) in
fun do_incr -> if do_incr then begin incr count end; !count;;
Using it like:
# counter true;;
- : int = 0
# counter true;;
- : int = 1
# counter true;;
- : int = 2
# counter false;;
- : int = 2
# counter false;;
- : int = 2
# counter true;;
- : int = 3
Upvotes: 1
Reputation: 31459
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 *)
Upvotes: 8
Reputation: 41290
Since tmp
is a value, it is executed once. Changing it into a function should make the counter increase each time tmp
is invoked.
Furthermore, you could return string
instead of string ref
for simplicity:
let counter: int ref = ref (-1);;
let vargen: string = "_t";;
// tmp now is a function
let tmp() = incr counter; 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());;
Upvotes: 3
Reputation: 12937
You could use
let tmp =
let counter = ref 0 in
(fun () -> incr counter; vargen ^ (string_of_int !counter))
Call the function using tmp ()
, and change 0 to -1 if you want the counter to start at 0.
Upvotes: 3