Topaz Docs

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 or NULL_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"))
)