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
,那么创建此列表的懒惰方式是什么?
答案 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