10
2
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).
10
2
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).
3
Forth has two looping constructs, x y do
... loop
, and lesser known [begin]
... [until] x y
where x
and 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.
3
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.
2
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 gforth
.
1
This includes double-cell arithmetic, bitwise, number comparison and stack manipulation words. Double-cell integer literals also count.
1.
) gives a double-cell literal. For small numbers, it means pushing an extra zero at the cost of only one byte.m+
= 0 d+
~= under+
(not exactly, since overflow may occur.)d2*
and 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
2dup
, 2over
, 2tuck
have a good chance to win over local variables.1
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 ROT
, -ROT
, 2DUP
, 2OVER
, etc...
0
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).
f
prefix, as in f+
, fdup
etc.). 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. 1e3
instead of 1000
).1+
and 1-
.f**
(power), falog
(power of 10), fsqrt
, and various exp, log, trigonometry-related ones.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.