是否在每次函数调用时评估可选参数的默认值?

Are default values to optional parameters evaluated on every function call?

OCaml spec 记录了可选参数的默认值的使用,但没有具体说明如果默认值是例如一个每次可以 return 不同值的函数。

从一些测试来看,似乎每次都计算值 如果 参数没有传入;例如

let x = ref 0;;

let incr x =
  x := !x + 1;
  !x
;;

let test ?(a = incr x) () = a;;

调用 test () 结果为 1、2、3、...,每次递增,但调用 test ~a:123 () 不会递增 ref。

运行 test ()test ~a () 的行为似乎大致类似于

let test ?a () =
  let a =
    match a with
    | None -> incr x
    | Some a -> a
  in
  body_of_test ~a ()
;;

这是建模的正确方法吗?而且,这种行为是否记录在某处?

这确实是预期的行为。从documentation(强调我的)看:

A function of the form fun ? lab :( pattern = expr0 ) -> expr is equivalent to fun ? lab : ident -> let pattern = match ident with Some ident -> ident | None -> expr0 in expr

where ident is a fresh variable, except that it is unspecified when expr0 is evaluated.

尽管对增量的评估如您所想的那样工作,但在函数应用程序中 "hide" 效果是非常不明智的。值得注意的是,以下代码可以 return truefalse,但不能保证另一个版本的编译器会给出相同的行为。

let test2 ?(a = incr x) ?(b = incr x) () = a < b
if test2 () then ...