Ah, I solved the infinite loop!! I'm glad I took the time to write this out here.
Let's start with these definitions:
(def foo() 34)
(def bar() (foo))
I'd like to make sure that bar always calls the same foo, even if foo is later overridden.
wart> (bar)
34
wart> (def foo() 35)
wart> (bar)
35 ; Somehow should still return 34
To do so, I save the current binding of foo when bar is defined, and restore it inside the body.
(let $foo foo ; lexical load-time binding
(def bar()
(making foo $foo ; restore foo for the entire dynamic scope of this body
(foo))))
wart> (def foo() 36)
wart> (bar)
34
(making is wart's way of creating a new dynamic binding.)
<rant>
I'm permitting foo to be extended but freezing its definition in a specific call-site. Compare this with racket's approach, which is to freeze the definition of foo and prevent any extensions at all call-sites. Racket's approach is similar to Java's final keyword.
</rant>
I wish I could save this pattern as a macro:
(freezing foo
(def bar()
(foo)))
But freezing would need to 'reach into' its subexpressions. Hmm, I think I can bake this into the implementation of extensible mac. Too bad I won't be able to use stepwise refinement in implementing _that_..
Update: I've fixed mac so :case expressions can't trigger infinite loops: http://github.com/akkartik/wart/commit/a7fb204296. HOWEVER: this commit makes my tests 8 times slower. It's a shattering illustration of how these calls can compound.