我在使用 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
有什么想法可以解决我的问题 Guyz?
谢谢大家。
最佳答案
当你写 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 *)
关于ocaml - OCaml 中的副作用和顶级表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10459363/