Control Flow in Topaz
Topaz manages the flow of execution primarily through expressions that evaluate to values, rather than imperative statements that perform actions. This functional approach leads to more predictable and composable code. This section covers the primary mechanisms for controlling program flow in Topaz v1.0.
Conditional Evaluation: IF
The primary tool for conditional branching is the IF
special form. It evaluates a condition and, based on the result, evaluates one of two possible expressions.
Syntax: (IF CONDITION_EXPR TRUE_EXPR FALSE_EXPR)
- It evaluates
CONDITION_EXPR
.#true
is treated as true, while#false
orNULL_SIG
is treated as false. - If the condition is true, it evaluates and returns the result of
TRUE_EXPR
. - If the condition is false, it evaluates and returns the result of
FALSE_EXPR
.
($ temperature 25)
($ clothing-advice
(IF (> temperature 20)
"It's warm, wear a t-shirt!"
"It's cool, consider a jacket."
)
)
;; The value of clothing-advice is "It's warm, wear a t-shirt!"
;; Nested conditionals
($ grade 85)
($ letter-grade
(IF (>= grade 90)
"A"
(IF (>= grade 80)
"B"
(IF (>= grade 70)
"C"
"F"
)
)
)
)
Iteration via Recursion and Higher-Order Functions
Topaz, true to its functional roots, prefers declarative approaches to iteration over traditional imperative loops like for
or while
. This is primarily achieved through recursion and higher-order functions.
Recursion
As shown in the Functions and Processes guide, recursion is a natural and powerful way to perform iteration, especially on data structures like vectors. The pattern often involves processing the first element of a collection and then recursively calling the process on the rest of the collection.
Example: Summing the numbers in a vector
($ sum-vector
(λ (vec)
(IF (vector:is-empty vec)
0 ;; Base case: the sum of an empty vector is 0
(+ (vector:first vec) (sum-vector (vector:rest vec))) ;; Recursive step
)
)
)
(sum-vector [10 20 30 40]) ;; Evaluates to 100
Note: IS-EMPTY
, FIRST
, and REST
are illustrative names for common list/vector manipulation functions that would be in the standard library.
Higher-Order Functions
A more declarative, and often preferred, way to handle collections is by using higher-order functions--processes that take other processes as arguments. Standard functions like map
, filter
, and reduce
are essential tools in this paradigm.
($ numbers [1 2 3 4 5])
;; MAP: Applies a process to every element, returning a new vector of the results.
($ squared (vector:map (λ (n) (* n n)) numbers))
;; The value of squared is [1 4 9 16 25]
;; FILTER: Returns a new vector containing only elements that satisfy a predicate.
($ evens (vector:filter (λ (n) (= (% n 2) 0)) numbers))
;; The value of evens is [2 4]
;; REDUCE: Combines all elements into a single value by repeatedly applying a process.
($ sum (vector:reduce + 0 numbers)) ;; Starts with an initial value of 0
;; The value of sum is 15
;; FOLD-LEFT and FOLD-RIGHT for more control over evaluation order
($ concatenated (vector:fold-left string:concat "" ["Hello" " " "Topaz" "!"]))
;; The value of concatenated is "Hello Topaz!"
Macros for Control Flow
Topaz v1.0 includes a macro system that enables the creation of custom control flow constructs:
;; Define a 'when' macro that executes body only if condition is true
(DEFMACRO when (condition body-expressions...)
`(IF ,condition
(BEGIN ,@body-expressions)
NULL_SIG
)
)
;; Use the 'when' macro
($ x 10)
(when (> x 5)
(io:print "x is greater than 5")
(io:print "This also gets executed")
)
;; Define an 'unless' macro (opposite of when)
(DEFMACRO unless (condition body-expressions...)
`(IF ,condition
NULL_SIG
(BEGIN ,@body-expressions)
)
)
;; Define a 'cond' macro for multiple conditions (similar to Lisp's cond)
(DEFMACRO cond (clauses...)
;; Implementation would expand to nested IF expressions
;; This is a simplified conceptual example
`(IF ,(first (first clauses))
,(second (first clauses))
(cond ,@(rest clauses))
)
)
;; Usage of cond macro
($ grade 85)
($ letter (cond
((>= grade 90) "A")
((>= grade 80) "B")
((>= grade 70) "C")
(#true "F") ;; Default case
))
Pattern Matching (Future Extension)
Future versions of Topaz will include a MATCH
expression for Pattern Matching, which will provide even more powerful and expressive control flow for deconstructing and branching on complex data structures:
;; Future MATCH expression for handling Result types
(MATCH some-result
((result:ok value) (io:print (string:concat "Success! Got value: " value)))
((result:err message) (io:print (string:concat "Failure! Reason: " message)))
)
;; Pattern matching on user-defined types
(MATCH user-input
((# :type :login :username u :password p) (authenticate u p))
((# :type :logout :session-id sid) (logout sid))
((# :type :unknown) (io:print "Unknown command"))
)