In case it slipped your memory, what I've been trying to do is define an
infix operator & such that:
(f & g)(...)
means:
g gets its arguments, f gets its arguments, f runs, g runs
And to do this I wanted a function get_results such that
get_results( p )
returns a list of the results of running p.
The problem centred around not knowing how many arguments p would take off the
stack at any one time, and pdnargs is not to be trusted. Here at last is a
solution.
The gist is as follows. Move the stack into a list "thestack". Then one by one
put things from this list back on to the stack. At each stage, try running p.
If it throws a STACK EMPTY mishap, then you need to try more arguments. If
not, then you've done it. Make a new list out of the results on the stack and
throw the remnant of "thestack" back on to the stack. (The word "elegant" does
not exactly leap to mind...)
So first we have a function try(p) which returns false if p throws a STACK
EMPTY error when run, otherwise p is run and true is returned.
;;; returns false if stack empty error, true if successful
define try( p );
define prmishap(s, l);
if issubstring('STACK EMPTY', 1, s ) then
false;
exitfrom( try );
else
sysprmishap( s, l );
endif
enddefine;
p(); true;
enddefine;
Now we can do get_results, using "thestack" to store all potential arguments
and iteratively putting them onto the stack in the correct order:
define get_results( p ) -> list;
lvars p list thestack item n flag i j;
stacklength() -> n;
conslist( n ) -> thestack; ;;; store the stack somewhere
true -> flag;
for i from 0 to n do ;;; i is number of args to try
clearstack();
for j from n-i+1 to n do ;;; j indexes the top i args
thestack(j);
endfor;
try(p) -> flag;
quitif(flag);
endfor;
unless flag then ;;; it's a genuine underflow
mishap('STACK UNDERFLOW', [^p]);
endunless;
conslist( stacklength() ) -> list; ;;; this is the answer
explode( allbutlast(i, thestack) ); ;;; throw remnant back
enddefine;
And finally we can do the & operator with ridiculous ease:
define 5 &( f, g );
lvars f g;
procedure();
lvars g_results;
get_results(g) -> g_results;
f();
explode( g_results );
endprocedure;
enddefine;
And now you can use & at your leisure and convenience!
Jon Rowe
|