i tried to code to calculate time that a function costs
list <- buildlist 10000 10000
starttime <- getClockTime
let sortedlist = quicksort list
endtime <- getClockTime
let difftime = diffClockTimes endtime starttime
function buildlist:
buildlist :: Int -> Int -> IO [Int]
buildlist n m = do
seed <- getStdGen
let l = randomRs (0, m) seed
let list = take n l
return list
function quicksort:
quicksort [] = []
quicksort (x:xs) =
let head = [a|a<-xs,a<=x]
tail = [a|a<-xs,a>x]
in quicksort head ++ [x] ++ quicksort tail
first question: when i output the difftime, it is always zero no matter how long the list is.
second one: i wonder what ">>=" in the code from Real World Haskell means.
getClockTime >>= (\(TOD sec _) -> return sec)
third: i write this to get tdSec and tdPicosec from a TimeDiff variable. is there any easier way?
time <-(\(TimeDiff _ _ _ _ _ s ps) -> return [ ( \a -> fromIntegral a :: Double ) s , ( \a -> fromIntegral a :: Double ) ps ] ) difftime
Question 1:
Your code does not sort the list! It simply defines the name
sortedlist
as beingquicksort 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
seq
.seq
has typea -> 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 usedeepseq
Question 2:
>>=
is the monadic bind operator. Here it takes anIO
action of typeIO a
and a functiona -> IO b
and combines them together to make a new action of typeIO b
. This does the same thing as do notation.foo >>= \x -> expr
is the same thing asand 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 accessessortedlist
, so it's never even computed.As stated in another answer, you can force your program to compute
sortedlist
with a somewhat magical function calleddeepseq
fromControl.Deepseq
.deepseq v
is equivalent toid
, except that it has the side-effect of forcingv
to be fully evaluated.As for your second question, yes, there's an easier way to access the fields of a
TimeDiff
. The field names inData
declaration second as getter functions. So,tdSec td
gets the seconds oftd
andtdPicosec 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/chronographHere's a short example of how to use it:
A few points:
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 intochronoNF
chronoNF
evaluates using the same strategy asdeepseq
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.