Control Structures

Control Structures define how a sequence of expressions is evaluated

Overview

The flow of a program is controlled by control structures. Control structures are expressions that define how a sequence of expressions is evaluated.

There are three kind of control structures:

  • Sequential: Block, the most common where expressions are evaluated one after the other
  • Conditional If or Which, where expressions are evaluated depending on the value of a condition
  • Iterative Loop or FixedPoint, where expressions are evaluated repeatedly

Sequential Control Structure

Block

["Block", expr-1, …expr-n]

A ["Block"] expression is a sequence of expressions that are evaluated sequentially.

A new scope is created for the ["Block"] expression. The scope is destroyed when the ["Block"] expression is finished evaluating. This means that variables defined in the ["Block"] expression are not accessible outside of the ["Block"] expression.

The value of the ["Block"] expression is the value of the last expression expr-n.

If one of the expression in the block is a ["Return"] expression, a ["Break"] expression or a ["Continue"] expression, no more expressions are evaluated and the value of the ["Block"] is this expression.

["Block"] expressions can be nested as necessary.

["Block", ["Assign", "c", 5], ["Multiply", "c", 2]]
 
 
// ➔ 10

Conditional Control Structure

If

["If", condition, expr-1]

If the value of conditionis the symbol True, the value of the ["If"] expression is expr-1, otherwise Nothing.

["If", condition, expr-1, expr-2]

If the value of conditionis the symbol True, the value of the ["If"] expression is expr-1, otherwise expr-2.

Here’s an example of a function that returns the absoluve value of a number:

["Function", ["If", ["Greater", "n", 0], "n", ["Negate", "n"]], "n"]

["If"] expressions can be nested as necessary.

Which

["Which", condition-1, expr-1, …condition-n, expr-n]

The value of the ["Which"] expression is the value of the first expression expr-n for which the corresponding condition condition-n is True.

\begin{cases} x & \text{if } x > 0 \\ -x & \text{if } x < 0 \\ 0 & \text{otherwise} \end{cases}
\[ \begin{cases} x & \text{if } x > 0 \\ -x & \text{if } x < 0 \\ 0 & \text{otherwise} \end{cases} \]
["Block",
  ["Assign", "n", -10]
  ["Which", ["Greater", "n", 0], "n", ["Negate", "n"], "n"]
]
// ➔ 10

A ["Which"] expression is equivalent to the following ["If"] expression:

["If", ["Equal", condition-1, "True"], expr-1,
    ["If", ["Equal", condition-2, "True"], _expr-2,
    ... ["If", ["Equal", condition-n, "True"],
          expr-n,
          "Nothing"
    ]
  ]
]

A ["Which"] expression is equivalent to a switch statement in JavaScript or the Which[] function in Mathematica.

Loops

Loop

["Loop", body]

Repeatedly evaluate bodyuntil the value of bodyis a ["Break"] expression, or a ["Return"] expression.

  • ["Break"] exits the loop immediately. The value of the ["Loop"] expression is the value of the ["Break"] expression.
  • ["Return"] exits the loop and returns the value of the ["Return"] expression.

To exit the loop, a ["Break"] or ["Return"] expression must be evaluated.

Loop with only a body argument is equivalent to a while(true) in JavaScript or a While[True, ...] in Mathematica.

["Loop", body, collection]

Iterates over the elements of collection and evaluates body with an implicit argument _ whose value is the current element. The value of the ["Loop"] expression is the value of the last iteration of the loop, or the value of the ["Break"] expression if the loop was exited with a ["Break"] expression.

["Loop", ["Print", ["Square", "_"]], ["Range", 5]]
// ➔ 1 4 9 16 25
["Loop", ["Function", ["Print", ["Square", "x"], "x"]], ["Range", 5]]
// ➔ 1 4 9 16 25

Loop with a body and collection to iterate is equivalent to a forEach() in JavaScript. It is somewhat similar to a Do[...] in Mathematica.

FixedPoint

["FixedPoint", body, initial-value]

["FixedPoint", body, initial-value, max-iterations]

Assumes bodyis an expression using an implicit argument _.

Apply bodyto initial-value, then apply bodyto the result until the result no longer changes.

To determine if a fixed point has been reached and the loop should terminate, the previous and current values are compared with Equal.

Inside body, use a ["Break"] expression to exit the loop immediately or Return to exit the enclosing ["Function"] expression.

Controlling the Flow of Execution

To exit a function, use Return.

To control the flow of a loop expression, use Break and Continue.

Return

["Return", value]

Interupts the evaluation of a ["Function"] expression. The value of the ["Function"] expression is value.

The ["Return"] expression is useful when used with functions that have multiple exit points, conditional logic, loops, etc…

Here’s a contrived example of a function that returns the sign of a number:

[
  "Function",
  [
    "Block",
    ["If", ["Greater", "x", 0], ["Return", 1]],
    ["If", ["Less", "x", 0], ["Return", -1]],
    0
  ],
  "x"
]

Break

["Break" ]

["Break", value]

When in a loop exit the loop immediately. The final value of the loop is valueor Nothing if not provided.

Continue

["Continue" ]

["Continue", value]

When in a loop, skip to the next iteration of the loop. The value of the iteration is value or Nothing if not provided.