Arc Forumnew | comments | leaders | submitlogin
2 points by akkartik 4478 days ago | link | parent

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.