Ordinary Arc wouldn't need such a macro, since the system I describe isn't purely hyper-static.
---
"The way I understand it, the compiler would create a box for oddp the way an actual binding using var would have, but this box would be empty as it were."
Yes, exactly.
---
"One problem though is what happens when you try to redefine evenp in terms of a new oddp. Without having a way to remove the old bindings of evenp and oddp, this seems to be impossible. One of them will continue to use the old definition of the other no matter what order you define them."
You don't change the bindings. You mutate the box using "=". The box itself stays the same, it just has a different value at runtime.
So if you want to change oddp in such a way that evenp notices the changes, you would say this:
(= oddp ...)
And if you want to change oddp in such a way that evenp doesn't notice the changes, you would say this:
(var oddp ...)
In fact, that's how Nulan defines self-recursive and mutually-recursive functions. Using Arc syntax, this:
(def foo () ...)
Would get macroexpanded into this:
(var foo)
(= foo (fn () ...))
Notice that it first creates the box, and then assigns to it.