const std = @import("std");
pub fn main() !void {
var i: i128 = 0;
foo(&i);
}
pub fn foo(i: *i128) void {
i.* += 1;
std.debug.print("i: {d}\n", .{i.*});
bar(i);
}
pub fn bar(i: *i128 ) void {
i.* += 1;
foo(i);
}
This code will work, but will eventually overflow the stack if it runs for a long time.
If I change it to the tail-recursive version below, it will run for a long time without any stack overflow.
const std = @import("std");
pub fn main() !void {
var i: i128 = 0;
foo(&i);
}
pub fn foo(i: *i128) void {
i.* += 1;
std.debug.print("i: {d}\n", .{i.*});
@call(.always_tail, bar, .{ i });
}
pub fn bar(i: *i128 ) void {
i.* += 1;
@call(.always_tail, foo, .{i});
}
However, tail recursion requires the same parameters. For example, the parameters of functions foo and bar in the above code are both *128 .
If their parameters are different, the compiler will issue an error, such as the following code.
const std = @import("std");
pub fn main() !void {
var i: i128 = 0;
foo(&i);
}
pub fn foo(i: *i128) void {
i.* += 1;
std.debug.print("i: {d}\n", .{i.*});
@call(.always_tail, bar, .{ i, 10 });
}
pub fn bar(i: *i128, _: i32) void {
i.* += 1;
@call(.always_tail, foo, .{i});
}
The compiler will produce the following error:
src/main.zig:11:5: error: unable to perform tail call: type of function being called 'fn (*i128, i32) void' does not match type of calling function 'fn (*i128) void'
@call(.always_tail, bar, .{ i, 10 });
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.zig:16:5: error: unable to perform tail call: type of function being called 'fn (*i128) void' does not match type of calling function 'fn (*i128, i32) void'
@call(.always_tail, foo, .{i});
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I understand why the compiler does this: taking x86 as an example, the return address is next to the parameter when the function is called. If their parameters are different, the value of the return address may be overwritten.
Due to the requirements of my project, I need to achieve a similar effect as above: with different parameters, and tail recursion calls each other.
How should this be implemented in zig? Do you have any suggestions?