[Push] On re-entrant PUSH programs and how prefix is postfix
Maarten
mkeijzer at xs4all.nl
Thu Feb 5 05:03:55 EST 2004
Hi Lee,
> I'm not as sold on the prefix version of Push you've outlined (hsuP?).
To be quite honest, I didn't expect you to be. You might want to decide at
some point if you're a lisp-head or a forth-head though! Personally, I prefer
infix :-/
> Postfix and stacks just seem like a natural pairing to me -- you push
> things on stacks first and then call instructions that operate on
> them... But maybe I have to meditate on your examples some more.
The prefix stuff works nicely for the more functional operations, like
arithmetic. It becomes a bit more awkward for the explicit stack
manipulations, though it's not too bad (I do have to mention I haven't
explored it in depth though). In prefix,
(BOOL.YANK 3 TRUE FALSE FALSE CODE.YANK BOOL.OR FALSE TRUE )
can be interpreted as taking the result of the fourth boolean operation to the
left of the operation. In this case, it would be the OR. For this
interpretation, you do not need stacks. It's a 'regular' lisp program flow
where types are mixed.
The CODE.YANK is there to slightly confuse the issue. If you imagine a CODE.DO
there, it would become a bit more hairy, as you would have to figure out
which code will be executed in the middle and what it's boolean 'return
values' are... In short, though the stacks are still there, the set of stacks
can be considered the 'type' on which each operation works. The OR function
for instance will get a set of lists (the type) as input, take the boolean
list and ORs the first two on the list, returning it together with the other
'unchanged' list. This looks a bit like Peter Martin's polymorphic GP system.
Nothing is lost, nothing is gained. It all boils down to what you're most
comfortable with.
However.
I think the main advantage of prefix lies in the ability to get the most
important code at the front of the list, instead of the back. If you are to
do any kind of arithmetic, in postfix, the most important (root) node will be
at the back of the expression. Given that most code manipulating operators
are lisp-inspired, this back is not as easily accessible as the front. This
might hinder evolution considerably. In the past, I have experimented a bit
with prefix versus postfix in my logic programming approach, and found that
prefix seemed to work better. This is an unpublished 'seemed', so don't take
my word for it. In any case, having the code that produces the final result
to be most easily accessed might be something to consider.
This is a an empirical question though. There are also a few practical
advantages, one is that the idiom 'operate on second element' in the case of
binary functions can be replaced with the more cleaner 'operate on first
element'. I'm assuming that this idiom was introduced for readibililty
purposes, as I think a full postfix interpreter would have nothing of that
kind of thing.
But as I said, it's just a thought, I'm not seriously suggesting to reverse
everything.
-Maarten-
PS. when implementing push I noticed that for an imperative solution, both
SHOVE and YANK are relatively expensive as they induce copying (large) parts
of the stack. I noticed that both can be implemented using the fast SWAPNTH
(take value from the integer stack and swap that nth element with the first).
Maybe add SWAPNTH?
PPS. Another thought: why CODE.FROMBOOLEAN etc., and not simply add a generic
function TOCODE (or simply QUOTE??) ? Saves on the syntax, CODE.TOCODE is a
NOOP, and there is precedence for having TYPE.OP operate on a different stack
than TYPE (TYPE.= pushes on the boolean stack, CODE.NULL, CODE.ATOM, does
that too, not to speak of CODE.SIZE, CODE.POSITION, CODE.LENGTH that operate
on the integer stack.)
PPPS. no stopping me now... just an observation on the reentrant interpreter.
CODE.QUOTE could be called CODE.FROMEXEC, while CODE.DO* could be called
EXEC.FROMCODE... This is not a suggestion for a name change (far from it),
but simply to illustrate the duality between (quoted) code (on the code
stack) and executable code (on the execution stack).
More information about the Push
mailing list