Как рассчитать произвольную функцию в F # - PullRequest
3 голосов
/ 24 февраля 2012

вот в чем проблема. Мне нужно время функции в 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) Возможно, что-то в корне не так с этим, но я не думаю, что я далек от решения, которое могло бы и выглядит примерно так.

Есть предложения?

О, кстати. полученное сообщение об ошибке гласит:

стандартный ввод (19,1): ошибка FS0030: ограничение значения. Значение 'it' было выведено, чтобы иметь общий тип val it: (('_a ->' _b) -> '_a ->' _b) * System.TimeSpan
Либо определите «это» как простой термин данных, сделайте его функцией с явными аргументами или, если вы не собираетесь использовать его как универсальный, добавьте аннотацию типа.

Ответы [ 5 ]

8 голосов
/ 24 февраля 2012

У вас есть как минимум две проблемы:

  1. Попробуйте let res = f a.У вас уже есть значения f и a в области видимости, но вы в настоящее время определяете res как функцию, которая принимает новый f и применяет его к новому a.
  2. Donне используйте DateTime s (которые подходят для представления даты и времени, но не для коротких периодов).Вместо этого вы должны использовать System.Diagnostics.Stopwatch.
7 голосов
/ 24 февраля 2012

Вы можете сделать что-то вроде этого:

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 голосов
/ 24 февраля 2012

Я бы сделал это так:

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.

1 голос
/ 24 февраля 2012

Как уже было предложено, вы должны использовать секундомер вместо DateTime для этого вида анализа времени.

Что еще не упомянуто, так это то, что если вам по какой-то причине нужно использовать DateTime, то всегда рассматривайте возможность использования DateTime.UtcNow, а не DateTime.Now. Реализация DateTime.Now может быть перефразирована как «DateTime.UtcNow.ToLocalTime ()», и эта часть «ToLocalTime ()» делает больше, чем вы могли бы подумать. В дополнение к меньшим накладным расходам, DateTime.UtcNow также позволяет избежать головной боли, связанной с переходом на летнее время. В Интернете можно найти несколько статей и сообщений в блоге о различиях между DateTime.Now и DateTime.UtcNow

.
0 голосов
/ 03 июля 2018

Вдохновлен тем, как FSharp Interactive делает это (см. https://github.com/Microsoft/visualfsharp/blob/master/src/fsharp/fsi/fsi.fs#L197),. Это время, функция и отчет о том, сколько ЦП, распределение и т. Д.

Пример вывода: 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...