ocaml - OCaml 中的副作用和顶级表达式

标签 ocaml side-effects

我在使用 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/

相关文章:

string - 将字符串拆分为字符列表的最简单方法是什么?

module - OCaml 模块 : include AND open?

ocaml - 整数类型的模型 n

f# - 组合 2 个(或 n)('a -> unit)具有相同 arg 类型的函数

java - 使用 Java 中的引用来创建副作用

floating-point - 核心OCaml中浮点的绝对值

c# - 如何防止 Visual Studio 2015 的调试器评估具有副作用的静态属性?

c++ - 如何在 C++11 中调用函数后将对象声明为无效?

reactjs - 使用 useEffect 与使用 useCallback 处理 API 调用

parsing - OCaml 解析函数