运行以下程序将打印"空间溢出:当前大小8388608字节".我已经读过这个和这个,但仍然不知道如何解决我的问题.我正在使用foldr,不应该保证它是"尾递归"吗?
到目前为止,我对Haskell感觉很棒,直到我知道在使用强大的递归时我应该防止"空间溢出".:)
module Main where import Data.List value a b = let l = length $ takeWhile (isPrime) $ map (\n->n^2 + a * n + b) [0..] in (l, a ,b) euler27 = let tuple_list = [value a b | a <-[-999..999] , b <- [-999..999]] in foldr (\(n,a,b) (max,v) -> if n > max then (n , a * b) else (max ,v) ) (0,0) tuple_list main = print euler27
编辑:isPrime
为简单起见删除定义
正如皮尔回答的那样,你应该使用foldl'
.更多细节:
foldl'
在将其放入折叠步骤之前计算其"左侧".
foldr
给你的折叠步骤一个右侧值的"thunk".这个"thunk"将在需要时计算.
让我们总结foldr
并看看它如何评估:
foldr (+) 0 [1..3] 1 + foldr (+) 0 [2..3] 1 + 2 + foldr (+) 0 [3] 1 + 2 + 3 + foldl (+) 0 [] -- this is a big thunk.. 1 + 2 + 3 + 0 1 + 2 + 3 1 + 5 6
并使用foldl'
:(代码中省略了标签,因为SO不能很好地显示它)
foldl (+) 0 [1..3] -- seq is a "strictness hint". -- here it means that x is calculated before the foldl x `seq` foldl (+) x [2..3] where x = 0+1 foldl (+) 1 [2..3] x `seq` foldl (+) x [3] where x = 1+2 foldl (+) 3 [3] x `seq` foldl (+) x [] where x = 3+3 foldl (+) 6 [] 6
用途好foldr
,不泄漏."步骤"必须:
返回不依赖于"右侧"的结果,忽略它或将其包含在惰性结构中
按原样返回右侧
良好foldr
用法的例子:
-- in map, the step returns the structure head -- without evaluating the "right-side" map f = foldr ((:) . f) [] filter f = foldr step [] where step x rest | f x = x : rest -- returns structure head | otherwise = rest -- returns right-side as is any f = foldr step False where -- can use "step x rest = f x || rest". it is the same. -- version below used for verbosity step x rest | f x = True -- ignore right-side | otherwise = rest -- returns right-side as is