This is an interesting idea and probably Casette.jl or IRTools.jl is the best way to solve it.
On the other hand, to some extent it can be solved with usual macros (sorry, I am just thinking aloud, not sure if its doable in reality).
Idea is that your code roughly equivalent to
world # pointer to something interesting and contextual
value # just a Float64 perhaps
let world = "hello"
mkFoo(x) = Foo(world, x)
i.e. if we create closure inside
let block, than we are good to go. Of course, your example use function declaration outside of
let block, in which case you can’t declare closure.
What can be done, is “storing” closure declaration somewhere and applying it afterwards, so for the end user, it looks like
@with_context world mkFoo(x) = Foo(world, x)
@in_context world = World(...) begin
x = mkFoo(3)
y = mkFoo(5)
@in_context should generate these lines
let world = World(...) begin
mkFoo(x) = mkFoo(world, x) # substitute from @with_context declaration
Of course, it’s very quickly became rather complicated: what should we do if we have more than one context? How can we decide which functions to use? And what can we do with nested
So it looks like that building full scaled implementation in this approach is too complicated, but limited versions could exist.