将两个列表相乘会导致堆栈溢出

时间:2014-05-07 15:46:32

标签: haskell

test :: [Int] -> [Int]
test l   | (length l) > 5 = l
         | otherwise = test l ++ take 1 searchSpace
    where searchSpace = zipWith (*) [100..999] [100..999]

上面的代码为我提供了堆栈溢出。我假设Haskell正在全面评估并在searchSpace中存储zipWith的结果。如果我只想让我的程序逐步应用take 1,那么创建此列表的懒惰方式是什么?

2 个答案:

答案 0 :(得分:6)

你有一个无限循环。如果我们将[1..6](选择为长度大于5)这样的列表传递给test,它会像这样减少:

test [1..6]
test [1..6] ++ take 1 searchSpace
test [1..6] ++ take 1 searchSpace ++ take 1 searchSpace
test [1..6] ++ take 1 searchSpace ++ take 1 searchSpace ++ take 1 searchSpace
...

评估树的顶部在第二步中变为(++),必须评估其左参数才能继续。

[]     ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)

因此,最终结果是该函数根本不做任何工作,并且将所有时间都花费在您的无限循环分支上。

答案 1 :(得分:1)

如果l <= 5,则在没有终止条件的情况下调用test l recusrively。 你宁愿想要像

这样的东西
test :: [Int] -> [Int]
test l   | (length l) > 5 = l
         | null l = take 1 searchSpace
         | otherwise = test init_of_l ++ take 1 searchSpace
    where searchSpace = zipWith (*) [100..999] [100..999]
          init_of_l = init l

working example here