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 FIRSTFLOW 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 ↗