Stack manipulation

This chapter is a primer on how to use the language's facilities to shuffle values around on the stack.

Instructions used in this chapter

SymbolNameBrief
ddupDuplicate the top group on the stack.
ppopDiscard the top value on the stack.
fflipSwap the top two groups on the stack.
^yankDuplicate the second group from the top of the stack.
&groupConcatenate the top two groups on the stack.
_underRun some code "under" the group on top of the stack.
lliftRun separate blocks on the same arguments and push both the results.

Basics

If you've used any stack-based language before, you'll be expecting these mainstays.

Duplicate a value (Forth's DUP):

1d
> 1 1

Get rid of one (Forth's DROP):

1p
>

Flip the top two (Forth's SWAP):

1 2f
> 2 1

Duplicate the second from the top (Forth's OVER):

1 2^
> 1 2 1

We're missing some common choices from Forth, which we'll address in the next section.

Temporary groups

It is sometimes convenient to use stack utilities on multiple values at once, treating them like a "group" of consecutive values. This can be done with & (group), which joins values together into larger groups that can be as large as you want.

1 2& 1 2 3&&
> 1&2 1&2&3

When an instruction refers to "groups" instead of "values" in its documentation, it means it will treat these groups specially:

1 2&d
1&2 1&2

Any other instruction will simply dissolve the group entirely when it needs a value from it.

1 2 3&&4+
> 1 2 7

We can use this to replicate some other Forth words, like ROT:

1 2 3&f
> 2&3 1

Dipping

The last 2 tools included for the stack take blocks. The first is _ (under; often called dip in other languages), which pops a group, executes the block, and pushes the popped group again. This lets you work lower on the stack, leaving higher values as they are.

1 2 3_+
> 3 3

We can finally emulate 2SWAP:

1 2 3 4&_&`f
> 3&4 1&2

Lifting

l (lift) takes two blocks, executes the second one, pops a group, rewinds to before it ran, runs the first block, then pushes the group that was popped from the first branch. It sounds complicated, but all it really does is let you execute multiple functions on the same input and get both results:

3 3l+}*
> 6 9

Here we use it to compute both \(3 + 3 = 6\) and \(3 * 3 = 9\) without having to duplicate the inputs. This enables idioms reminiscent of a fork in APL or Haskell's liftA2 function (when specialized to the (->) r functor), for which the instruction is named.