4

所以我的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"

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

但是,如果我删除显示长度数据,它会闪烁

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

然后暂停一下,直到它运行完所有实际功能。

我的理解是通过在其中放置 seq 来阻止惰性评估。我用错了吗?

4

2 回答 2

11

是的。有两点需要考虑:seq评估为 WHNF(弱头范式),并且secondData是一个列表。WHNF表示数据会被求值到最外层的构造函数,最外层的构造函数为secondDatais :(除非为空,则构造函数为[])。所以

secondData `seq` generateBars (barSize featureSet) secondData

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

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

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

于 2012-07-04T01:16:07.670 回答
3

seq仅将值强制为弱头范式;对于列表,这意味着它只评估足够远来判断列表是否匹配[]_:_。猜测一下,纯粹基于名称(因为您没有给出任何类型),这或类似的事情就是发生在您身上的事情:它只是评估到足以意识到“是的,这里根本没有数据” .

通常的技巧是调用seq列表的长度或使用deepseq.

于 2012-07-04T01:16:22.920 回答