---
title: "Standard Library: Control Flow and Macros"
output: arl::arl_html_vignette
pkgdown:
  as_is: true
vignette: >
  %\VignetteIndexEntry{Standard Library: Control Flow and Macros}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

<!-- AUTO-GENERATED from inst/arl/ source files. Do not edit manually. -->
<!-- Regenerate with: make lang-docs -->

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
arl::register_knitr_engine()
```

*Examples on this page may reference functions from other stdlib modules
without showing explicit `(import ...)` statements. In the REPL or your
own code, you will need to import non-prelude modules before using their
exports — see [Importing modules](lang-reference.html#importing-modules).*


## Control Flow Macros {#section-control-flow-macros}

### when {#when}

Evaluate body forms when test is truthy.

**Signature:** `(when test body...)`

**Parameters:**
- **`test`** — Condition to evaluate
- **`body`** — Expressions to evaluate when test is truthy

**Examples:**
```{arl}
(when #t "yes")          ; => "yes"
(when #f "yes")          ; => #nil
(when (> 3 2) (+ 1 1))   ; => 2
```

```{arl, include=FALSE}
(assert-equal "yes" (when #t "yes"))
(assert-equal #nil (when #f "yes"))
(assert-equal 2 (when (> 3 2) (+ 1 1)))
```

**See also:** [unless](#unless), [if](lang-core.html#if), [cond](#cond)

---

### unless {#unless}

Evaluate body forms when test is falsy.

**Signature:** `(unless test body...)`

**Parameters:**
- **`test`** — Condition to evaluate
- **`body`** — Expressions to evaluate when test is falsy

**Examples:**
```{arl}
(unless #f "fallback")    ; => "fallback"
(unless #t "fallback")    ; => #nil
(unless (= 1 2) "nope")  ; => "nope"
```

```{arl, include=FALSE}
(assert-equal "fallback" (unless #f "fallback"))
(assert-equal #nil (unless #t "fallback"))
(assert-equal "nope" (unless (= 1 2) "nope"))
```

**See also:** [when](#when), [if](lang-core.html#if)

---

## Conditional Macros {#section-conditional-macros}

### cond {#cond}

Multi-branch conditional.

**Signature:** `(cond clause rest...)`

**Parameters:**
- **`clause`** — First (test body...) clause
- **`rest`** — Additional clauses; last may be (else body...)

**Examples:**
```{arl}
(cond
  ((= 1 2) "a")
  ((= 1 1) "b")
  (else "c"))            ; => "b"

(cond
  ((> 10 20) "big")
  (else "small"))        ; => "small"
```

```{arl, include=FALSE}
(assert-equal "b" (cond ((= 1 2) "a") ((= 1 1) "b") (else "c")))
(assert-equal "small" (cond ((> 10 20) "big") (else "small")))
```

**See also:** [case](#case), [if](lang-core.html#if), [when](#when)

---

### case {#case}

Branch on key equality. Each clause:
((datum ...) body ...) or (else body ...).
Key expression is evaluated only once.

**Signature:** `(case key clause rest...)`

**Parameters:**
- **`key`** — Expression to match (evaluated once)
- **`clause`** — First match clause: ((datum...) body...)
- **`rest`** — Additional clauses; last may be (else body...)

**Examples:**
```{arl}
(case (+ 1 1)
  ((1) "one")
  ((2) "two")
  ((3) "three")
  (else "other"))        ; => "two"

(case 'x
  ((a b) "ab")
  ((x y) "xy")
  (else "?"))            ; => "xy"
```

```{arl, include=FALSE}
(assert-equal "two" (case (+ 1 1) ((1) "one") ((2) "two") ((3) "three") (else "other")))
(assert-equal "xy" (case 'x ((a b) "ab") ((x y) "xy") (else "?")))
```

**Note:** The key expression is evaluated only once. Each clause datum list can contain multiple values.

**See also:** [cond](#cond), [if](lang-core.html#if)

---

## Error Handling {#section-error-handling}

### try {#try}

Evaluate thunk with error/finally handlers.

**Signature:** `(try thunk [error_handler] [finally_handler])`

**Parameters:**
- **`thunk`** — Zero-argument function to execute
- **`error_handler`** — Function receiving error condition (default #f)
- **`finally_handler`** — Zero-argument cleanup function (default #f)

**Examples:**
```{arl}
(try (lambda () 42))                           ; => 42
(try (lambda () (stop "oops"))
      :error_handler (lambda (e) "caught"))      ; => "caught"
(try (lambda () 1)
      :finally_handler (lambda () (display "done")))  ; => 1
```

```{arl, include=FALSE}
(assert-equal 42 (try (lambda () 42)))
(assert-equal "caught" (try (lambda () (stop "oops")) :error_handler (lambda (e) "caught")))
```

**Note:** Low-level functional interface to R's tryCatch.

**See also:** [try-catch](#try-catch)

---

### try-catch {#try-catch}

Macro wrapper around try with catch/finally.

**Signature:** `(try-catch body clauses...)`

**Parameters:**
- **`body`** — Expression to evaluate
- **`clauses`** — Optional (catch var body...) and/or (finally body...) clauses

**Examples:**
```{arl}
;; Basic try with catch
(try-catch (/ 1 0)
  (catch e (string-append "caught: " ($ e "message"))))

;; try with finally (always runs)
(try-catch (+ 1 2)
  (finally (display "cleanup")))    ; => 3

;; try with both catch and finally
(try-catch (stop "oops")
  (catch e (string-append "error: " ($ e "message")))
  (finally (display "done")))       ; => "error: oops"

;; try with no handlers (just evaluates body)
(try-catch (+ 1 2))                       ; => 3
```

```{arl, include=FALSE}
(assert-equal 3 (try-catch (+ 1 2)))
(assert-equal "error: oops" (try-catch (stop "oops") (catch e (string-append "error: " ($ e "message")))))
```

**Note:** Macro wrapper around `try` that provides familiar catch/finally syntax. The catch clause binds the error condition to the given variable. The finally clause runs regardless of success or failure.

**See also:** [try](#try)

---

## Continuations {#section-continuations}

### call-cc {#call-cc}

Invoke receiver with the current continuation (escape procedure).

**Signature:** `(call-cc receiver)`

**Parameters:**
- **`receiver`** — Function that receives the current continuation as its argument

**Examples:**
```{arl}
(call-cc (lambda (k) (k 42)))  ; => 42
```

```{arl, include=FALSE}
(assert-equal 42 (call-cc (lambda (k) (k 42))))
```

**Note:** Alias for R's `callCC`. The receiver is passed the current continuation.

**See also:** [call-with-current-continuation](#call-with-current-continuation)

---

### call-with-current-continuation {#call-with-current-continuation}

Full name alias for call-cc.

**Signature:** `(call-with-current-continuation receiver)`

**Parameters:**
- **`receiver`** — Function that receives the current continuation as its argument

**Examples:**
```{arl}
(call-with-current-continuation (lambda (k) (k 42)))  ; => 42
```

```{arl, include=FALSE}
(assert-equal 42 (call-with-current-continuation (lambda (k) (k 42))))
```

**Note:** Full name alias for `call-cc`.

**See also:** [call-cc](#call-cc)

---

## Binding Macros {#section-binding-macros}

### pattern-symbols {#pattern-symbols}

Collect all symbols from a destructuring pattern, ignoring dots.

**Signature:** `(pattern-symbols pattern)`

**Parameters:**
- **`pattern`** — Nested list/symbol pattern to extract symbol names from

**See also:** [destructuring-bind](#destructuring-bind)

---

### destructuring-bind {#destructuring-bind}

Bind a destructuring pattern to a value, then evaluate body forms.

**Signature:** `(destructuring-bind pattern value body...)`

**Parameters:**
- **`pattern`** — Destructuring pattern (possibly nested, with . for rest)
- **`value`** — Expression whose result is destructured
- **`body`** — Expressions evaluated with the pattern bindings in scope

**Examples:**
```{arl}
(destructuring-bind (a b c) (list 1 2 3)
  (+ a b c))                 ; => 6
(destructuring-bind (x . rest) (list 10 20 30)
  rest)                      ; => (20 30)
```

```{arl, include=FALSE}
(assert-equal 6 (destructuring-bind (a b c) (list 1 2 3) (+ a b c)))
(assert-equal (list 20 30) (destructuring-bind (x . rest) (list 10 20 30) rest))
```

**See also:** [let](#let), [let*](#let-star), [pattern-symbols](#pattern-symbols)

---

### let {#let}

Bind names to values within body.

**Signature:** `(let bindings body...)`

**Parameters:**
- **`bindings`** — List of (pattern value) pairs, evaluated in parallel
- **`body`** — Expressions evaluated with the bindings in scope

**Examples:**
```{arl}
(let ((x 1) (y 2))
  (+ x y))               ; => 3

(let ((x 10))
  (* x x))               ; => 100
```

```{arl, include=FALSE}
(assert-equal 3 (let ((x 1) (y 2)) (+ x y)))
(assert-equal 100 (let ((x 10)) (* x x)))
```

**Note:** Bindings are evaluated in parallel: earlier bindings are NOT visible to later ones. Use `let*` for sequential binding.

**See also:** [let*](#let-star), [letrec](#letrec)

---

### let* {#let-star}

Sequential let bindings.

**Parameters:**
- **`bindings`** — List of (pattern value) pairs, evaluated sequentially
- **`body`** — Expressions evaluated with the bindings in scope

**Examples:**
```{arl}
(let* ((x 1) (y (+ x 1)))
  (+ x y))               ; => 3

(let* ((a 10) (b (* a 2)) (c (+ a b)))
  c)                      ; => 30
```

```{arl, include=FALSE}
(assert-equal 3 (let* ((x 1) (y (+ x 1))) (+ x y)))
(assert-equal 30 (let* ((a 10) (b (* a 2)) (c (+ a b))) c))
```

**Note:** Bindings are evaluated sequentially: each binding can refer to previously bound names. Supports destructuring patterns.

**See also:** [let](#let), [letrec](#letrec)

---

### letrec {#letrec}

Recursive bindings.

**Signature:** `(letrec bindings body...)`

**Parameters:**
- **`bindings`** — List of (name value) pairs, all mutually visible
- **`body`** — Expressions evaluated with the bindings in scope

**Examples:**
```{arl}
(letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
         (odd?  (lambda (n) (if (= n 0) #f (even? (- n 1))))))
  (even? 10))             ; => #t
```

```{arl, include=FALSE}
(assert-true (letrec ((ev? (lambda (n) (if (= n 0) #t (od? (- n 1))))) (od? (lambda (n) (if (= n 0) #f (ev? (- n 1)))))) (ev? 10)))
```

**Note:** All bindings are visible to all init expressions, enabling mutual recursion. Init values are assigned via `set!` into pre-allocated slots.

**See also:** [let](#let), [let*](#let-star)

---

### when-let {#when-let}

Bind pattern to value and evaluate body when value is truthy.

**Signature:** `(when-let binding body...)`

**Parameters:**
- **`binding`** — Single (pattern value) pair
- **`body`** — Expressions evaluated when value is truthy, with pattern bound

**Examples:**
```{arl}
(when-let (x (assoc 'a (list (list 'a 1) (list 'b 2))))
  (cadr x))              ; => 1

(when-let (x #f)
  "never reached")       ; => #nil
```

```{arl, include=FALSE}
(assert-equal 1 (when-let (x (assoc 'a (list (list 'a 1) (list 'b 2)))) (cadr x)))
(assert-equal #nil (when-let (x #f) "never reached"))
```

**See also:** [if-let](#if-let), [when](#when), [let](#let)

---

### if-let {#if-let}

Bind pattern to value and choose branch based on its truthiness.

**Signature:** `(if-let binding then rest...)`

**Parameters:**
- **`binding`** — Single (pattern value) pair
- **`then`** — Expression evaluated when value is truthy, with pattern bound
- **`rest`** — Optional else expression when value is falsy

**Examples:**
```{arl}
(if-let (x 42)
  (+ x 1)
  "nothing")             ; => 43

(if-let (x #f)
  "truthy"
  "falsy")               ; => "falsy"
```

```{arl, include=FALSE}
(assert-equal 43 (if-let (x 42) (+ x 1) "nothing"))
(assert-equal "falsy" (if-let (x #f) "truthy" "falsy"))
```

**See also:** [when-let](#when-let), [if](lang-core.html#if), [let](#let)

---

## Looping Macros {#section-looping-macros}

### do-list {#do-list}

Loop over seq binding var each iteration. Expands to while.

**Signature:** `(do-list binding body...)`

**Parameters:**
- **`binding`** — Pair of (var sequence-expr)
- **`body`** — Expressions evaluated for each element with var bound

**Examples:**
```{arl}
(define total 0)
(do-list (x '(1 2 3))
  (set! total (+ total x)))
total                       ; => 6

(define result (list))
(do-list (ch '("a" "b" "c"))
  (set! result (append result (list ch))))
result                      ; => ("a" "b" "c")
```

```{arl, include=FALSE}
(define _test-total 0)
(do-list (_x '(1 2 3)) (set! _test-total (+ _test-total _x)))
(assert-equal 6 _test-total)
```

**Note:** Expands to a `while` loop over the sequence converted to a list.

**See also:** [while](lang-core.html#while), [map](lang-functional.html#map), [loop](#loop)

---

### recur {#recur}

Signal a recur back to the enclosing `loop`. Only valid inside a `loop` body.

**Signature:** `(recur args...)`

**Parameters:**
- **`args`** — New values for each loop variable (must match loop binding count)

**Examples:**
```{arl}
(loop ((i 5) (acc 0))
  (if (= i 0) acc (recur (- i 1) (+ acc i))))  ; => 15
```

```{arl, include=FALSE}
(assert-equal 15 (loop ((i 5) (acc 0)) (if (= i 0) acc (recur (- i 1) (+ acc i)))))
```

**See also:** [loop](#loop)

---

### loop {#loop}

Clojure-style loop/recur that expands to an R while loop.

**Signature:** `(loop bindings body...)`

**Parameters:**
- **`bindings`** — List of (var init-value) pairs for loop variables
- **`body`** — Loop body; use (recur ...) to iterate with new values

**Examples:**
```{arl}
;; Factorial via loop/recur
(loop ((n 5) (acc 1))
  (if (= n 0)
    acc
    (recur (- n 1) (* acc n))))  ; => 120

;; Sum of a list via loop/recur
(loop ((xs '(1 2 3 4)) (total 0))
  (if (null? xs)
    total
    (recur (cdr xs) (+ total (car xs)))))  ; => 10
```

```{arl, include=FALSE}
(assert-equal 120 (loop ((n 5) (acc 1)) (if (= n 0) acc (recur (- n 1) (* acc n)))))
(assert-equal 10 (loop ((xs '(1 2 3 4)) (total 0)) (if (null? xs) total (recur (cdr xs) (+ total (car xs))))))
```

**Note:** The compiler auto-optimizes self-tail-calls in `(define name (lambda ...))` patterns, so `loop`/`recur` is primarily useful for anonymous iteration and mutual recursion patterns. Expands to an R `while` loop internally.

**See also:** [recur](#recur), [while](lang-core.html#while), [do-list](#do-list)

---

### until {#until}

Repeat body until test is truthy.

**Signature:** `(until test body...)`

**Parameters:**
- **`test`** — Condition checked before each iteration; loop stops when truthy
- **`body`** — Expressions evaluated each iteration

**Examples:**
```{arl}
(define i 0)
(until (= i 5)
  (set! i (+ i 1)))
i                          ; => 5
```

```{arl, include=FALSE}
(define _test-i 0)
(until (= _test-i 5) (set! _test-i (+ _test-i 1)))
(assert-equal 5 _test-i)
```

**See also:** [while](lang-core.html#while)

---

## Threading Macros {#section-threading-macros}

### -> {#thread-first}

Thread value through forms (first argument).

**Signature:** `(-> value forms...)`

**Parameters:**
- **`value`** — Initial value to thread
- **`forms`** — Sequence of forms to thread through

**Examples:**
```{arl}
(-> 5 (+ 3) (* 2))       ; => 16  ; (5+3)*2
(-> (list 1 2 3) reverse) ; => (3 2 1)
(-> "hello"
    nchar)                ; => 5
```

```{arl, include=FALSE}
(assert-equal 16 (-> 5 (+ 3) (* 2)))
(assert-equal (list 3 2 1) (-> (list 1 2 3) reverse))
(assert-equal 5 (-> "hello" nchar))
```

**Note:** Threads the value as the FIRST argument to each successive form. If a form is a bare symbol, it is called as a one-argument function.

**See also:** [->>](#thread-last)

---

### ->> {#thread-last}

Thread value through forms (last argument).

**Signature:** `(->> value forms...)`

**Parameters:**
- **`value`** — Initial value to thread
- **`forms`** — Sequence of forms to thread through

**Examples:**
```{arl}
(->> '(1 2 3) (map (lambda (x) (* x x))))  ; => (1 4 9)
(->> 5 (- 10))           ; => 5  ; (- 10 5)
(->> '(1 2 3)
     (map (lambda (x) (+ x 10)))
     (car))              ; => 11
```

```{arl, include=FALSE}
(assert-equal (list 1 4 9) (->> '(1 2 3) (map (lambda (x) (* x x)))))
(assert-equal 5 (->> 5 (- 10)))
(assert-equal 11 (->> '(1 2 3) (map (lambda (x) (+ x 10))) (car)))
```

**Note:** Threads the value as the LAST argument to each successive form. Compare with `->` which threads as the first argument.

**See also:** [->](#thread-first)

---

### as-> {#as-to}

Thread with a named binding. The value is bound to name
in each form, so it can appear in any position.

**Signature:** `(as-> expr name forms...)`

**Parameters:**
- **`expr`** — Initial value
- **`name`** — Symbol to bind the threaded value to
- **`forms`** — Sequence of forms using name

**Examples:**
```{arl}
(as-> 1 x (+ x 1) (* x 3))  ; => 6
```

```{arl, include=FALSE}
(assert-equal 6 (as-> 1 x (+ x 1) (* x 3)))
```

**See also:** [->](#thread-first), [->>](#thread-last)

---

### some-> {#some-to}

Thread-first with short-circuit on falsy values.
Like -> but stops and returns #nil or #f if any step produces a falsy value.

**Signature:** `(some-> value forms...)`

**Parameters:**
- **`value`** — Initial value
- **`forms`** — Sequence of forms to thread through

**Examples:**
```{arl}
(some-> 5 (+ 3) (* 2))   ; => 16
(some-> #nil (+ 3))       ; => #nil
```

```{arl, include=FALSE}
(assert-equal 16 (some-> 5 (+ 3) (* 2)))
(assert-equal #nil (some-> #nil (+ 3)))
```

**See also:** [->](#thread-first), [some->>](#some-to-gt)

---

### some->> {#some-to-gt}

Thread-last with short-circuit on falsy values.
Like ->> but stops and returns #nil or #f if any step produces a falsy value.

**Signature:** `(some->> value forms...)`

**Parameters:**
- **`value`** — Initial value
- **`forms`** — Sequence of forms to thread through

**Examples:**
```{arl}
(some->> 5 (- 10))    ; => 5
(some->> #nil (- 10))  ; => #nil
```

```{arl, include=FALSE}
(assert-equal 5 (some->> 5 (- 10)))
(assert-equal #nil (some->> #nil (- 10)))
```

**See also:** [->>](#thread-last), [some->](#some-to)

---

### cond-> {#cond-to}

Conditionally thread value through forms (first argument).
Each clause is (test form). If test is truthy, threads value through form;
otherwise passes value unchanged.

**Signature:** `(cond-> value clauses...)`

**Parameters:**
- **`value`** — Initial value
- **`clauses`** — Pairs of (test form) to conditionally apply

**Examples:**
```{arl}
(cond-> 1 (#t (+ 1)) (#f (* 3)))  ; => 2
```

```{arl, include=FALSE}
(assert-equal 2 (cond-> 1 (#t (+ 1)) (#f (* 3))))
```

**See also:** [->](#thread-first), [cond->>](#cond-to-gt)

---

### cond->> {#cond-to-gt}

Conditionally thread value through forms (last argument).
Thread-last variant of cond->.

**Signature:** `(cond->> value clauses...)`

**Parameters:**
- **`value`** — Initial value
- **`clauses`** — Pairs of (test form) to conditionally apply

**Examples:**
```{arl}
(cond->> 5 (#t (- 10)) (#f (* 100)))  ; => 5
```

```{arl, include=FALSE}
(assert-equal 5 (cond->> 5 (#t (- 10)) (#f (* 100))))
```

**See also:** [->>](#thread-last), [cond->](#cond-to)

---

