Skip to content

Tutorial I: a stack based language

Conor O'Brien edited this page Dec 21, 2016 · 1 revision

Not your average programming language

If you are used to programming in any popular language, then the stack-based or stack-oriented memory model will surely come as a surprise, more or less. A stack in the most broad sense is an array containing data. Stacked uses a stack instead of an expression model (e.g. a = 1 + 2). For a stack-based language, the information is "pushed" to the stack, after which operators can consume such information from the stack. The idea of working with a stack instead of infix operations is most likely foreign to a programmer. In fact, the very idea of a stack-based language may seem ridiculous if it is to have a purpose, or some may say. I am currently writing An Apology for Stack-Oriented Languages, a small-ish document intended to provide a rationale for such a memory model (as of 12/20/2016). A main point is that programming is pretty foreign upon first glance, but becomes more "readable" as you use the language more--that is, immediate and surface "unreadability" is more of a criticism of one's lack of desire to understand versus knowledge. However, if you cannot stand using this language without (or even with) an expanded rationale, then the metaphorical door is open to you to leave.

Now, I will first provide some equivalent programs so that you can get a feel for what the language looks like.

Hello, World!

'Hello, World!' out

Okay, so that's your first taste! Simple enough--'Hello, World!' pushes that string to the stack, and out pops it from the stack.

Variable declaration

3.14 @foo
5 @bar
foo bar * out   (* 15.7 *)

This code is equivalent to the following python code:

foo = 3.14
bar = 5
print(foo * bar)  # 15.7

That is to say, @<x> sets variable <x> to the top of the stack, consuming it. So, foo is set to 3.14, and bar to 5. Then, foo and bar push their respective values (3.14 and 5), and * multiplies them together, finally being outputted by out. Last, (*...*) is a comment.

Fisher-yates algorithm for shuffling a list.

{ arr :
  arr size @n
  { i :
    i n .. randin @j
    arr i j exch @arr
  } 0 n 2- for
  arr isolate
} @:shuf

Or, if you prefer a visual representation:

the above program, prettified

There's a lot going on in this program. Let's talk about the outermost structure:

{ arr :
  (* ... *)
} @:shuf

This creates a lambda that takes a single argument from the stack, names it arr, and defines the resulting function as shuf. The @: token allows shuf to be used as a built-in function.

  arr size @n

This sets the variable n to be the size of arr.

  { i :
    (* ... *)
  } 0 n 2- for

This iterates from 0 to n-2 inclusive, applying the code block preceding, for each integer in the said range. The counter is named i.

    i n .. randin @j
    arr i j exch @arr

This part creates a range from i to n, right exclusive. randin selects a random member in this range, and sets it to j. Then, on the next line, indices i and j are exchanged in arr, and the array is updated. This is the fisher-yates algorithm implemented in stacked, and is in fact how it is internally defined.