Chapter 5: Control Flow
This chapter covers conditionals, pattern matching, and recursion.
Conditionals
if
The basic conditional expression:
(if condition
then-expression
else-expression)Examples:
(if (> x 0)
"positive"
"not positive")
(if (null? lst)
0
(+ 1 (length (cdr lst))))The else clause is optional. If omitted and the condition is false, an unspecified value is returned:
> (if #t "yes")
"yes"cond
Multiple conditions with cond:
(cond
((< n 0) "negative")
((= n 0) "zero")
((< n 10) "small")
((< n 100) "medium")
(else "large"))The else clause handles any remaining cases. Each clause is (test body ...).
cond also supports the => syntax:
(cond
((find predicate lst) => process-result)
(else default))If the test is true, its value is passed to the procedure after =>.
case
Match a value against constants:
(case day
((monday tuesday wednesday thursday friday) "weekday")
((saturday sunday) "weekend")
(else "unknown"))when and unless
One-sided conditionals for side effects:
(when (file-exists? path)
(println "File found!")
(process-file path))
(unless (directory? path)
(error "Expected a directory"))Pattern Matching with match
Pattern matching is a powerful way to destructure and dispatch on data:
(match value
(pattern1 body1 ...)
(pattern2 body2 ...)
...)Matching Lists
> (import (sigil match))
> (define (sum-list lst)
(match lst
(() 0)
((x) x)
((x . rest) (+ x (sum-list rest)))))
> (sum-list '(1 2 3 4))
10Matching Literals
(define (describe val)
(match val
(#t "true")
(#f "false")
('() "empty list")
(_ "something else"))) ; _ matches anythingMatching Symbols
Quote symbols to match them literally:
(define (handle-command cmd)
(match cmd
('quit (exit))
('help (show-help))
('status (show-status))
(_ (println "Unknown command"))))Binding Variables
Unquoted symbols bind to the matched value:
> (match '(1 2 3)
((a b c) (+ a b c)))
6
> (match '(point 3 4)
(('point x y) (sqrt (+ (* x x) (* y y)))))
5Complex Patterns
(define (describe-pair p)
(match p
((0 . 0) "origin")
((0 . y) (str "on y-axis at " y))
((x . 0) (str "on x-axis at " x))
((x . y) (str "point at " x "," y))))Recursion
Scheme favors recursion over iteration. Most loops are written recursively.
Basic Recursion
(define (factorial n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))Tail Recursion
Tail-recursive procedures reuse the current stack frame:
(define (factorial-tail n)
(define (loop n acc)
(if (<= n 1)
acc
(loop (- n 1) (* n acc))))
(loop n 1))The loop call is in tail position — it's the last thing the function does.
Named let for Loops
A common pattern for iteration:
(define (sum-list lst)
(let loop ((lst lst) (acc 0))
(if (null? lst)
acc
(loop (cdr lst) (+ acc (car lst))))))Named let creates a local procedure and calls it immediately.
Processing Lists
Common patterns:
;; Map - transform each element
(define (my-map f lst)
(if (null? lst)
'()
(cons (f (car lst))
(my-map f (cdr lst)))))
;; Filter - keep matching elements
(define (my-filter pred lst)
(cond
((null? lst) '())
((pred (car lst))
(cons (car lst) (my-filter pred (cdr lst))))
(else
(my-filter pred (cdr lst)))))
;; Fold - reduce to single value
(define (my-fold f init lst)
(if (null? lst)
init
(my-fold f (f init (car lst)) (cdr lst))))These are built-in as map, filter, and fold-left.
Higher-Order Procedures
Procedures that take or return procedures:
> (map (lambda (x) (* x x)) '(1 2 3 4))
(1 4 9 16)
> (filter (lambda (x) (> x 2)) '(1 2 3 4 5))
(3 4 5)Returning a procedure:
> (define (make-adder n)
(lambda (x) (+ x n)))
> (define add5 (make-adder 5))
> (add5 10)
15Practical Example
A simple expression evaluator:
(define (eval-expr expr)
(match expr
;; Numbers evaluate to themselves
((? number? n) n)
;; Quoted values
(('quote x) x)
;; Binary operations
((op a b)
(let ((va (eval-expr a))
(vb (eval-expr b)))
(case op
((+) (+ va vb))
((-) (- va vb))
((*) (* va vb))
((/) (/ va vb))
(else (error "Unknown operator" op)))))))
(eval-expr '(+ 1 (* 2 3))) ; => 7Note: The (? predicate pattern) syntax tests a predicate. This may not be available in all Sigil versions — check your implementation.
Practice Exercises
- Write a recursive procedure to compute Fibonacci numbers.
- Use
matchto write a procedure that counts the depth of nested lists. - Write a procedure that flattens a nested list into a flat list.
What's Next
Let's learn how to organize code into modules.