The descriptive text inside a step can be escaped to executable form. Within those escaped regions you can call other procedures, capture results, loop, and invoke builtin functions.

Escaping to Code

Inline Code

A paragraph describing a procedure or the body of a step can inline code, delimited from the surrounding text by braces, as follows

  • a { character; followed by

  • an expression; followed by

  • a } character.

For example, in an otherwise normal procedure you might find yourself needing to call a function that performs a task outside the Technique langauge:

rescued :

# Get rescued from certain death

Instead of dying unprotected in open space, we will get picked up by
a passing spaceship.

    1.  Measure improbability { calculate() } and
        wonder how to get to the first-class compartment.

Code Block

The entire body of a procedure or scope code can be written as a code block.

red_button :
{
    press('BUTTON')
    display("Please do not press this button again")
}

Expressions

An expression is a statement in a code block that evaluates to a value.

An identifier is the name of a variable, procedure, or function. The rules for identifiers in expressions are the same as was covered in procedure declarations. An identifier must

  • begin with a lowercase letter [a-z]; then

  • any number of additional lowercase letters, digits, or underscores [a-z0-9_]*.

Sequences

An expression can be a single expression, described below, or a sequence of expressions, which is formed using the semicolon

  • an expression; followed by

  • a ; character; followed by

  • another expression;

  • and so on.

This is used when you need to combine multiple expressions into a code inline.

Each line of a code block is also an element of a sequence, but in a code block newlines serve as the separator; semicolons are not required.

The value of a sequence is the value of the final expression in the sequence.

Variables

A variable or bound name is an identifier. They can be cryptic or verbose as your needs require. The Answer could be { a } or { answer }, putting the temperature of your tea in { temp }, and using { probability } for the measure of ambient probability would all be valid variable names.

A bare variable name is a valid expression, whose value is the value of the variable.

Literals

Any value that can be written as a literal in Technique can be used as an expression. So
{ "There's a frood who really knows where his towel is" }, { 6 pints }, and { $(5 pounds) } are valid expressions. Tablet, tuple, and array literals are also valid expressions.

Binding Values

The value of an expression can be bound to a named variable. A binding is made using the tilde character

  • an expression; followed by

  • the ~ binding symbol; followed by

  • a variable name.

A binding by itself does not have the value it captures. The result of evaluating

happiness :
{
    "Small green pieces of paper" ~ money
}

is { () }, unit. To return the value from this procedure, you need to write the variable name as the final element in the sequence. When evaluated,

happiness :
{
    "Small green pieces of paper" ~ money
    money
}

has a result with a value of { "Small green pieces of paper" }.

Invoking Procedures

Another procedure in the document can be invoked, passing control to it and awaiting its result. This can be done as an expression the same way as in descriptive text, writing

  • a < opening bracket; followed by

  • the name of the procedure or Technique being invoked; followed by

  • a > closing bracket.

For example, invoking { <restore_normality> } is always important after using the Infinite Improbability Drive, as is making it work in the first place by making a cup of really hot tea
{ <https://damogran.gov.galactic/heart-of-gold/EntirelyUnlikeTea> }.

An invocation can take parameters if its arity so requires:

  • a ( opening parenthesis; followed by

  • optional arguments, separated by the , comma character; followed by

  • a ) closing parenthesis.

so { <pickup_guys_from_airlock>(2) } or { <traverse_door>('HAPPY', 3) } are also valid expressions.

Executing Functions

The main reason to escape to code is to call functions. Functions are built-in or otherwise provided by the host environment you are running in. A function application expression is

  • the name of the function being called; followed by

  • a ( opening parenthesis; followed by

  • optional arguments, separated by the , comma character; followed by

  • a ) closing parenthesis.

The application { calculate() } calls a function named calculate. It will be an error if the runtime can't find a function by that name to link to.

Like invocations, functions can take parameters according to their arity, so { seq(1, 5) } and { exec("fire-missiles.sh") } are valid expressions. Unlike invocations, function applications always have parentheses when written, even if the argument list is empty.

Statements

Because Technique is otherwise a very free-form language where arbitrary text makes up the bulk of the content, the parser needs a way to be able to tell the difference between the word repeat in a sentence and the keyword {repeat x} indicating a loop. This is achieved by putting the control statement keyword in a code inline.

Statements are not expressions and do not have a value of their own. They create scopes, but they either do not have a value or pass through the value of the inner expression.

Repetition

The repetition control structure is

  • the keyword repeat; followed by
  • an expression.

That expression is then evaluated. Then evaluated again, and so on. This creates an endless loop describing a service, process, or continuously operating machine.

Note that a {repeat x} does not return so it does not have a value.

This control structure is used for documentation and to launch a repeating process. Typically the expression being evaluated is an invocation; that procedure can clearly document the linear and finite process for handling a individual iteration of the process; the procedure calling {repeat x} can be thought of as a wrapper.

Iteration

More practical than an endless loop is a loop which iterates over a list of values. The {foreach x in y} ... {foreach x in y} control structure is for this purpose. It is written as

  • the keyword foreach; followed by

  • a variable name; followed by

  • the keyword in; followed by

  • a list; and then

  • a nested scope that is the body of the loop.

The list being iterated over can be an array literal, the result of a procedure or function, or a variable containing a list.

For example this step:

    1.  Learn the source material
        { foreach book in seq(1, 5) }
            -   Read book { book } of the trilogy.

contains a loop where { book } is populated in turn with each of { [1, 2, 3, 4, 5] }.

Constraints

The final control structure is not a loop but a constraint, {within x}. This is a form of annotation indicating the resource budget that a scope is expected to be complete within. A constraint is formed with

  • the keyword within; followed by

  • a cost indicating the limit; and then

  • a nested scope that is the body so constrained.

For example, persistence should be rewarded in a timely fashion:

    2.  Missiles are aimed at the ship!
        { within 45 seconds }
            @humans
                -   Figure out a way to avoid being blown up.
            @computer
                -   Sing a song.

The example shown here is a time constraint. You can also specify a monetary constraint, or an amount indicating a resource constraint.

The value of the nested scope is passed through as the value of the constraint.

The cost can be a variable, function, literal, or any other expression. A cost literal is most common. A quantity here is interpreted as a cost; the $(...) constructor syntax is not required.

© 2004-2026 Athae Eredh Siniath, and Others. Technique is open source and MIT licensed.