[stack] utility of the retain stack

John Nowak <[email protected]>
Newsgroups gmane.comp.lang.concatenative
Message-ID <[email protected]>
Hello all. One of the problems I've run into with a second-order  
language is that you don't get partial application. (I've recently  
been able to extend the intersection-based type system to a higher  
order language, so this second-order restriction may not last anyway.)

Essentially, the problem is something like this. Let's say I want to  
write a function that has this effect:

    ('a0 .. 'aN) 'x -> ('a0 F 'x G .. 'aN F 'x G) 'x

In other words, given a list of objects 'a0 to 'aN and some object 'x,  
we want to map over the list applying some function F to each element,  
followed by applying G with 'x on the stack. We want to keep 'x around  
at the end. An implementation in Cat would look as such:

    pick [[quote [dip] compose] dip compose papply map] dip

We can demonstrate its correctness as follows:

('a0 .. 'aN) 'x [F] [G] pick [[quote [dip] compose] dip compose papply  
map] dip
('a0 .. 'aN) 'x [F] [G] 'x [[quote [dip] compose] dip compose papply  
map] dip
('a0 .. 'aN) 'x [F] [G] [quote [dip] compose] dip compose papply map 'x
('a0 .. 'aN) 'x [F] quote [dip] compose [G] compose papply map 'x
('a0 .. 'aN) 'x [[F]] [dip] compose [G] compose papply map 'x
('a0 .. 'aN) 'x [[F] dip] [G] compose papply map 'x
('a0 .. 'aN) 'x [[F] dip G] papply map 'x
('a0 .. 'aN) ['x [F] dip G] map 'x
('a0 F 'x G .. 'aN F 'x G) 'x

This works fine (there may be an nicer way to write it), but there are  
two problems. One, it's too complicated. The same thing with named  
variables (i.e. naming 'x and lifting it into the function) is *much*  
more direct (where \ is a lambda of sorts):

('a0 .. 'aN) 'x \y. [F y G] map
('a0 .. 'aN) [F 'x G] map
('a0 F 'x G .. 'aN F 'x G) 'x

Two, there's no way to do it in a second order language as we're  
relying on higher order functions.

The solution seems to be to introduce a retain stack a la Forth (and  
Factor). Here, we indicate the value of the retain stack by placing it  
to the right of the dot. '+r' copies the top element of the retain  
stack to the data stack:

('a0 .. 'aN) 'x >r map[F +r G] r>
('a0 .. 'aN) map[F +r G] r> . 'x
('a0 F +r G .. 'aN F +r G) r> . 'x
('a0 F 'x G .. 'aN F 'x G) r> . 'x
('a0 F 'x G .. 'aN F 'x G) 'x

It's worth nothing here that we can only evaluate as such because  
we're assuming F, G, and map do not alter the retain stack. This is  
something a compiler could easily enforce by tracking the retain stack  
on the type level and disallowing named functions or arguments to a  
combining form from using elements already on the retain stack at the  
time they're called. An annotation could be used to bypass this  
restriction.

Considering how much simpler this is than the version without the  
retain stack, I'm wondering if Joy and Cat are missing something by  
not offering that second stack. Here's how the retain stack version  
might work in Joy:

('a0 .. 'aN) 'x r> [F +r G] map r>
('a0 .. 'aN) [F +r G] map r> . 'x
('a0 F +r G .. 'aN F +r G) r> . 'x
('a0 F 'x G .. 'aN F 'x G) r> . 'x
('a0 F 'x G .. 'aN F 'x G) 'x

Any thoughts or am I just rambling?

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