OCaml中的通用定时器高阶函数

Mar*_*tus 7 generics ocaml

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

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

问题是我无法以能够处理任何arity函数的方式实现它.例如以下代码:

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

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

pad*_*pad 9

我理解你打算用任意arity制作一个计时器功能.但是你不能在OCaml中以一种简单的方式做到这一点.

此外,只有一个参数的计时器功能足以在实践中使用:

let timer f x =
   let t0 = Sys.time()                                         
   in let result = f x                                              
   in let diff = Sys.time() -. t0                                     
   in diff, result
Run Code Online (Sandbox Code Playgroud)

因为任何g具有任何arity的函数都可以通过以下方式timer轻松传递:

let diff, result = timer (fun () -> g x1 x2 x3 ... xN) ()
Run Code Online (Sandbox Code Playgroud)

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

let diff, result = timer (g x1 x2 x3 ... xN-1) xN
Run Code Online (Sandbox Code Playgroud)


gas*_*che 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
Run Code Online (Sandbox Code Playgroud)

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

let fun_to_test = match some_configuration with ... in
timer fun_to_test
Run Code Online (Sandbox Code Playgroud)

pad的设计,起初更具吸引力,因为更一般,鼓励你改写:

let fun_to_test, arg = match some_configuration with .... in
timer fun_to_test arg
Run Code Online (Sandbox Code Playgroud)

这个选择的问题在于它最初似乎很好,并且在添加几个选项后,您会遇到一个案例,其中要测试的不同函数的参数不是同一类型.而且你有一个类型错误.错误代码示例:

let fun_to_test, arg =
  if Random.bool ()
  then (foo, 3)
  else (bar, 3.2)
in timer fun_to_test arg
Run Code Online (Sandbox Code Playgroud)

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

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