THE NOQERI FIELD GUIDE / FLOW CONTROL

Choose the trail. Lead the flow.

Eleven lessons on decisions, bindings, collection traversal, recursion and guards. Learn how Noqeri moves from one instruction to the next.

Noqeri v0.1.4 developer preview. The examples use typed functions, if/else, arrays, for-in and Boolean operators. Structural case-pattern matching and automatic tail-call optimization are not claimed as implemented.

← THE FULL FIELD GUIDE← FUNCTIONS FIRST

FLOW CONTROL / 01 OF 11

Case expressions

Choose a trail at a crossroads

Programs often need to take one of several paths depending on a value. In Noqeri, use `if`, `else if` and `else` to select a branch. Each condition is checked before the next branch is considered.

let code: int = 1

if code == 0 {
    print("Zero")
} else if code == 1 {
    print("One")
} else {
    print("Other")
}

IMPLEMENTATION NOTE: The current compiler implements conditional branches, not a `case` pattern-matching expression. An explicit final `else` handles values not caught earlier.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 02 OF 11

Variable patterns

Name the value you follow

Bindings let you give a useful name to the value behind a decision. Use `let` inside a branch to hold a value that you want to inspect or pass to another function.

let value: int = 4

if value == 0 {
    print("Zero")
} else {
    let other: int = value
    print(other)
}

IMPLEMENTATION NOTE: `let` and scoped branches are available today. Destructuring bindings inside `case` patterns are not part of the currently implemented parser.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 03 OF 11

String patterns

Listen for the right message

Use string equality when a branch depends on a particular message or command. More complex prefix and substring handling belongs to string-processing helpers rather than a special pattern syntax.

let command: string = "start"

if command == "start" {
    print("Ready")
} else if command == "stop" {
    print("Stopped")
} else {
    print("Unknown command")
}

IMPLEMENTATION NOTE: This lesson demonstrates exact string comparisons. Prefix extraction and string destructuring are not presented as implemented match patterns.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 04 OF 11

List patterns

Find your place in the pack

Arrays let you keep a known set of values together. Read an element by its index and test its value with `if`. Noqeri also has selected growable scalar lists and checked bounds operations.

let scores: [int; 3] = [4, 2, 9]

if scores[0] == 4 {
    print("Starts with four")
}

for score in scores {
    print(score)
}

IMPLEMENTATION NOTE: Fixed arrays and array `for-in` have implementation coverage. Structural list head/tail patterns are not part of the current language contract.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 05 OF 11

Recursion

A trail that calls itself

A recursive function calls itself with a smaller or simpler input. Always give it a base case that returns directly; otherwise recursion may continue until the call stack is exhausted.

function factorial(n: int): int {
    if n <= 1 {
        return 1
    }
    return n * factorial(n - 1)
}

print(factorial(5))

IMPLEMENTATION NOTE: The example uses ordinary typed functions, `if` and `return`. Keep input sizes reasonable; recursion depth and stack use depend on the execution backend.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 06 OF 11

Tail calls

Make the next step the last step

Tail-recursive style passes an accumulator into the next call. The recursive call becomes the final operation in that branch. This can simplify state handling, but optimizing away the stack frame requires a separate compiler guarantee.

function factorialStep(n: int, product: int): int {
    if n <= 1 {
        return product
    }
    return factorialStep(n - 1, product * n)
}

function factorial(n: int): int {
    return factorialStep(n, 1)
}

print(factorial(5))

IMPLEMENTATION NOTE: This is tail-recursive source, not a promise of tail-call elimination. For long repetitions, an iterative `while` loop avoids relying on recursion-stack optimization.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 07 OF 11

List recursion

Visit every member of the pack

Traversing a collection means processing each member until none remain. Noqeri offers `for-in` on fixed arrays and slices and qualified scalar lists, so you can express this traversal directly without head-and-tail pattern destructuring.

let values: [int; 5] = [18, 56, 35, 85, 91]
let total: int = 0

for value in values {
    total = total + value
}

print(total)

IMPLEMENTATION NOTE: Array and slice traversal have tested execution paths. The example is iterative and does not claim recursive list-pattern syntax.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 08 OF 11

Multiple subjects

Decide with more than one signal

A decision can depend on several values at once. Combine comparisons with `&&`, then use `else if` and `else` for the remaining possibilities.

let x: int = 0
let y: int = 1

if x == 0 && y == 0 {
    print("Both are zero")
} else if x == 0 {
    print("First is zero")
} else if y == 0 {
    print("Second is zero")
} else {
    print("Neither is zero")
}

IMPLEMENTATION NOTE: Noqeri evaluates the conditions as Boolean expressions. A multi-subject `case` matching table is not currently part of the parser.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 09 OF 11

Alternative patterns

More than one way through

When several values should lead to the same behavior, join equality tests with `||`. The resulting branch runs when at least one of those comparisons is true.

let number: int = 4

if number == 2 || number == 4 || number == 6 {
    print("Matched an even option")
} else if number == 1 || number == 3 || number == 5 {
    print("Matched an odd option")
} else {
    print("Another number")
}

IMPLEMENTATION NOTE: The supported Boolean OR operator is `||`. Alternatives inside pattern-matching clauses have not been implemented as a separate language feature.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 10 OF 11

Pattern aliases

Keep a useful name on the trail

Give a selected value a second, more descriptive name when that makes later logic easier to read. You can bind an array element to a local before you use it.

let trail: [int; 3] = [8, 13, 21]
let first: int = trail[0]

if first > 10 {
    print("Large first value")
} else {
    print(first)
}

IMPLEMENTATION NOTE: This uses a standard local binding. Pattern-alias destructuring is not part of the currently documented compiler syntax.

FOLLOW THE SOURCE ↗

FLOW CONTROL / 11 OF 11

Guards

Check before you leap

A guard is a condition that must pass before work continues. Noqeri uses ordinary `if` conditions in loops and functions to protect the next operation.

let numbers: [int; 5] = [1, 2, 3, 4, 5]
let limit: int = 3

for number in numbers {
    if number > limit {
        print(number)
    }
}

IMPLEMENTATION NOTE: Use typed comparisons and normal control flow for guards. Case-pattern guard clauses are not currently an implemented source construct.

FOLLOW THE SOURCE ↗

Keep the pack moving.

Now that you can choose branches and traverse collections, practice counted repetition and loop control. Noqeri supports while, repeat, break and continue for direct iteration.

let remaining: int = 3
while remaining > 0 {
    print(remaining)
    remaining = remaining - 1
}

repeat 2 {
    print("One more step")
}
EXPLORE LANGUAGE CONTROL FLOW ↗SEE HOW THE COMPILER LOWERS LOOPS ↗
BUILD SOMETHING REAL WITH NOQERI.OPEN THE PLAYGROUND ↗