How to force evaluation in Haskell?

Giorgio picture Giorgio · Jan 4, 2013 · Viewed 13.8k times · Source

I am relatively new to Haskell and I am trying to learn how different actions can be executed in sequence using the do notation. In particular, I am writing a program to benchmark an algorithm (a function)

foo :: [String] -> [String]

To this purpose I would like to write a function like

import System.CPUTime

benchmark :: [String] -> IO Integer
benchmark inputList = do
                         start <- getCPUTime
                         let r = foo inputList
                         end <- getCPUTime
                         return (end - start) -- Possible conversion needed.

The last line might need a conversion (e.g. to milliseconds) but this is not the topic of this question.

Is this the correct way to measure the time needed to compute function foo on some argument inputList?

In other words, will the expression foo inputList be completely reduced before the action end <- getCPUTime is executed? Or will r only be bound to the thunk foo inputList?

More in general, how can I ensure that an expression is completely evaluated before some action is executed?


This question was asked a few months ago on programmers (see here) and had an accepted answer there but it has been closed as off-topic because it belongs on stack overflow. The question could not be moved to stack overflow because it is older than 60 days. So, in agreement with the moderators, I am reposting the question here and posting the accepted question myself because I think it contains some useful information.

Answer

Giorgio picture Giorgio · Jan 4, 2013

Answer originally given by user ysdx on programmers:

Indeed you version will not benchmark your algorithm. As r is not used it will not be evaluated at all.

You should be able to do it with DeepSeq:

benchmark :: [String] -> IO Integer
benchmark inputList = do
                     start <- getCPUTime
                     let r = foo inputList
                     end <- r `deepseq` getCPUTime
                     return (end - start)

(a `deepseq` b) is some "magic" expression which forces the complete/recursive evaluation of a before returning b.