-
Notifications
You must be signed in to change notification settings - Fork 10
Use a more stack efficient version of mapM #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Thanks for the great suggestion. Let's keep in mind that the main goal of this library, like the time library, is to guarantee correctness of time semantics. So we strongly prefer simple, expressive, and clearly correct types and implementations. As a subgoal - that means avoid CPS at almost any cost. But still, if we can improve stack usage, it would be nice. First of all, are you sure that the current implementation eats stack? Have you tested it? I'm not convinced that is the case here, even though in some cases If you can show it is true that we build up stack - can we think of a simpler (non-CPS) way to improve that? What does There is no way to avoid traversing the entire spine of the list and saving the thunks before returning a result. We just have to make sure that the thunks are on the heap and not the stack. |
|
@josefs See also Ed Kmett's comment to Neil Mitchell's blog post that you linked. This implies that the behavior of |
|
@josefs Here are two more points:
Looking forward to hearing your thoughts. |
|
Thanks for the feedback! First of all let me explained the way I tested this. I wrote the following small test program and ran it with a restricted stack size. ("Israel" is the largest time zone file I have easy access to) Before my change I needed a stack size of 32K. After my change I only needed 1K to run it. I think it makes a lot of sense to check for corrupted timezone files and use the Maybe monad to capture any problems. It is certainly possible to simplify my implementation. The Would you consider this implementation to be preferable? I'm afraid I don't know of a simple way to eliminate the stack leak. |
|
The datatype Personally I think it's clearer that this code doesn't use any stack space compared to the continuation passing implementation in my patch. All calls are tail calls. So thanks for asking me to simplify things! |
The function mapM is notorious for eating up a lot of stack space. This diff provides a version of mapM for the Maybe monad and the list traversable which doesn't eat up the stack. Having a version of mapM which doesn't eat a lot of stack is particularly helpful when trying to find spaceleaks with the method described here: http://neilmitchell.blogspot.com/2015/09/detecting-space-leaks.html
|
Ping |
|
Hi @josefs I am really sorry for leaving this great idea languish for so long. Are you still with me? If so, I would like to merge this. Here are a last few small suggested tweaks, please let me know what you think:
Thanks! Another random observation: When I saw your code I immediately thought of dlist. But dlist is solving a different problem - it intentionally builds up thunks to avoid repeated list traversals. Your implementation is more like |
The function mapM is notorious for eating up a lot of stack space.
This diff provides a version of mapM for the Maybe monad and the
list traversable which doesn't eat up the stack.
Having a version of mapM which doesn't eat a lot of stack is
particularly helpful when trying to find spaceleaks with the
method described here:
http://neilmitchell.blogspot.com/2015/09/detecting-space-leaks.html