这是问题所在。我需要使用另一个函数计算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'定义为一个简单的数据项,使其成为具有显式参数的函数,或者,如果您不打算将其作为泛型,则添加类型注释。
答案 0 :(得分:8)
您至少有两个问题:
let res = f a
。您已在范围内设置了值f
和a
,但您目前将res
定义为一个函数,该函数接受一个新的f
并将其应用于新{{1} }}。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