7

我正在尝试在 OCaml 中实现一个通用计时器函数,它将作为输入一个任意数量的函数并返回类型'r并返回一个函数:

  • 输入参数的数量和类型相同,并且
  • 返回类型float * 'r,其中浮点数将是函数中花费的时间的度量(例如由 报告Sys.time()

问题是我无法以它可以处理任何数量的功能的方式实现它。例如以下代码:

让计时器 f =              
   让 timerf xy =                                 
      让 t0 = Sys.time ()                                         
      在让结果 = fxy                                                 
      在 let diff = Sys.time() -。t0                                     
      在差异中,结果                                    
   在定时器    

仅适用于输入 arity 2 的函数。对我来说,如何概括它以处理任何 arity 的函数并不明显。我希望部分功能应用程序能以某种方式神奇地解决这个难题,但我无法让它工作。

4

2 回答 2

9

我理解您制作具有任意数量的计时器功能的意图。但是你不能在 OCaml 中轻松地做到这一点。

此外,一个只有一个参数的定时器函数在实践中就足够了:

let timer f x =
   let t0 = Sys.time()                                         
   in let result = f x                                              
   in let diff = Sys.time() -. t0                                     
   in diff, result

由于任何g具有任何数量的函数都可以通过以下方式timer轻松传递:

let diff, result = timer (fun () -> g x1 x2 x3 ... xN) ()

或通过使用部分应用程序更好(如@Andreas 所建议):

let diff, result = timer (g x1 x2 x3 ... xN-1) xN
于 2012-04-04T22:01:26.340 回答
7

对 pad 解决方案的评论过于冗长,无法发表评论。

在实践中,我发现f : unit -> 'a通过传递()而不是延迟参数来强制执行是一种更好的设计。

let timer f =
  let t0 = Sys.time() in
  let result = f () in
  let t1 = Sys.time() in
  t1 -. t0, result

原因是我倾向于经常使用以下模式:

let fun_to_test = match some_configuration with ... in
timer fun_to_test

pad 的设计,一开始更吸引人,因为更通用,鼓励你改写:

let fun_to_test, arg = match some_configuration with .... in
timer fun_to_test arg

这种选择的问题在于,起初它看起来不错,在添加了一些选项之后,您会遇到要测试的不同函数的参数类型不同的情况。你有一个类型错误。错误代码示例:

let fun_to_test, arg =
  if Random.bool ()
  then (foo, 3)
  else (bar, 3.2)
in timer fun_to_test arg

通过使用预先传递的参数强制闭包,我在这里免费获得“存在类型”:最后一个函数参数的类型不会出现在timer应用程序的类型中。我发现这在实践中会更好。

当然,您也可以延迟完整的调用并()在 pad 的设计中用作参数。但我更喜欢强迫我这样做的选择,因为否则我太想不这样做了,我以后再付钱。

于 2012-04-05T13:21:27.043 回答