Arc Forumnew | comments | leaders | submitlogin
2 points by dido 4313 days ago | link | parent

Pauan, although I disagree with you on precisely how the hyper-static scope primitives should be used to create an actual module system, the idea seems to be general enough that it might actually be worth implementing in Arcueid in more or less the manner which you describe. The only problem I have is what happens with forward references, e.g. such as arise with mutual recursion. To go with the classic example of mutual recursion:

  (def evenp (x) (if (is x 0) t (oddp (- x 1)))
  (def oddp (x) (if (is x 0) nil (evenp (-x 1)))
Without a special operator, it seems impossible to define something like this in pure hyper-static scope. With the sort of hybrid hyper-static scope you envision, what would compiler do if it got this sort of definition?

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. If no subsequent definition of oddp followed, that would result in an unbound free variable error at runtime when evenp was used, exactly the way the reference Arc implementation would. If oddp were defined, however, it would then fill in the empty box that the reference to it in evenp created, and so the call to oddp would make use of the first definition of evenp that followed it, just as a non-hyper-static system would. Subsequent definitions of oddp using var would have no effect on evenp though, unless evenp were redefined.

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.



1 point by Pauan 4313 days ago | link

"Without a special operator, it seems impossible to define something like this in pure hyper-static scope"

Nulan uses a very simple "defs" macro for this:

http://arclanguage.org/item?id=17449

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.

-----