如何计算f#中的任意函数

时间:2012-02-23 21:15:20

标签: function f# lambda

这是问题所在。我需要使用另一个函数计算f#中的函数。我有这段代码

let time f a =
  let start = System.DateTime.Now in
  let res = (fun f a -> f(a)) in
  let finish = System.DateTime.Now in
  (res, finish - start)

我试图称之为

time ackermann (2,9);;

我有一个ackermann函数,它将一个元组(s,n)作为参数 这可能是一个根本错误的东西,但我认为我远没有一个可能看起来像这样的解决方案。

有什么建议吗?

哦顺便问一下。我得到的错误信息是:

stdin(19,1):错误FS0030:值限制。值'it'被推断为具有泛型类型     val it:(('_a - >'_b) - >'_a - >'_ b)* System.TimeSpan
将'it'定义为一个简单的数据项,使其成为具有显式参数的函数,或者,如果您不打算将其作为泛型,则添加类型注释。

5 个答案:

答案 0 :(得分:8)

您至少有两个问题:

  1. 试试let res = f a。您已在范围内设置了值fa,但您目前将res定义为一个函数,该函数接受一个新的f并将其应用于新{{1} }}。
  2. 不要使用a s(适用于表示日期和时间,但不能用于缩短持续时间)。相反,您应该使用DateTime

答案 1 :(得分:7)

您可以这样做:

let time f =
  let sw = System.Diagnostics.Stopwatch.StartNew()
  let r = f()
  sw.Stop()
  printfn "%O" sw.Elapsed
  r

用法

time (fun () -> System.Threading.Thread.Sleep(100))

在将大量内容发送到fsi时,我通常会在代码文件中保留以下内容。

#if INTERACTIVE
#time "on"
#endif

这打开了fsi的内置时序,它提供的不仅仅是执行时间:

Real: 00:00:00.099, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0

答案 2 :(得分:2)

我会这样做:

let time f = fun a ->
    let start = System.DateTime.Now
    let res = f a
    (res, System.DateTime.Now - start)

然后,您可以使用它来创建定时功能,例如

let timedAckermann = time ackermann
let (res, period) = timedAckermann (2,9)

您还应该考虑使用System.Diagnostics.Stopwatch代替DateTime s。

答案 3 :(得分:1)

正如已经建议的那样,你应该使用秒表而不是DateTime进行这种时序分析。

尚未提及的是,如果由于某种原因需要使用DateTime,那么请始终考虑使用DateTime.UtcNow而不是DateTime.Now。 DateTime.Now的实现可以解释为“DateTime.UtcNow.ToLocalTime()”,并且“ToLocalTime()”部分的功能比您想象的要多。除了减少开销之外,DateTime.UtcNow还避免了与夏令时相关的麻烦。您可以在网上找到几篇文章和blog posts,了解DateTime.Now和DateTime.UtcNow之间的差异

答案 4 :(得分:0)

受FSharp Interactive的工作方式启发(请参阅https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp/fsi/fsi.fs#L197),这将为函数计时并报告多少CPU,分配等。

示例输出:Real: 00:00:00.2592820, CPU: 00:00:26.1814902, GC gen0: 30, gen1: 1, gen2: 0

  
  let time f =
      let ptime = System.Diagnostics.Process.GetCurrentProcess()
      let numGC = System.GC.MaxGeneration
      let startTotal = ptime.TotalProcessorTime
      let startGC = [| for i in 0 .. numGC -> System.GC.CollectionCount(i) |]
      let stopwatch = System.Diagnostics.Stopwatch.StartNew()
      let res = f ()
      stopwatch.Stop()
      let total = ptime.TotalProcessorTime - startTotal
      let spanGC = [ for i in 0 .. numGC-> System.GC.CollectionCount(i) - startGC.[i] ]
      let elapsed = stopwatch.Elapsed 
      printfn "Real: %A, CPU: %A, GC %s" elapsed total ( spanGC |> List.mapi (sprintf "gen%i: %i") |> String.concat ", ")
    res