Arc Forumnew | comments | leaders | submitlogin
1 point by Pauan 4311 days ago | link | parent

P.S. Another strategy is to use boxes, which is what Nulan does. Using boxes has some extra benefits, including making macros completely hygienic, but I figured it would be easier for you to implement variable renaming.


2 points by dido 4308 days ago | link

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 4307 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.

-----

1 point by dido 4310 days ago | link

If I understand this correctly, it would allow Arcueid's compiler to resolve global variables at compile-time, rather than at run-time. No need for variable renaming. There is currently a genv instruction in Arcueid's virtual machine which basically takes a symbol referring to a global variable and finds its binding in the global environment. If we do hyper-static scope, the genv instruction can be changed to take a reference to the actual global variable instead. Thus, the mappings of symbols to free variables are only required when compiling an expression.

-----

1 point by Pauan 4310 days ago | link

Yes, exactly.

-----