[stack] concatenative lexically-scoped polymorphic mutable variables

John Nowak <[email protected]>
Newsgroups gmane.comp.lang.concatenative
Message-ID <[email protected]>
Recently, I had been working on a problem in 5th. Because 5th is a  
linear language, it is impossible for any object to be referenced more  
than once (by definition). One problem this creates, amongst many, is  
that global variables cannot be efficiently implemented. The reason is  
that accessing a global variable either requires that it be copied,  
which may be expensive, or requires temporarily removing it, which is  
unsafe as an attempt to fetch it again before it is restored will  
cause an error. Neither is acceptable.

One way of solving this problem is to allow global variables to be  
removed, but to also keep track of this on the type level. This is  
implemented by passing an extensible record on top of the stack (or on  
the side of the stack -- whichever sounds nicer to you). A "push"  
function can be used to push an object into a particular "slot" in the  
record provided that the slot is currently empty. A "pull" function  
can be used to remove an object from a slot provided that the slot is  
currently full. These slots are polymorphic in the sense that objects  
of different types can inhabit the same slot at different times  
throughout the program.

If this is taken to its logical conclusion by allowing slots to hold  
multiple values, and by adding a bit of type system magic to ensure  
that only the most recently bound object in a slot can be manipulated  
until the point of the introduction of that pseudo-binding returns  
(which is doable), you end up with a type-safe form of dynamic  
scoping. This is not particularly interesting as I believe it is  
already well-known that dynamic scoping is compatible with  
concatenativity. (It may, however, be interesting that this is  
relatively easy to handle in terms of type inference.)

What is perhaps a new realization is that this approach gets you  
lexical scoping as well. This is doable by generating unique names for  
the lexical pseudo-variables in a particular definition. Because the  
names are unique, other functions will be unable to access the slots.  
5th's disallowing of recursive definitions is critical here as well as  
it prevents the slots from getting clobbered before the they are  
removed and discarded. Since the types of the slots are carried  
individually in the type system, mutating these slots can be done in a  
manner that is type-safe, even if the type associated with a  
particular slot changes within a definition.

In a non-linear variant of 5th, we could employ the same system but  
disallow updating or removing values from slots. This would give us  
variables that work as if they were implemented via substitution.  
However, substitution is not actually necessary as the fetching of a  
"variable" can be delayed until the function that fetches an object  
from a particular slot is called. Because substitution is avoided, the  
language remains a concatenative (albeit with rather fancy namespace  
control). The big bonus here is that you get a dual view of the  
semantics; you can look at it either from the perspective of term  
rewriting and substitution or via the perspective of function  
composition. This has led me to consider dropping linearity as this is  
just too pretty.

There are a few restrictions on all this. As already indicated, the  
language must not allow recursion. (Actually, tail recursion is  
allowable.) Additionally, the language must not have first class  
functions as the pseudo-variables cannot be closed over. Finally,  
special care must be taken for things like callback functions. In  
particular, the type system must ensure that the function given does  
not reference any slots meant to be used to emulate lexical scoping.  
This is straightforward to enforce.

This email is really about 10 pages shorter than it should be. If  
anyone managed to follow along, or would like clarification, I'd be  
happy to respond.

- John
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.