compiler
compiler copied to clipboard
`RangeError` occurs in CP styled functions
Quick Summary: I've been playing with continuation passing styled functions and stumbled upon the code, that seems to confuse the compiler.
Here is the code:
g : Int -> (Int -> a) -> a
g value cont =
case value of
1 -> cont 1
_ -> g (value-1) (\result -> cont (result * value))
Expected: function g computes value's factorial
Actual (repl):
> g 1 (Debug.log "result")
result: 1
1 : Int
> g 2 (Debug.log "result")
RangeError: Maximum call stack size exceeded
- Elm: 0.19.1
- Browser: no browser (repl)
- Operating System: ubuntu 20
Thanks for reporting this! To set expectations:
- Issues are reviewed in batches, so it can take some time to get a response.
- Ask questions in a community forum. You will get an answer quicker that way!
- If you experience something similar, open a new issue. We like duplicates.
Finally, please be patient with the core team. They are trying their best with limited resources.
This is the compiled output:
var $author$project$T$g = F2(
function (value, cont) {
g:
while (true) {
if (value === 1) {
return cont(1);
} else {
var $temp$value = value - 1,
$temp$cont = function (result) {
return cont(result * value);
};
value = $temp$value;
cont = $temp$cont;
continue g;
}
}
});
It looks like tail-call optimization accidentally broke capturing of arguments, changing the captured values. This problem is evident in perhaps another simpler example:
f x l = if x == 0 then l else f (x - 1) ((\_ -> x) :: l)
> List.map (\g -> g ()) (f 10 [])
[0,0,0,0,0,0,0,0,0,0]
: List number
The output should be [10, 9, ... , 1]
For people being bitten by this in the future, using https://github.com/micahhahn/elm-safe-recursion is both going to fix this and allow mutual recursion in TCO