Hello,
Is it possible to accomplish dynamic scope in a way that respects tail
calls with luajit?
I've been approximating dynamic scope for a particular algorithm in the
classic set/restore manner:
function withx(x, body)
local oldx = globalx
local result = {body()}
globalx = oldx
return unpack(result)
end
Unfortunately, while simple, this approach evaluates the body function in a
non-tail position. Until now, this wasn't a problem, but I've run in to a
recursive use case which now suffers from stack overflows.
Racket accomplishes dynamic scope via "continuation marks" (see [1] and
[2]) that, if manipulated in tail position, modify a cell in the current
frame, so these "marks" with dynamic extent can be used without affecting
space complexity. The documentation for the "parameterize" macro calls out
the body-in-tail-position behavior explicitly [3].
A blog post [4] suggests that dynamic scope can hack-ily be accomplished
via debug.getlocal, but the specific code posted there is incorrect in the
presence of tail calls (try adding a 'return' to the fn call in run_func).
I suppose Lua 5.2's getinfo with what='t' can return istailcall to
workaround this, but we've gotten pretty far in to hack territory and I'd
like to stay on luajit.
I don't care if the resulting code achieves normal variable syntax or not.
I'm fine with function call syntax to get the current dynamic value.
So to recap: Is there a way in luajit to accomplish tail-call-safe dynamic
scope or otherwise associate per-stack-frame data?
Thanks,
Brandon
[1] https://docs.racket-lang.org/reference/contmarks.html
[2] "Adding Delimited and Composable Control to a Production Programming
Environment" - Flatt, et al.
[3]
https://docs.racket-lang.org/reference/parameters.html?q=parameterize#%28form._%28%28lib._racket%2Fprivate%2Fmore-scheme..rkt%29._parameterize%29%29
[4] http://leafo.net/guides/dynamic-scoping-in-lua.html