Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

seq not forcing evaluation

Tags:

haskell

So I have my haskell program that looks something like this:

main = do
    secondData <- loadSecondBars "output.data"
    putStrLn $ "Generated Second Data " ++ (show $ length secondData)
    let tenMinBars = secondData `seq` generateBars (barSize featureSet) secondData
    putStrLn $ "Generated Ten Minute Bars " ++ (show $ length tenMinBars)
    let combinedData = seq tenMinBars sortBars (tenMinBars ++ secondData)
    putStrLn $ "Generated Combined" ++ (show $ length combinedData)
    let completedOrderManager = evalState (runBar combinedData) startState
    putStrLn "Ran Algo"

Doing this it will take about 8 seconds to load my second data, then about 3 seconds to do the rest of the functions.

However, if I remove the show length data, it will flash

"Generated Second Data"
"Generated Ten Minute Bars"
"Generated Combined"
"Ran Algo"

Then pause for a bit till it runs through all the actual functions.

It was my understanding by having seq in there I prevented the lazy evaluation. Am I using them wrong?

like image 424
DantheMan Avatar asked Dec 09 '22 23:12

DantheMan


2 Answers

Yes. There are two important points to consider: seq evaluates to WHNF (weak-head normal form), and secondData is a list. WHNF means that the data will be evaluated to the outermost constructor, and the outermost constructor for secondData is : (unless it's empty, then the constructor is []). So

secondData `seq` generateBars (barSize featureSet) secondData

will only do enough work to determine if secondData is the empty list, or if it has at least one element.

length evaluates the spine of a list, which basically means it determines how many elements are in the list by traversing the full structure. This means that length will do more work than seq for lists with more than 1 element.

You can use deepseq (from deepseq) to fully evaluate a list, but you may not want to. length and deepseq have to fully traverse the list. If you don't need to know that information in advance, this is wasted effort as your consumer will have to traverse the list again also. Depending on the consumer, this may also increase heap residency because deepseq will force all the data structures first, but they won't be GC'd until after the algorithm is complete.

like image 63
John L Avatar answered Dec 21 '22 21:12

John L


seq only forces values to weak-head normal form; for lists, this means it only evaluates far enough to tell whether a list matches [] or _:_. At a guess, based purely on names (since you haven't given any types), this or something like it is what's happening to you: it's only evaluating far enough to realize that "yup, there's more than no data at all here".

The usual trick is to call seq on the length of the list or use deepseq.

like image 34
Daniel Wagner Avatar answered Dec 21 '22 22:12

Daniel Wagner