Quoting
As shown in the previous chapter, the syntax of tourniquet is
quite simple: a function is defined by its name, followed by :=
, followed by
a sequence of functions (the functions being separated by
whitespace), and finally
ended with a semicolon (;
).
But there is an additional bit of the syntax that we must address: quoting. The
only way in which round
brackets/parentheses ((
,
)
) are used in tourniquet is for quotation. Wrapping a sequence of zero or
more functions inside of parentheses results in the sequence itself being
pushed onto the top of the stack. This effectively creates an anonymous
function, and then pushes it
onto the stack.
Quoting is important for some purposes. For example, there is a built-in
function called if
that serves the same purpose as “if” statements in other
languages — that is, it allows for conditional execution. Say that we
wanted to define a function similar to add_one
(defined in the previous
chapter), but have it only add one when the other summand is
odd. That way, the resulting integer is always even. We could do that like so:
make_even := dup 2 % 0 = () (1 +) if;
And we could visualise the application of this function like so, assuming that we start with 3 on top of the stack:
┄┄┄┲━━━┓
… ┃ 3 ┃
┄┄┄┺━━━┛
↓ dup
┄┄┄┲━━━┳━━━┓
… ┃ 3 ┃ 3 ┃
┄┄┄┺━━━┻━━━┛
↓ 2
┄┄┄┲━━━┳━━━┳━━━┓
… ┃ 3 ┃ 3 ┃ 2 ┃
┄┄┄┺━━━┻━━━┻━━━┛
↓ %
┄┄┄┲━━━┳━━━┓
… ┃ 3 ┃ 1 ┃
┄┄┄┺━━━┻━━━┛
↓ 0
┄┄┄┲━━━┳━━━┳━━━┓
… ┃ 3 ┃ 1 ┃ 0 ┃
┄┄┄┺━━━┻━━━┻━━━┛
↓ =
┄┄┄┲━━━┳━━━━━━━┓
… ┃ 3 ┃ false ┃
┄┄┄┺━━━┻━━━━━━━┛
↓ ()
┄┄┄┲━━━┳━━━━━━━┳━━━━┓
… ┃ 3 ┃ false ┃ () ┃
┄┄┄┺━━━┻━━━━━━━┻━━━━┛
↓ (1 +)
┄┄┄┲━━━┳━━━━━━━┳━━━━┳━━━━━━━┓
… ┃ 3 ┃ false ┃ () ┃ (1 +) ┃
┄┄┄┺━━━┻━━━━━━━┻━━━━┻━━━━━━━┛
↓ if
┄┄┄┲━━━┓
… ┃ 4 ┃
┄┄┄┺━━━┛
dup
is a built-in function that duplicates the value that’s on top of the
stack. %
is a built-in function that performs the modulo
operation, using the same
nomenclature as other languages like C, Python,
Rust, etc. And, as mentioned before, sequences of
functions can possibly be empty (i.e. length of zero), so ()
represents a
quotation of the identity
function (the function that
does nothing to the stack).
Finally, the built-in function if
consumes the top three values on the stack.
The bottom such value is a
boolean value that
determines whether the first function (if it’s true
), or the second function
(if it’s false
), is applied. The middle such value is the first function, and
the top such value is the second function.
app
Closely related to quotation is the built-in function app
. app
is short for
apply, which means that it simply
applies the function that is on top of the stack. The most clear way to see how
app
works is to observe that the following two functions are equivalent
(using the same example from the previous chapter):
add_one := 1 +;
add_one' := (1 +) app;