Counting Apples
The flexibility of implicit functional calls in forth
2021-07-30
There is an example from Thinking Forth that resonated with me that I would like to document here.
It showcases how implicit calls and implicit data passing make Forth a uniquely flexible and expressive language.
About Retro
This markdown file is a valid retro program written in the literate style.
Here are some ways to interact with it:
read it with your eyes
you can run it with
retro apples.md
. This will execute everything between~~~
triple tilde fences. (It wonāt do anything.)run the tests with
retro -t apples.md
. This will execute everything between triple backtick fences.Open up the repl by typing
retro
and then type'apples.md include
. Now play around.
Learn more:
Counting apples
Look, we know we have some apples. But how many! We obviously need to write a little forth program to keep track.
Hereās a variable:
'apples var
The word apples
returns an address.
You can write to it and read from it:
#20 apples store
apples fetch
'There_are_%n_apples s:format s:put nl
Thatās it, life is easy counting apples.
Now letās write a word to increment your apples count by a bunch:
:dozens (-n) #12 apples v:inc-by ;
Now you can count them apples so fast! Apples by the dozens!
dozens
apples fetch
'Twelve_more_is_%n_apples s:format s:put nl
Kinds of apples
Uh oh, a requirements change! It is no longer sufficient to merely keep track of apples.
Now we must keep a tally of both green apples and red apples!
Thatās okay. Remember, apples
just returns an
address.
First, we need some new variables:
'reds var
'greens var
reds
and greens
will be our new tally
counts. One for each color.
Now, a bit of indirection:
'color var
A new variable. color
will be a pointer to whichever
color (reds or greens) we are currently tallying. This word will operate
mostly behind the scenes. Itās kind of glue.
Look, here come some verb words:
:red @reds !color ;
:green @greens !color ;
red
stores the reds
total at the
color
address. green
does the same for
greens
.
Now, to fix our apples
var with a final bit of glue:
:apples color ;
apples
is no longer a variable, but instead a word
(function) that now returns the address of color. Which in turn holds
the value of reds
or greens
, depending.
apples
still just returns an address. Nothing has broken in
our code. You can continue to use it the same way.
Our code from above?
#20 apples store
apples fetch
nl 'Guess_what,_still_%n_apples s:format s:put nl nl
Still works.
Now you can store tallies in greens
and
reds
:
#10 !reds
#20 !greens
and fetch the individual totals:
red apples fetch dup
'%n_red_apples s:format s:put nl
green apples fetch dup
'and_%n_green_apples s:format s:put nl
+ #30 eq?
[ 'are_30_apples s:put ]
[ 'That_dont_add_up s:put ]
choose
nl nl
and our previous apples dozener?
:dozens (-n) #12 apples v:inc-by ;
Yeah that still works too:
apples fetch
'%n_red_apples s:format s:put nl
dozens apples fetch
'plus_12_more_equals_%n s:format s:put nl
Conclusion
Forthās implicit function calls allow you to change words from variables to functions and vice versa, possibly without having to change any existing code.
Because Forth also has implicit data passing: you donāt have to pass data to functions or actively handle return values. Everything goes on the stack.
And I think thatās neat.