HP Forums

Full Version: DOSUBS with binary operations
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
In an older thread I stumbled upon the following program:
Code:
\<<
  DUP HEAD +
  :: CROSS DOSUBS
  \GSLIST ABS 2 /
\>>

Compared to my original program I noticed that \<< CROSS \>> can be replaced by :: CROSS:
Code:
\<<
  DUP HEAD +
  2 \<< CROSS \>> DOSUBS
  \GSLIST ABS 2 /
\>>

But then I noticed that also 2 was missing.
This surprised me since I wasn't aware that the frame index could be omitted.
It turns out that this doesn't work for :: DROP but only with operations that operate on two objects like :: + or :: ^.
Furthermore, it also works when these operations are wrapped within a code object like \<< CROSS \>>.

However, the following doesn't work:
Code:
{ 0 1 4 9 16 25 }
\<< SWAP - \>>
DOSUBS

We get:

DOSUBS Error:
Invalid User Function


But we can use:
Code:
{ 0 1 4 9 16 25 }
\<< \-> u v \<< v u - \>> \>>
DOSUBS

Or then of course:
Code:
{ 0 1 4 9 16 25 }
2
\<< SWAP - \>>
DOSUBS

Which returns the expected result:
Code:
{ 1 3 5 7 9 }

Please excuse my ignorance but is this behaviour described in the manuals?
At least in the HP 48G Series User's Guide I couldn't find anything.
Or is it just folklore like the null-tag trick?



Addendum:

It also works for more than two arguments as long as they are declared:
Code:
{ 1 2 3 4 5 }
\<< \-> u v w \<< u v + w * \>> \>>
DOSUBS

The result is:
Code:
{ 9 20 35 }

It appears to work with DOLIST as well, which is nice.
However, while it works with \<< * \>> it doesn't work with :: *.

We get:

DOLIST Error:
Bad Argument Type

(05-15-2022 11:56 AM)Thomas Klemm Wrote: [ -> ]... This surprised me since I wasn't aware that the frame index could be omitted.
... Please excuse my ignorance but is this behaviour described in the manuals?

Yes, the following is in the DOSUBS section of the 50g's Advanced User's Reference Manual:

HP Wrote:The real number n can be omitted when the first argument is one of the following:
• A command.
• A user program containing a single command.
• A program with a user-defined function structure.
• A global or local name that refers to one of the above.
That was quick!
Thanks for your reply.

For some reason I didn't think to consult the documentation for the HP-50g as well:
Quote:The number of lists, n, can be omitted when the first or level 1 argument is any of the following:
• A command.
• A program containing exactly one command (e.g. « DUP »)

Meanwhile I tried the example \<< DUP \>> with DOLIST and it doesn't work:

DOLIST Error:
Wrong Argument Count


However the following works:
Code:
{ 1 2 3 4 5 }
1
\<< DUP \>>
DOLIST

And we get the expected:

{ 1 1 2 2 3 3 4 4 5 5 }

The following also works:
Code:
{ 1 2 3 4 5 }
\<< -> u \<< u DUP \>> \>>
DOLIST

So HP-48G and HP-50g seem to behave slightly differently.
And you can consider me one of today's lucky 10,000.
(05-15-2022 11:56 AM)Thomas Klemm Wrote: [ -> ]Addendum:

It also works for more than two arguments as long as they are declared:
Code:
{ 1 2 3 4 5 }
\<< \-> u v w \<< u v + w * \>> \>>
DOSUBS

The result is:
Code:
{ 9 20 35 }

It appears to work with DOLIST as well, which is nice.
However, while it works with \<< * \>> it doesn't work with :: *.

We get:

DOLIST Error:
Bad Argument Type


Yes, another amusing inconsistency between DOSUBS and DOLIST. DOSUBS allows null-tags but DOLIST does not. You can however use :: * DTAG DOLIST which has a slight speed advantage at the cost of obscurity.

The HP49/50 libraries ListExt and GoferLists can use programs, lists or null-tags for (AFAIK) all higher-order functions, and lists and null-tags make programs smaller in bytes and almost always faster. One can wish that DOLIST, DOSUBS and STREAM would be able to use all three forms but unfortunately we're stuck with what we have, especially for the 48G.
(05-15-2022 06:27 PM)John Keith Wrote: [ -> ]You can however use :: * DTAG DOLIST which has a slight speed advantage at the cost of obscurity.

I was running:
Code:
:: DUP
DTAG

And I just got DUP on the stack.
Then I ran TYPE on it to get 19 which means:
Built-in command

Or then with * I got 18 which means:
Built-in function

Somehow I've always thought that a program (i.e. \<< … \>>) is similar to quote (or ') in Lisp.
But as it turns out, we can do the same by adding an empty tag to a built-in function or command and then removing it again using the DTAG command.
In both cases the immediate execution is postponed, which is what we want.

Thanks for your explanation: that was enlightening.
Reference URL's