seq不强迫评估

Dan*_*Man 4 haskell

所以我的haskell程序看起来像这样:

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"
Run Code Online (Sandbox Code Playgroud)

这样做需要大约8秒钟来加载我的第二个数据,然后大约需要3秒来完成其余的功能.

但是,如果我删除节目长度数据,它将闪烁

"Generated Second Data"
"Generated Ten Minute Bars"
"Generated Combined"
"Ran Algo"
Run Code Online (Sandbox Code Playgroud)

然后暂停一下,直到它贯穿所有实际功能.

这是我的理解,因为我在那里阻止了懒惰的评估.我用错了吗?

Joh*_*n L 11

是.有两个要点需要考虑:seq评估为WHNF(弱头正常形式),并且secondData是一个列表.WHNF意味着数据将被评估到最外层的构造函数,而最外层的构造函数secondData是for :(除非它是空的,然后是构造函数[]).所以

secondData `seq` generateBars (barSize featureSet) secondData
Run Code Online (Sandbox Code Playgroud)

只做足够的工作来确定是否secondData是空列表,或者它是否至少有一个元素.

length评估列表的主干,这基本上意味着它通过遍历整个结构来确定列表中有多少元素.这意味着length将比seq具有多于1个元素的列表做更多的工作.

您可以使用deepseq(来自deepseq)来完全评估列表,但您可能不想这样做. length并且deepseq必须完全遍历列表.如果您不需要提前知道这些信息,这是浪费精力,因为您的消费者也必须再次遍历列表.根据使用者的不同,这也可能会增加堆驻留时间,因为deepseq会先强制所有数据结构,但在算法完成之后才会进行GC.