[stack] stackless fixed-arity concatenative languages

John Nowak <[email protected]>
Newsgroups gmane.comp.lang.concatenative
Message-ID <[email protected]>
In some languages, such as Haskell, all functions consume a fixed  
number of arguments and produce a fixed number of arguments.* For  
example, the 'foldr' function in Haskell always consumes three values  
and produces one. In fact, all functions in Haskell produce one value.

Concatenative languages like Joy expand on this; functions are not  
restricted to returning only one value.** For example, 'dup' consumes  
one value and produces two. We'll say 'dup' has a 1/2 arity; 'pop'  
would have a 1/0 arity, '+' would have a 2/1 arity, 'swap' would have  
a 2/2 arity, and so on.

However, some functions in Joy go beyond this. For example, 'i'  
essentially takes the entire state of the program as an argument and  
yields a new state. Because 'i' simply invokes the quotation on the  
top of the stack, there's no way to tell how many values 'i' will  
consume or produce without knowing what's on top of the stack. Other  
examples of such functions include 'dip' and 'while'.

One downside of such functions is that it becomes impossible to  
efficiently compile a language like Joy to C; you have no choice but  
to make use of a stack (or some equivalent mechanism) in the  
implementation. In contrast, a concatenative language with only fixed- 
arity functions can be efficiently compiled to C without any need for  
a stack. An example of such a language is Forth without n-ary words  
like 'roll' and with the modest restriction that both branches of a  
conditional must have the same stack effect. [1][2]

It seems the way to do this for a language like Joy would be to find  
alternatives for functions like 'i' and add a type system to ensure  
conditional branches are balanced. Ignoring the type system for now,  
it seems one possibility would be to restrict 'i' to simply dequoting  
the quotation on the top of the stack without allowing it access to  
the stack itself. If one wanted the quotation to have access to  
arguments on the stack, they could be partially applied to the  
quotation first. Several versions of 'i' would need to be available to  
indicate how many values will be returned from its use. For example:

    # 'p' is partial application
    # 'i1' indicates that the quotation produces 1 value
    # the result is '7'
    2 [5 +] p i1

Rather than dealing with partial application, a convenient and  
efficient implementation would simply offer a suite of 'i' combinators  
from 0i0 up until 4i4 or so, where the numbers indicate the number of  
values to be consumed and produced.

While this all likely seems to be overly burdensome at first, most  
functions that make use of quotations would not need so many versions.  
For example, 'fold' would only be valid for quotations of arity 2/1,  
and hence only one version would be needed.

Does anyone think such a language would be feasible? What might the  
benefits be? What useful features would be lost?

- John

[1] http://www.complang.tuwien.ac.at/papers/ertl%26maierhofer95.ps.gz
[2] http://www.complang.tuwien.ac.at/papers/ertl96diss.ps.gz

* Yes, all functions in Haskell /really/ take one argument and are  
curried, and yes, there are tricky ways of implementing variadic  
functions, but we'll ignore that for now.

** Yes, all functions are /really/ unary functions of stacks to  
stacks, but we'll ignore that for now.
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.