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
Tail-calls in recursive functions are not optimized if used with pipeline operators #1770
Comments
Here is another (smaller/repl-based) example:
HOWEVER, not if slightly modified using pipe operator:
|
tail call optimization fails when pipes are used elm/compiler#1770.
tail call optimization fails when pipes are used elm/compiler#1770.
In changing how code was generated in 0.19.0 to make sure the generated assets were really small, we moved some AST shuffling later into the optimization process. The old version tried to flatten out The resulting behavior is that tail-call elimination is only performed when the recursive call is in "tail call position" (i.e. called directly at the conclusion of some some branch of logic) This particular optimization enters into the realm of feature because it can change program behavior, so it's definitely important to keep this stable. It looks like this behavior is going to remain the same from 0.19.0 to 0.19.1, and I think the best path is to just require the "tail call position" without any special exceptions for now. |
Is the change in behavior anything other than a "RangeError: Maximum call stack size exceeded"? I think it would be safe to say no client would be relying on this behavior and furthermore the behavior is likely widely variant across systems. From the operator documentation, we have
But what seems to be suggested in your note is that this is not an equivalency. I may be missing something, but this is rather surprising behavior. A common refactoring relies on the expectation of this equivalency; that |
From slack discussion: https://elmlang.slack.com/archives/C13L7S5GR/p1535488054000100
In Elm 0.19. Reproducible in Ellie.
SSCCE:
Here,
tailCallWithPipeline
andtailCallWithoutPipeline
are semantically identical recursive functions, the only difference is a use of pipeline operator|>
.However, executing
tailCallWithPipeline
ends up in runtime error:RangeError: Maximum call stack size exceeded
, whereastailCallWithoutPipeline
does not (correctly optimized and run fine).Both worked fine in 0.18.
The text was updated successfully, but these errors were encountered: