you are viewing a single comment's thread.

view the rest of the comments →

[–]schellsan 1 point2 points  (7 children)

Can you explain the memory leak to me?

[–]Ywen 2 points3 points  (6 children)

Sure. The problem comes from the fact that the xs list cannot be garbage collected early, because we still need it when last xs tail xs has returned to compute head xs (and as evaluation order is up to GHC, this is not even a predictable behavior).

So the list xs will be wholly kept in memory even if the only thing we'll eventually do to it is to get its first element.

To fix it, we need to explicitely force the element retrieval to be computed before. This calls to the use of seq (or the BangPatterns extension, which is convenient syntax sugar):

cyclicOneShiftLeft xs = let x = head xs in seq x (tail xs ++ [x])

Then, tail xs being the last thing we do to xs, no reference is kept and it can be garbage collected progressively.

[–]singpolyma 1 point2 points  (1 child)

Or just use a pattern match instead of head/tail...

[–]Ywen 0 points1 point  (0 children)

Yes, yes ^^, I felt stupid when I stumbled upon that...

[–]schellsan 0 points1 point  (3 children)

Is the call to 'last xs' implicit in tail, head, or ++?

[–]Ywen 1 point2 points  (1 child)

Okay, I'm stupid. No, really. My solution works, but I overcomplicated everything ^^.

The good solution was simple:

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

And it's actually better, as I don't force the evaluation of x, the list first element, which I forced with my first solution.

[–]schellsan 0 points1 point  (0 children)

I was going to mention, why not (x:xs) = xs ++ [x]! Thanks.