What general tips do you have for golfing in Forth (and its clones)? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to Forth (e.g. "remove comments" is not an answer).
Avoid explicit loops at all costs
Forth has two looping constructs,
x y do ...
loop, and lesser known
[until] x y where
y are values for limit and index, or conditions to be noted, respectively.
These are very slow, very wordy (haha) and overall rather bloaty, so only use them if you need to.
Instead, like a proper functional language (which Forth is, really), one should prefer recursivity over explicit loops because it tends to be shorter and makes a better use of the language.
Forth has a lot of cool builtin words, many of which are helpful for crafting the sorts of algorithms found on PPCG.
A bad but illustrative example of this are the words for increment (
1+) and decrement (
1-). They save a byte over writing
1 + to increment the top of the stack.
Additonally, here is a handy list of many (probably not all) words found in modern distributions like
Leave the junk
Programs aren't required to be stack-safe.
Instead, they can leave extra junk on the stack if it saves you bytes. In Forth, the "return value" is leaving something on top of the stack. It probably doesn't matter what junk you have below that on the stack unless you're using recursion and stack depth matters.
Watch the stack
When writing your code, pay attention to what happens on the stack at each command. I usually draw it out as I go, like so:
6 6 7 7 6 * DUP 42 42
As you go like this, you may find it easier to recognize when you can make use of stack operations like
(gforth-specific) Utilize the separate floating-point stack
gforth has a separate stack for floating-point numbers. Even if you're only dealing with integers, offloading some work and storage to the FP stack may result in shorter code overall, either by avoiding explicit stack manipulation or using FP-specific operations not available on the main stack. Returning to the FP stack is also a perfectly valid option (except when the task is to return a boolean).
- FP-related operations (arithmetic, stack manipulation) usually cost one more byte each (the
fprefix, as in
fdupetc.). FP number literals also cost one more byte (postfix
e, as in
1e), but some numbers can tie or even save a byte (e.g.
- Some operations are missing on the FP stack, probably the most painful being
- FP stack's unique operations include
falog(power of 10),
fsqrt, and various exp, log, trigonometry-related ones.
- You can move numbers between main and FP stacks via
s>f(single to float),
f>s(float to single),
d>f(double to float),
f>d(float to double). At times, the "double" variations may be used to produce or consume an extra zero.
Try using various double-cell words
- Appending a period on an integer literal (e.g.
1.) gives a double-cell literal. For small numbers, it means pushing an extra zero at the cost of only one byte.
under+(not exactly, since overflow may occur.)
d2/could be used to extract/push one bit from a word.
a b c d d==
a c = b d = and
a b c d d<>=
a c <> b d <> or
- Words that copy two numbers at once, e.g.
2tuckhave a good chance to win over local variables.