Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a time function in Haskell

I’m new to Haskell and I’d like to be able to time the runtime of a given function call or snippet of code.

In Clojure I can use ‘time’:

user=> (time (apply * (range 2 10000))) "Elapsed time: 289.795 msecs" 2846259680917054518906413212119868890148051... 

In Scala, I can define the function myself:

scala> def time[T](code : => T) =  {      |   val t0 = System.nanoTime : Double      |   val res = code      |   val t1 = System.nanoTime : Double      |   println("Elapsed time " + (t1 - t0) / 1000000.0 + " msecs")      |   res      | } time: [T](=> T)T  scala> time((1 to 10000).foldLeft(1:BigInt)(_*_)) Elapsed time 274.292224 msecs res0: BigInt = 284625968091705451... 

How can I write the equivalent of my Scala function or Clojure's ‘time’ in Haskell? The System.TimeIt module I've found on Hackage is not general enough because it works only if an IO computation is being measured. So timeIt(4 + 4) wouldn't work, only timeIt(print $ 4 + 4), which gets annoying fast. Beside, I really want to see how Haskell handles the general case.

Thank you!

like image 364
Jacob Avatar asked Oct 04 '09 16:10

Jacob


People also ask

How do you time a Haskell function?

Simplest things is to just do :set +s in ghci , and then you can see the execution time of anything you run, along with memory usage. Functions run much slower in ghci, however.

How do I get the current time in Haskell?

You can use getCurrentTime from Data. Time. Clock .

How do you multiply numbers in Haskell?

In Haskell you can't multiply an Int by a Float because the * operator has type Num a => a -> a -> a - it takes two values of the same numeric type and gives you a result that is that type. You can multiply an Int by an Int to get an Int , or a Float by a Float to get a Float .


2 Answers

Please look at using the standard libraries for this:

  • Timing computations in Haskell
  • Criterion, possibly the best open source benchmarking/timing library in existence
  • About Criterion

Just use criterion.


A note on evaluation depth: laziness means you need to decide how much evaluation you want to have during your timing run. Typically you'll want to reduce your code to normal form. The NFData typeclass lets you do this via the rnf method. If evaluating to the outermost constructor is ok, use seq on your pure code to force its evaluation.

like image 78
Don Stewart Avatar answered Oct 05 '22 15:10

Don Stewart


Haskell is lazily evaluated. If your expression doesn't have some side effect (as encoded in the IO monad or the like), then the program doesn't need to actually resolve the expression to a value, and so won't.

To get meaningful numbers out of this, you might try timing print 4 and print expr and take the difference, in order to remove the overhead of string formatting and IO.

like image 35
Phil Miller Avatar answered Oct 05 '22 13:10

Phil Miller