5

我遇到了ocaml的麻烦。

我想创建一个函数,每次调用它时都会增加我的计数器,并将我的 vargen 字符串与计数器编号连接起来并返回这个新字符串。

我没有成功的做法是:

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;;

但我的输出总是:

_t1
_t1
_t1
_t1

我的输出应该是:

    _t0
    _t1
    _t2
    _t3

有什么想法可以解决我的问题吗?

谢谢大家。

4

4 回答 4

8

当您编写let tmp = ref foo时,表达式foo会被计算一次,以产生一个存储在引用中的值。访问引用会返回此值,而无需重新计算原始表达式。

引发重新评估的方法是改用函数:如果你写一个函数(fun () -> foo),这是一个值:它按原样返回,传递给函数,存储在引用中。每次将参数应用于此值时,foo都会计算表达式。

克莱门特的解决方案很好。的想法

let counter =
  let count = ref (-1) in
  fun () -> incr count; !count

是指分配一次,但每次fun () -> incr count; !count调用函数时都会递增。对函数进行本地引用可以避免一些全局变量的缺陷。您可以将其视为函数的“静态变量” counter,只是它是 OCaml 范围和评估规则的自然结果,而不是附加的、特定于函数的概念。

你甚至可以编写一个更通用的vargen生成器,每次调用它时都会创建新的、独立的计数器:

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 *)
于 2012-05-05T07:50:52.037 回答
3

因为tmp是一个值,所以执行一次。将其更改为函数应该使计数器在每次tmp调用时增加。

此外,为简单起见,您可以返回string而不是string ref

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());;
于 2012-05-05T06:42:44.557 回答
3

你可以使用

let tmp = 
  let counter = ref 0 in
  (fun () -> incr counter; vargen ^ (string_of_int !counter))

使用 调用该函数tmp (),如果您希望计数器从 0 开始,请将 0 更改为 -1。

于 2012-05-05T06:47:42.310 回答
1

如果您需要在不增加计数器的情况下选择性地读取计数器,则可以添加一个参数:

let counter =
  let count = ref (-1) in
    fun do_incr -> if do_incr then begin incr count end; !count;;

像这样使用它:

# counter true;;
- : int = 0
# counter true;;
- : int = 1
# counter true;;
- : int = 2
# counter false;;
- : int = 2
# counter false;;
- : int = 2
# counter true;;
- : int = 3
于 2016-01-28T13:41:54.683 回答