Haskell calculate time of function performing

假装没事ソ 提交于 2019-12-04 07:49:17

Question 1:

Your code does not sort the list! It simply defines the name sortedlist as being quicksort list but this wont be computed until the value is actually needed. That is lazy evaluation. We do not do extra work in this language.

Since benchmarks are extra useless work (that is the point), this makes benchmarking hard.

Your choices

  • Use seq. seq has type a -> b -> b and has the behavior of evaluating its first argument to what is called "weak head normal form". Here since you want to force the entire list you might want to use deepseq
  • Use a proper benchmarking package like criterion (prefered and easier)

Question 2:

>>= is the monadic bind operator. Here it takes an IO action of type IO a and a function a -> IO b and combines them together to make a new action of type IO b. This does the same thing as do notation. foo >>= \x -> expr is the same thing as

 do x <- foo
    expr

and in fact, do notation is just syntactic sugar for >>=

I'm not sure what is being asked in question 3--perhaps it should get its own Stackoverflow question.

difftime is always zero, because Haskell's lazy evaluation order has completely optimized away the actual sort. Nothing in your program accesses sortedlist, so it's never even computed.

As stated in another answer, you can force your program to compute sortedlist with a somewhat magical function called deepseq from Control.Deepseq. deepseq v is equivalent to id, except that it has the side-effect of forcing v to be fully evaluated.

starttime <- getClockTime
let sortedlist = quicksort list
endtime <- deepseq sortedlist getClockTime

As for your second question, yes, there's an easier way to access the fields of a TimeDiff. The field names in Data declaration second as getter functions. So, tdSec td gets the seconds of td and tdPicosec td gets the picoseconds.

For measuring the evaluation time of pure functions, you might be interested in my Chronograph package: http://hackage.haskell.org/package/chronograph

Here's a short example of how to use it:

Prelude Data.Chronograph> :m Data.Chronograph Data.List
Prelude Data.Chronograph Data.List> let theList = reverse [1..1000]
Prelude Data.Chronograph Data.List> sum theList 
500500
Prelude Data.Chronograph Data.List> let timed = chronoNF (sort theList)
Prelude Data.Chronograph Data.List> measure timed
0.000062s
Prelude Data.Chronograph Data.List> head $ val timed
1

A few points:

  • I evaluate the sum of the original theList to force its construction and reversal. If it's not forced here, the cost of construction will be attributed to the evaluation of the expression passed into chronoNF
  • chronoNF evaluates using the same strategy as deepseq as some other answers discuss. chronograph provides other functions for different evaluation strategies. For example, we could evaluate to weak head normal form, which wouldn't actually fully sort the list.

chronograph can also measure IO expressions, but those are typically much simpler to deal with than non-IO expressions.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!