[stack] adding construction to Joy-like languages

John Nowak <[email protected]>
Newsgroups gmane.comp.lang.concatenative
Message-ID <[email protected]>
This may be more of a post-holiday brain dump than anything  
interesting. If so, just ignore.

One of the things I really like about FP is the functional form of  
construction. I've mentioned this in earlier emails, but here's a  
quick summary:

   Here's a construction involving three functions:

     [f, g, h]

   Applying (denoted ':') the construction to a value works as such:

     [f, g, h]:x  ==  <f:x, g:x, h:x>  -- angle brackets denote a list

In short, construction is very similar to the cleave combinators in  
Factor. Unfortunately, the cleave combinators are not nearly as  
convenient as construction for a number of reasons:

1. The single form of construction handles any number of inputs and  
outputs properly. In contrast, a family of cleave combinators is  
needed. Factor has "smart combinators" that rely on the types of the  
functions involved to get around this, but they're quite awkward in  
comparison to FP's approach.

2. FP has functions which, given a list, return a single element from  
that list. Factor has no way (that I know of) to index into a stack  
returning only the element selected.

3. FP uses lists to group more than one element. As such, you can do  
something like '[sq, dup]:5' to get '<25, <5, 5>>'. Emulating this  
behavior is nearly impossible in Factor because all values are carried  
inside a stack. As such, you must either return a flat stack like '25  
5 5' (which is what '[sq] [dup] bi' would do) or return all stacks  
independently like '{25} {5 5}' which makes getting at the values  
painful. I've mentioned this problem earlier but I'm not sure if I'm  
explaining it adequately.

The solution I propose has four parts:

1. Replace the stack with a vector in the style of More's array  
theory. Here, a vector containing a single element is equivalent to  
the element it contains (and vice versa). We'll denote such nestable  
vectors with parentheses, e.g. '1 (2 3)' is a two element vector  
containing '1' and the two element vector '(2 3)'. Note that, as in  
More's array theory, '(1)' is equivalent to '1'. As such, '1 2 3 + *'  
can be written '(1 (2 3 +) *)' without changing the meaning of the  
expression. '()' denotes the empty vector.

2. Add functions for indexing into a vector, e.g. '1 2 3 4 2nd' yields  
'3'.

3. Add a set of functions for grouping values, e.g. '1 2 3 4 2g'  
yields '1 2 (3 4)'.

4. Add a syntax for construction of the form [|f0, f1 .. fN|].

What construction will do for us is take the top value of the vector  
passed to it and apply every function in the construction of N  
functions to it yielding a vector that is the concatenation of the  
vector below the initial value and the N values produced from the  
application. Whew.

Here are some examples:

   1 2 3 [|sq, neg|]  ==  1 2 9 -3  -- works as '3' == '(3)'
   3 4 2g [|+, -|]  ==  7 -1
   5 [|sq, dup, drop|]  ==  25 (5 5) ()
   5 12 [|1st sq, 2nd sq|] +  ==  (5 sq) (12 sq) +  ==  25 144 +  ==   
169

Something marginally more useful:

   discriminant = 3g [|2nd sq, [|1st, 3rd|] * 4 *|] -

Instead of adding a new syntax, we could alternatively offer c2, c3,  
etc, to denote construction over a set number of functions:

   discriminant = 3g [2nd sq] [[1st] [3rd] 2c * 4 *] 2c -

Useful? I'm not sure. The need to group things into a single vector  
all the time means it is still less convenient than the FP version:

   discriminant = - [sq 2nd, * [* [1st, 3rd], 4]]

This is especially if we use an infix syntax (e.g. 'f g h == g:[f,  
h]') like J's monadic hook:

   discriminant = (sq 2nd) - 4 * 1st * 3rd  -- all associate right

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