how to solve “stack space overflow” in haskell

风格不统一 提交于 2019-11-30 10:07:23

As pierr answered, you should use foldl'. For more details:

  • foldl' calculates its "left-side" before giving it to your fold step.
  • foldr gives your fold step a "thunk" for the right-side value. This "thunk" will be calculated when needed.

Let's make a sum with foldr and see how it evaluates:

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

And with foldl': (tag omitted in code because SO doesn't display it nicely)

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

In good uses for foldr, which don't leak. the "step" must either:

  • Return a result that doesn't depend on the "right-side", ignoring it or containing it in a lazy structure
  • Return the right-side as is

Examples of good foldr usage:

-- 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

replace

foldr (\(n,a,b) (max,v) -> if n > max then (n , a * b) else (max ,v) ) (0,0) tuple_list

with

foldl' (\(max ,v) (n,a,b) -> if n > max then (n , a * b) else (max ,v) ) (0,0) tuple_list

solved this problem, should that suggest we should always prefer to use foldl' instead of other variants(foldl,foldr)?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!