sigildocs

(sigil core)

(sigil core) - Core Language Primitives

The foundation of Sigil. This module is automatically imported into every module and provides essential procedures, macros, and syntax forms.

List Operations

(append '(1 2) '(3 4))           ; => (1 2 3 4)
(reverse '(1 2 3))               ; => (3 2 1)
(filter even? '(1 2 3 4 5))      ; => (2 4)
(map (lambda (x) (* x 2)) '(1 2 3)) ; => (2 4 6)
(fold + 0 '(1 2 3 4))            ; => 10

Control Flow

(cond
  ((< x 0) "negative")
  ((= x 0) "zero")
  (else "positive"))

(case color
  ((red green blue) "primary")
  ((cyan magenta yellow) "secondary")
  (else "other"))

(when (> x 0) (do-something))
(unless (null? lst) (process lst))

Records

(define-record <point> (x) (y))
(define p (point 10 20))
(point-x p)  ; => 10
(point? p)   ; => #t

Exception Handling

(error "Something went wrong: ~a" details)
(raise (make-exception 'not-found "Resource missing" '()))

Keyword Arguments

(define (greet name (keys: (greeting "Hello")))
  (format "~a, ~a!" greeting name))

(greet "World")                    ; => "Hello, World!"
(greet "World" greeting: "Hi")     ; => "Hi, World!"

This module uses bootstrap primitives (%make-module, %module-export!) instead of define-library for internal bootstrapping reasons.

Exports

zero?procedure

Check if a number is zero.

(zero? 0)    ; => #t
(zero? 1)    ; => #f
(zero? -1)   ; => #f
(zero? 0.0)  ; => #t
positive?procedure

Check if a number is positive (greater than zero).

(positive? 5)    ; => #t
(positive? 0)    ; => #f
(positive? -3)   ; => #f
(positive? 0.1)  ; => #t
negative?procedure

Check if a number is negative (less than zero).

(negative? -5)   ; => #t
(negative? 0)    ; => #f
(negative? 3)    ; => #f
(negative? -0.1) ; => #t
appendprocedure

Concatenate any number of lists into one.

Returns a new list with elements from all lists in order. The last list is shared (not copied).

(append '(1 2) '(3 4))        ; => (1 2 3 4)
(append '(a) '(b) '(c d))     ; => (a b c d)
(append '(1 2) '())           ; => (1 2)
reverseprocedure

Reverse the order of elements in a list.

Returns a new list with elements in reverse order.

(reverse '(1 2 3))    ; => (3 2 1)
(reverse '(a b c d))  ; => (d c b a)
(reverse '())         ; => ()

list-length-internal - Tail-recursive length

Check if a syntax object has local-binding metadata in its substs. Used for free-identifier=? comparison in literal matching.

Register captured locals for a macro instance. Returns the capture-id to use for retrieval.

Retrieve a captured value at runtime. capture-id is the unique ID for the macro instance. sym is the symbol name of the captured local.

syntax-rules transformer generator

In syntax-rules, the first element of each pattern is the macro keyword. It should be treated as a literal (matched exactly, not bound as a variable).

captured-locals is an alist of (symbol . value) for free identifiers that were local bindings at macro definition time. This enables proper hygiene for macros defined in local scopes.

letrecsyntax

letrec - recursive let bindings (bootstrap version) (letrec ((var init) ...) body ...) => ((lambda (var ...) (set! var init) ... body ...) #f ...)

letsyntax

let - local binding (bootstrap version) (let ((var val) ...) body ...) => ((lambda (var ...) body ...) val ...) (let name ((var val) ...) body ...) => (letrec ((name (lambda (var ...) body ...))) (name val ...))

let*syntax

let - sequential binding (bootstrap version) (let () body ...) => (let () body ...) ; Use let for proper scoping (let ((v e) rest ...) body ...) => (let ((v e)) (let (rest ...) body ...))

condsyntax

cond - multi-way conditional (bootstrap version) Only supports basic (test body ...) and (else body ...) clauses Arrow syntax (=>) not supported in bootstrap version

andsyntax

and - short-circuit logical and (bootstrap version)

orsyntax

or - short-circuit logical or (bootstrap version)

caarprocedure

Get the car of the car: (car (car x)).

(caar '((1 2) 3))  ; => 1
cadrprocedure

Get the car of the cdr (second element): (car (cdr x)).

(cadr '(1 2 3))  ; => 2
cdarprocedure

Get the cdr of the car: (cdr (car x)).

(cdar '((1 2 3) 4))  ; => (2 3)
cddrprocedure

Get the cdr of the cdr (tail after second): (cdr (cdr x)).

(cddr '(1 2 3 4))  ; => (3 4)
caadrprocedure

Get (car (car (cdr x))).

cadarprocedure

Get (car (cdr (car x))) - useful for alist value access.

caddrprocedure

Get the third element: (car (cdr (cdr x))).

(caddr '(1 2 3 4))  ; => 3
cdadrprocedure

Get (cdr (car (cdr x))).

cdddrprocedure

Get the tail after third element: (cdr (cdr (cdr x))).

(cdddr '(1 2 3 4 5))  ; => (4 5)
cadddrprocedure

Get the fourth element: (car (cdr (cdr (cdr x)))).

(cadddr '(1 2 3 4 5))  ; => 4

Check if a syntax object is an identifier (syntax-wrapped symbol)

Pattern match on syntax objects, preserving syntax in bindings. Returns an alist of (pattern-var . syntax-value) or #f if no match. Unlike the plain %pattern-match, this keeps syntax wrappers on bindings.

Match ellipsis patterns on syntax, building lists of bindings

Collect pattern variables from a pattern (for ellipsis handling) Returns plain symbols, stripping syntax wrappers from pattern variable names.

Match multiple expressions against a sub-pattern, accumulating bindings

Continue pattern matching after ellipsis

Instantiate a template with syntax bindings. This is the core of hygienic template construction.

  • Pattern variables are substituted with their bound syntax values
  • Introduced bindings are renamed with gensyms for hygiene
  • Free identifiers with capture-id emit (%macro-capture capture-id 'sym) forms
  • Other free identifiers are wrapped with definition-site module name

Expand an ellipsis template

Hygienic version of ellipsis expansion that uses renames and capture-id

Generate let-bindings for pattern variables from a match result Takes: pattern, literals list, and the binding alist variable name Returns: list of (var (cdr (assq 'var bindings-var))) Note: Variable names are stripped of syntax to work as proper binding names.

syntax-case macro implementation (syntax-case stx-expr (literal ...) clause ...) Each clause is (pattern body) or (pattern guard body)

syntaxsyntax

syntax macro - construct hygienic template (syntax template) where template uses pattern variables from syntax-case For now, this is a simple wrapper; full hygiene comes from the expander marks

with-syntax - bind pattern variables for use with syntax templates (with-syntax ((pattern expr) ...) body ...) This merges new bindings with existing %match bindings

letsyntax

Bind variables to values in a local scope.

Basic form binds variables in parallel (all values evaluated before binding):

(let ((x 1) (y 2)) (+ x y))  ; => 3

Named let creates a local recursive procedure for iteration:

(let loop ((n 5) (acc 1))
  (if (= n 0) acc (loop (- n 1) (* acc n))))  ; => 120
let*syntax

Bind variables sequentially, each binding visible to subsequent ones.

Unlike let, bindings are evaluated and bound one at a time:

(let* ((x 1) (y (+ x 1))) y)  ; => 2
(let* ((a 1) (b (* a 2)) (c (* b 3))) c)  ; => 6

let-values - bind multiple values from producers R7RS: (let-values (((var ...) producer) ...) body ...)

let-values - sequential let-values (same as let-values semantically) R7RS: (let-values (((var ...) producer) ...) body ...)

define-values - define multiple variables from a values producer R7RS: (define-values (var ...) producer) Implementation: Uses a helper that captures values in a list, then extracts each value. This avoids the complexity of generating fresh temporary names in syntax-rules.

parameterize - temporarily rebind parameters R7RS: (parameterize ((param value) ...) body ...) Saves old values, sets new values, executes body, restores old values. Note: This basic implementation doesn't use dynamic-wind so it won't restore on non-local exits. For most uses this is sufficient.

case-lambda - procedure with multiple arities (R7RS)

Example: (define add (case-lambda (() 0) ((x) x) ((x y) (+ x y))))

Supports fixed arities and rest arguments.

condsyntax

Multi-way conditional with multiple test-expression clauses.

Each clause is (test expr ...). The first true test's expressions are evaluated. Use else for a default clause. The => syntax passes the test result to a procedure.

(define x 5)
(cond ((> x 0) "positive")
      ((< x 0) "negative")
      (else "zero"))  ; => "positive"

;; Using => to pass the matched value to a procedure
(cond ((assq 'b '((a 1) (b 2))) => cadr)
      (else #f))  ; => 2
casesyntax

Dispatch on a key value, comparing against literal datums using eqv?.

(case (car '(b d))
  ((a e i o u) "vowel")
  ((b c d f g) "consonant")
  (else "unknown"))  ; => "consonant"
andsyntax

Short-circuit logical AND. Returns last value if all are true, else #f.

(and 1 2 3)        ; => 3
(and 1 #f 3)       ; => #f
(and)              ; => #t
(and (> 5 0) "yes") ; => "yes"
orsyntax

Short-circuit logical OR. Returns first true value, else #f.

(or #f 2 3)    ; => 2
(or #f #f)     ; => #f
(or)           ; => #f
(or (memq 'a '(b a c)))  ; => (a c)
whensyntax

Evaluate body expressions when test is true. Returns #f if test is false.

(when (> 5 0) (display "positive") 'done)  ; prints "positive", => done
(when #f (display "never"))  ; => #f
unlesssyntax

Evaluate body expressions when test is false. Returns #f if test is true.

(unless (< 5 0) (display "not negative") 'ok)  ; prints "not negative", => ok
(unless #t (display "never"))  ; => #f
letrecsyntax

Bind variables that can reference each other (mutually recursive).

Essential for defining local recursive procedures:

(letrec ((even? (lambda (n) (if (= n 0) #t (odd? (- n 1)))))
         (odd? (lambda (n) (if (= n 0) #f (even? (- n 1))))))
  (even? 10))  ; => #t
letrec*syntax

letrec* - sequential letrec (each init can reference earlier bindings) This is what internal defines expand to. Transforms to nested let + set! pattern.

%qq-unquote?procedure

The quasiquote macro (invoked with backtick `) allows building lists with some parts evaluated and some quoted.

Examples: (a b c) => '(a b c) (a ,x c) => (list 'a x 'c) (a ,@xs c) => (append (list 'a) xs (list 'c)) (a (b ,c) d) => (list 'a (list 'b c) 'd)

Implementation approach:

  • Walk the quasiquoted form
  • For atoms: quote them
  • For (unquote x): return x directly
  • For lists containing unquote-splicing: use append
  • For other lists: use cons or list Check if a form is (unquote x)

Check if a form is (unquote-splicing x)

Check if a list contains any unquote-splicing at the top level

%qq-expandprocedure

Expand a quasiquoted expression into list-building code

Expand a list without splicing using list

Expand a list that contains splicing using append

Collect segments for append: quoted items get wrapped in (list ...), spliced items are included directly

Collect one segment: either a single splice, or multiple non-spliced items Returns (segment . remaining-list)

Collect consecutive non-spliced items Returns (items . remaining-list)

The quasiquote macro - transforms the entire form

list->vectorprocedure

Convert a list to a vector. (list->vector lst) -> vector

string-joinprocedure

string-join - Join a list of strings with an optional separator (string-join '("a" "b" "c") "-") => "a-b-c" (string-join '("a" "b" "c")) => "abc"

mapprocedure

Apply a procedure to each element of a list, returning a new list.

(map (lambda (x) (* x 2)) '(1 2 3))  ; => (2 4 6)
(map symbol->string '(a b c))        ; => ("a" "b" "c")

For multi-list mapping, use list-map from (sigil list):

(import (sigil list))
(list-map + '(1 2 3) '(10 20 30))    ; => (11 22 33)
anyprocedure

Test if any element in a list satisfies a predicate.

Returns #t as soon as one matching element is found, #f otherwise.

(any even? '(1 3 4 5))    ; => #t
(any even? '(1 3 5 7))    ; => #f
(any null? '(() (1) (2))) ; => #t
everyprocedure

Test if all elements in a list satisfy a predicate.

Returns #t if the predicate is true for every element, #f otherwise.

(every number? '(1 2 3))  ; => #t
(every even? '(2 4 5))    ; => #f
(every symbol? '())       ; => #t (vacuously true)
for-eachprocedure

Apply a procedure to each element of a list for side effects.

Like map, but doesn't collect results—used for side effects like printing.

(for-each println '("a" "b" "c"))  ; prints a, b, c on separate lines
(for-each (lambda (x) (set! sum (+ sum x))) '(1 2 3))

For multi-list iteration, use list-for-each from (sigil list):

(import (sigil list))
(list-for-each (lambda (a b) (println "~a" (+ a b))) '(1 2) '(10 20))
filterprocedure

Return elements that satisfy a predicate.

Creates a new list containing only elements for which the predicate returns #t.

(filter even? '(1 2 3 4 5))       ; => (2 4)
(filter string? '(1 "a" 2 "b"))   ; => ("a" "b")
(filter (lambda (x) (> x 0)) '(-1 0 1 2))  ; => (1 2)
filter-mapprocedure

Map a procedure over a list, keeping only non-#f results.

Applies proc to each element and collects non-false results. This is equivalent to (filter values (map proc lst)) but more efficient.

(filter-map (lambda (x) (if (even? x) (* x 2) #f)) '(1 2 3 4))  ; => (4 8)
(filter-map (lambda (x) (and (> x 0) x)) '(-1 2 -3 4))          ; => (2 4)
partitionprocedure

Partition a list into two lists based on a predicate.

Returns two values: a list of elements satisfying the predicate, and a list of elements that don't.

(partition even? '(1 2 3 4 5 6))  ; => (2 4 6) (1 3 5)
(partition positive? '(-1 2 -3 4))  ; => (2 4) (-1 -3)
takeprocedure

Return the first n elements of a list.

If the list has fewer than n elements, returns the entire list.

(take '(1 2 3 4 5) 3)   ; => (1 2 3)
(take '(a b) 5)         ; => (a b)
(take '() 3)            ; => ()
removeprocedure

Remove all occurrences of an item from a list.

Uses equal? for comparison. Returns a new list with all elements equal to item removed.

(remove 2 '(1 2 3 2 4))    ; => (1 3 4)
(remove 'a '(a b a c a))   ; => (b c)
findprocedure

Find the first element satisfying a predicate.

Returns the first element for which the predicate returns #t, or #f if no element matches.

(find even? '(1 3 4 5))   ; => 4
(find even? '(1 3 5))     ; => #f
(find (lambda (x) (> x 10)) '(5 15 25))  ; => 15
assoc-refprocedure

Get the value for a key in an alist, or a default if not found.

Uses equal? for key comparison.

(assoc-ref 'b '((a . 1) (b . 2) (c . 3)))      ; => 2
(assoc-ref 'd '((a . 1) (b . 2)) 'not-found)   ; => not-found
(assoc-ref 'd '((a . 1) (b . 2)))              ; => #f
fold-leftprocedure

Reduce a list from the left.

Applies (proc accumulator element) for each element, threading the result as the accumulator for the next call.

(fold-left + 0 '(1 2 3 4))        ; => 10
(fold-left cons '() '(1 2 3))     ; => ((((() . 1) . 2) . 3)
(fold-left max 0 '(3 1 4 1 5))    ; => 5
fold-rightprocedure

Reduce a list from the right.

Applies (proc element accumulator) starting from the last element. Note: Not tail-recursive—may stack overflow on very long lists.

(fold-right cons '() '(1 2 3))    ; => (1 2 3)
(fold-right + 0 '(1 2 3 4))       ; => 10
(fold-right list '() '(a b c))    ; => (a (b (c ())))
even?procedure

even? - Test if an integer is even (even? 4) => #t (even? 3) => #f

odd?procedure

odd? - Test if an integer is odd (odd? 3) => #t (odd? 4) => #f

iotaprocedure

iota - Generate a list of integers (iota 5) => (0 1 2 3 4) (iota 5 1) => (1 2 3 4 5) (iota 5 0 2) => (0 2 4 6 8)

make-listprocedure

Create a list of n copies of fill.

(make-list 3 'a)  ; => (a a a)
(make-list 5)     ; => (#f #f #f #f #f)
(make-list 0 'x)  ; => ()

If fill is omitted, #f is used.

make-stringprocedure

Create a string of n copies of char.

(make-string 3 #\a)  ; => "aaa"
(make-string 5)      ; => "     "
(make-string 0 #\x)  ; => ""

If char is omitted, space is used.

vector->listprocedure

Convert a vector to a list. (vector->list vec) -> list (vector->list vec start) -> list from start to end (vector->list vec start end) -> list from start to end

Apply procedure to each element of a vector for side effects. (vector-for-each display #(1 2 3)) displays 123

vector-mapprocedure

Apply procedure to each element, return vector of results. (vector-map (lambda (x) (* x 2)) #(1 2 3)) => #(2 4 6)

vector-filterprocedure

Return a new vector containing only elements that satisfy the predicate. (vector-filter even? #(1 2 3 4 5)) => #(2 4)

vector-foldprocedure

Fold a procedure over a vector from left to right. (vector-fold + 0 #(1 2 3 4 5)) => 15

vector-copyprocedure

Copy a vector, optionally with start and end indices. (vector-copy vec) -> new vector copy (vector-copy vec start) -> copy from start to end (vector-copy vec start end) -> copy from start to end

vector-fill!procedure

Fill a vector with a value. (vector-fill! vec fill) -> fills entire vector (vector-fill! vec fill start) -> fills from start to end (vector-fill! vec fill start end) -> fills from start to end

Apply procedure to each character of a string for side effects. (string-for-each display "abc") displays abc

string-mapprocedure

Apply procedure to each character, return string of results. (string-map char-upcase "abc") => "ABC"

string-copyprocedure

Copy a string, optionally with start and end indices. (string-copy str) -> new string copy (string-copy str start) -> copy from start to end (string-copy str start end) -> copy from start to end

Convert a vector of characters to a string. (vector->string #(#a #b #c)) => "abc"

Convert a string to a vector of characters. (string->vector "abc") => #(#a #b #c) (string->vector "hello" 1 4) => #(#e #l #l)

Copy a bytevector, optionally with start and end indices. (bytevector-copy bv) -> new bytevector copy (bytevector-copy bv start) -> copy from start to end (bytevector-copy bv start end) -> copy from start to end

Append multiple bytevectors. (bytevector-append #u8(1 2) #u8(3 4)) => #u8(1 2 3 4)

resetsyntax

reset - establish a delimiting prompt Usage: (reset expr ...) The body is evaluated and its result returned. If shift is called within, control transfers to the shift's handler.

The handler receives (k thunk) where:

  • k is the delimited continuation
  • thunk is the procedure passed by shift: (lambda (k) body ...) We call the thunk with k to execute the shift body.
shiftsyntax

shift - capture the continuation up to the nearest reset Usage: (shift k expr ...) Captures the continuation up to the enclosing reset and binds it to k. The body expressions are then evaluated with k available. The captured continuation k is composable - calling (k v) will resume the computation with v, and return to this point when that completes.

call-with-port - R7RS procedure for safe port handling Calls proc with port as argument, closes port when proc returns, and returns the result of proc.

Usage: (call-with-port (open-input-file "data.txt") (lambda (port) (read-line port)))

delaysyntax

delay - create a promise that lazily evaluates an expression

Usage: (define p (delay (+ 1 2))) (force p) => 3 (force p) => 3 (memoized)

delay-force - create a promise for tail-recursive lazy algorithms

Like delay, but if the expression returns a promise, that promise is iteratively forced. This enables proper tail recursion in lazy streams.

Usage: (define (lazy-range n) (delay-force (if (> n 0) (cons n (lazy-range (- n 1))) '())))

Create an exception with the given kind, message, and irritants.

Create an exception with stack trace.

exception?procedure

Check if obj is an exception.

Get the kind of an exception (e.g., 'error, 'type-error).

Get the message from an exception.

Get the irritants (additional data) from an exception.

Get the stack trace from an exception.

Default handler - prints error and returns #f

Get the current exception handler.

Add stack trace to an exception (internal helper).

raiseprocedure

Raise an exception (non-continuable). Aborts to the nearest exception handler.

Raise a continuable exception. The handler can return a value to continue execution.

errorprocedure

Convenience function to raise an error exception. (error "message" irritant ...)

Install an exception handler and execute thunk (R6RS style). Handler is a procedure taking the exception. Thunk is the body to execute.

Run a thunk with a default error handler that prints and exits. Used by sigil-run to wrap the entry point so errors are visible. Applications can install their own handlers (like REPL does) to override.

guardsyntax

Handle exceptions with pattern-matching clauses (R7RS).

Each clause has the form (test result ...) or (else result ...). If no clause matches and there's no else, the exception is re-raised.

(guard (exn
         ((eq? (exception-kind exn) 'not-found) "missing")
         (else (exception-message exn)))
  (risky-operation))
string-refprocedure

Return the character at position k in the string.

(string-ref "hello" 0)  ; => #\h
(string-ref "hello" 4)  ; => #\o

The index k must be a non-negative integer less than the string length. Raises an error if the index is out of bounds.

string-lengthprocedure

Return the number of characters in the string.

(string-length "hello")  ; => 5
(string-length "")       ; => 0
(string-length "λ")      ; => 1  (counts characters, not bytes)
string-appendprocedure

Concatenate zero or more strings into a single string.

(string-append "hello" " " "world")  ; => "hello world"
(string-append)                       ; => ""
(string-append "only")                ; => "only"
substringprocedure

Extract a substring from start (inclusive) to end (exclusive).

(substring "hello" 1 4)   ; => "ell"
(substring "hello" 0 5)   ; => "hello"
(substring "hello" 2 2)   ; => ""

Both start and end must be valid indices where 0 <= start <= end <= length.

string=?procedure

Test if two strings are equal.

(string=? "hello" "hello")  ; => #t
(string=? "hello" "Hello")  ; => #f  (case-sensitive)
(string=? "" "")            ; => #t
char=?procedure

Test if two characters are equal.

(char=? #\a #\a)  ; => #t
(char=? #\a #\A)  ; => #f
char<?procedure

Test if the first character is less than the second.

(char<? #\a #\b)  ; => #t
(char<? #\b #\a)  ; => #f
(char<? #\A #\a)  ; => #t  (uppercase before lowercase in Unicode)
char<=?procedure

Test if the first character is less than or equal to the second.

(char<=? #\a #\a)  ; => #t
(char<=? #\a #\b)  ; => #t
(char<=? #\b #\a)  ; => #f
char>?procedure

Test if the first character is greater than the second.

(char>? #\b #\a)  ; => #t
(char>? #\a #\b)  ; => #f
char>=?procedure

Test if the first character is greater than or equal to the second.

(char>=? #\a #\a)  ; => #t
(char>=? #\b #\a)  ; => #t
(char>=? #\a #\b)  ; => #f
char->integerprocedure

Convert a character to its Unicode code point.

(char->integer #\a)    ; => 97
(char->integer #\A)    ; => 65
(char->integer #\λ)    ; => 955
(char->integer #\space) ; => 32
integer->charprocedure

Convert a Unicode code point to its character.

(integer->char 97)   ; => #\a
(integer->char 65)   ; => #\A
(integer->char 955)  ; => #\λ
stringprocedure

Create a string from zero or more character arguments.

(string #\h #\i)  ; => "hi"
(string)          ; => ""
(string #\λ)      ; => "λ"
carprocedure

Return the first element (car) of a pair.

(car '(1 2 3))      ; => 1
(car '(a . b))      ; => a
(car '((1 2) 3 4))  ; => (1 2)
cdrprocedure

Return the rest (cdr) of a pair.

(cdr '(1 2 3))      ; => (2 3)
(cdr '(a . b))      ; => b
(cdr '(1))          ; => ()
consprocedure

Construct a new pair with the given car and cdr.

(cons 1 2)           ; => (1 . 2)
(cons 1 '(2 3))      ; => (1 2 3)
(cons 'a '())        ; => (a)
set-car!procedure

Mutate the car of a pair.

(define p (cons 1 2))
(set-car! p 'a)
p  ; => (a . 2)
set-cdr!procedure

Mutate the cdr of a pair.

(define p (cons 1 2))
(set-cdr! p 'b)
p  ; => (1 . b)
vector-refprocedure

Return the element at position k in the vector.

(vector-ref #(a b c) 0)  ; => a
(vector-ref #(a b c) 2)  ; => c

The index must be a non-negative integer less than the vector length.

vector-set!procedure

Set the element at position k in the vector.

(define v #(1 2 3))
(vector-set! v 1 'x)
v  ; => #(1 x 3)
vector-lengthprocedure

Return the number of elements in the vector.

(vector-length #(a b c))  ; => 3
(vector-length #())       ; => 0
make-vectorprocedure

Create a vector of the given length, optionally filled with a value.

(make-vector 3)       ; => #(#<undefined> #<undefined> #<undefined>)
(make-vector 3 'x)    ; => #(x x x)
(make-vector 0)       ; => #()
displayprocedure

Display a value to a port (default: current output port).

(display "hello")      ; prints: hello
(display 42)           ; prints: 42
(display #\newline)    ; prints a newline

Strings are printed without quotes, characters without # notation.

newlineprocedure

Write a newline to a port (default: current output port).

(newline)  ; prints a newline character
writeprocedure

Write a value in machine-readable form to a port.

(write "hello")  ; prints: "hello"
(write #\a)      ; prints: #\a
(write '(1 2))   ; prints: (1 2)

Unlike display, strings include quotes and characters include # notation.

read-exprprocedure

Read an S-expression from a string.

(read-expr "(+ 1 2)")   ; => (+ 1 2)
(read-expr "42")        ; => 42
(read-expr "\"hello\"") ; => "hello"
loadprocedure

Load and evaluate a Scheme source file.

(load "myfile.sgl")

Reads and evaluates all expressions in the file sequentially.

evalprocedure

Evaluate an expression in the current environment.

(eval '(+ 1 2))          ; => 3
(eval '(list 'a 'b 'c))  ; => (a b c)

Convert a symbol to its string name.

(symbol->string 'hello)  ; => "hello"
(symbol->string '+)      ; => "+"

Convert a string to a symbol (interned).

(string->symbol "hello")  ; => hello
(eq? (string->symbol "x") (string->symbol "x"))  ; => #t

Convert a number to its string representation.

(number->string 42)       ; => "42"
(number->string 3.14)     ; => "3.14"
(number->string 255 16)   ; => "ff"  (with radix)

Parse a string as a number, returning #f if invalid.

(string->number "42")     ; => 42
(string->number "3.14")   ; => 3.14
(string->number "ff" 16)  ; => 255  (with radix)
(string->number "abc")    ; => #f
string->listprocedure

Convert a string to a list of characters.

(string->list "hello")  ; => (#\h #\e #\l #\l #\o)
(string->list "")       ; => ()
list->stringprocedure

Convert a list of characters to a string.

(list->string '(#\h #\i))  ; => "hi"
(list->string '())         ; => ""
bytevector?procedure

Test if a value is a bytevector.

(bytevector? #u8(1 2 3))  ; => #t
(bytevector? "string")    ; => #f

Create a bytevector of the given size, optionally filled with a byte value.

(make-bytevector 3)     ; => #u8(0 0 0)
(make-bytevector 3 42)  ; => #u8(42 42 42)

Return the byte at position k in the bytevector.

(bytevector-u8-ref #u8(10 20 30) 1)  ; => 20

Set the byte at position k in the bytevector.

(define bv (make-bytevector 3 0))
(bytevector-u8-set! bv 1 255)
bv  ; => #u8(0 255 0)

Return the number of bytes in the bytevector.

(bytevector-length #u8(1 2 3))  ; => 3
srcloc?procedure

Test if a value is a source location object.

srcloc-fileprocedure

Get the file path from a source location.

srcloc-lineprocedure

Get the line number (1-based) from a source location.

srcloc-columnprocedure

Get the column number (0-based) from a source location.

Get the byte position from a source location.

srcloc-spanprocedure

Get the byte span (length) from a source location.

make-srclocprocedure

Create a source location object.

(make-srcloc "file.sgl" 10 0 100 25)

Arguments: file, line, column, position, span.

Capture the current call stack as a stack trace object.

(capture-stack-trace 0)  ; capture full stack
(capture-stack-trace 1)  ; skip 1 frame
stack-trace?procedure

Test if a value is a stack trace object.

Return the number of frames in a stack trace.

Get a frame from a stack trace as a vector.

Returns #(proc-name srcloc) or #f if index is out of bounds.

foreign?procedure

Test if a value is a foreign (C) object.

foreign-typeprocedure

Get the type tag of a foreign object.

+procedure

Add zero or more numbers.

(+)           ; => 0
(+ 1)         ; => 1
(+ 1 2 3)     ; => 6
(+ 1.5 2.5)   ; => 4.0
-procedure

Subtract numbers or negate a single number.

(- 5)         ; => -5  (negation)
(- 5 3)       ; => 2
(- 10 3 2)    ; => 5
*procedure

Multiply zero or more numbers.

(*)           ; => 1
(* 2)         ; => 2
(* 2 3 4)     ; => 24
/procedure

Divide numbers or compute reciprocal.

(/ 2)         ; => 0.5  (reciprocal)
(/ 10 2)      ; => 5
(/ 24 2 3)    ; => 4
<procedure

Test if arguments are in strictly increasing order.

(< 1 2)       ; => #t
(< 1 2 3)     ; => #t
(< 1 1)       ; => #f
>procedure

Test if arguments are in strictly decreasing order.

(> 2 1)       ; => #t
(> 3 2 1)     ; => #t
(> 1 1)       ; => #f
<=procedure

Test if arguments are in non-decreasing order.

(<= 1 2)      ; => #t
(<= 1 1)      ; => #t
(<= 2 1)      ; => #f
>=procedure

Test if arguments are in non-increasing order.

(>= 2 1)      ; => #t
(>= 1 1)      ; => #t
(>= 1 2)      ; => #f
=procedure

Test if all arguments are numerically equal.

(= 1 1)       ; => #t
(= 1 1 1)     ; => #t
(= 1 2)       ; => #f
(= 1 1.0)     ; => #t
null?procedure

Test if a value is the empty list.

(null? '())   ; => #t
(null? '(1))  ; => #f
pair?procedure

Test if a value is a pair.

(pair? '(1 . 2))  ; => #t
(pair? '(1 2))    ; => #t
(pair? '())       ; => #f
number?procedure

Test if a value is a number.

(number? 42)    ; => #t
(number? 3.14)  ; => #t
(number? "42")  ; => #f
symbol?procedure

Test if a value is a symbol.

(symbol? 'foo)    ; => #t
(symbol? "foo")   ; => #f
string?procedure

Test if a value is a string.

(string? "hello")  ; => #t
(string? 'hello)   ; => #f
vector?procedure

Test if a value is a vector.

(vector? #(1 2 3))  ; => #t
(vector? '(1 2 3))  ; => #f
procedure?procedure

Test if a value is a procedure.

(procedure? +)              ; => #t
(procedure? (lambda (x) x)) ; => #t
(procedure? 42)             ; => #f
boolean?procedure

Test if a value is a boolean.

(boolean? #t)  ; => #t
(boolean? #f)  ; => #t
(boolean? 0)   ; => #f
char?procedure

Test if a value is a character.

(char? #\a)    ; => #t
(char? "a")    ; => #f
list?procedure

Test if a value is a proper list.

(list? '(1 2 3))  ; => #t
(list? '())       ; => #t
(list? '(1 . 2))  ; => #f  (improper list)
listprocedure

Create a list from the arguments.

(list 1 2 3)    ; => (1 2 3)
(list)          ; => ()
(list 'a 'b)    ; => (a b)
lengthprocedure

Return the length of a list.

(length '(1 2 3))  ; => 3
(length '())       ; => 0
integer?procedure

Test if a value is an exact integer.

(integer? 42)    ; => #t
(integer? 3.0)   ; => #f
(integer? 3.5)   ; => #f
eof-object?procedure

Test if a value is the end-of-file object.

(eof-object? (eof-object))  ; => #t
(eof-object? #f)            ; => #f
eq?procedure

Test object identity (same memory location).

(eq? 'a 'a)           ; => #t
(eq? '() '())         ; => #t
(eq? "a" "a")         ; => unspecified
(define x '(1 2))
(eq? x x)             ; => #t
eqv?procedure

Test equivalence (same type and value).

(eqv? 1 1)        ; => #t
(eqv? 1 1.0)      ; => #f
(eqv? #\a #\a)    ; => #t
equal?procedure

Test structural equality (deep comparison).

(equal? '(1 2 3) '(1 2 3))   ; => #t
(equal? "hello" "hello")     ; => #t
(equal? #(1 2) #(1 2))       ; => #t
notprocedure

Boolean negation.

(not #f)      ; => #t
(not #t)      ; => #f
(not '())     ; => #f  (only #f is false)
(not 0)       ; => #f
gensymprocedure

Generate a unique symbol, optionally with a prefix.

(gensym)          ; => g1234 (unique each time)
(gensym "temp")   ; => temp1235
applyprocedure

Apply a procedure to a list of arguments.

(apply + '(1 2 3))        ; => 6
(apply list 'a 'b '(c d)) ; => (a b c d)
valuesprocedure

Return multiple values.

(values 1 2 3)  ; returns 3 values
(call-with-values (lambda () (values 1 2))
                  (lambda (a b) (+ a b)))  ; => 3

Call producer with no args, pass its values to consumer.

(call-with-values
  (lambda () (values 1 2))
  (lambda (a b) (+ a b)))  ; => 3

Create a parameter object (dynamic variable).

(define my-param (make-parameter 10))
(my-param)        ; => 10
(my-param 20)     ; set to 20
(my-param)        ; => 20
parameter?procedure

Test if a value is a parameter object.

promise?procedure

Test if a value is a promise.

(promise? (delay (+ 1 2)))  ; => #t
(promise? 42)               ; => #f
make-promiseprocedure

Create an already-forced promise containing a value.

(force (make-promise 42))  ; => 42
forceprocedure

Force evaluation of a promise, caching the result.

(define p (delay (begin (display "computing...") (+ 1 2))))
(force p)  ; prints "computing...", returns 3
(force p)  ; returns 3 (cached, no print)
eval-stringprocedure

Evaluate a string as Sigil code.

(eval-string "(+ 1 2)")  ; => 3

Evaluate a string in a specific module's context.

(eval-string-in-module "(+ 1 2)" (find-module '(sigil core)))

Get the metadata alist of a procedure.

(procedure-metadata my-proc)  ; => ((doc . "...") (name . my-proc))

Set the metadata alist of a procedure.

(set-procedure-metadata! my-proc '((custom . value)))

Get the module a procedure was defined in.

Set the module attribution of a procedure.

Get the arity specification of a procedure.

(procedure-arity +)  ; => (-1 . 0)  (variadic, at least 0 args)

Get the name of a procedure (symbol or #f).

(procedure-name car)  ; => car
module?procedure

Test if a value is a module.

Get the current module context.

Set the current module context.

macroexpandprocedure

Expand macros in an expression (for debugging).

(macroexpand '(when #t (display "hi")))
disassembleprocedure

Disassemble a procedure's bytecode (for debugging).

(disassemble my-proc)
find-moduleprocedure

Find a module by its name, returning #f if not loaded.

(find-module '(sigil core))  ; => #<module (sigil core)>
load-moduleprocedure

Load a module by name, returning the module object.

(load-module '(sigil json))  ; => #<module (sigil json)>

Get the list of exported symbols from a module.

(module-exports (find-module '(sigil path)))  ; => (path-join path-dirname ...)
module-refprocedure

Look up a binding in a module by name.

(module-ref (find-module '(sigil core)) 'car)  ; => #<native car>
module-nameprocedure

Get the name of a module as a list of symbols.

(module-name (current-module))  ; => (sigil user)

Add a directory to the library search path.

(add-library-path! "/my/modules")
library-pathsprocedure

Return the list of library search paths.

(library-paths)  ; => ("/usr/lib/sigil" "/home/user/lib")

Get the current time in milliseconds since epoch.

(current-milliseconds)  ; => 1702834567890
keyword?procedure

Test if a value is a keyword.

(keyword? foo:)    ; => #t
(keyword? 'foo)    ; => #f

Convert a keyword to a string (without the colon).

(keyword->string foo:)  ; => "foo"

Convert a string to a keyword.

(string->keyword "foo")  ; => foo:

Convert a keyword to a symbol.

(keyword->symbol foo:)  ; => foo

Split an argument list into positional and keyword arguments Returns (positional-args . keyword-alist) where keyword-alist is ((kw . value) ...)

keyword-refprocedure

Get a keyword value from a keyword alist Returns default if keyword not found

Check for unknown keywords and signal error if any found known-keywords is a list of keyword objects

keys-form?procedure

Usage: (lambda ((keys: x (y 10))) (+ x y))

(define (add (keys: (x 0) (y 0))) (+ x y))

(add x: 1 y: 2) ; => 3 (add x: 5) ; => 5 (y defaults to 0)

The (keys: ...) form contains keyword parameter specs: name - required keyword (no default) (name default) - optional keyword with default value

When no (keys: ...) form is present, lambda/define work normally. Helper: Check if a form is (keys: ...)

opts-form?procedure

Helper: Check if a form is (opts: ...)

rest-form?procedure

Helper: Check if a form is (rest: ...)

Helper: Check if a form is any special parameter form

Helper: Parse keyword parameter specs from (keys: spec ...) Returns list of (name has-default default-expr keyword-obj)

Helper: Parse optional positional parameter specs from (opts: spec ...) Returns list of (name default-expr)

Helper: Extract required positional params (everything before opts:/keys:/rest:)

Helper: Find and extract the (keys: ...) form from formals

Helper: Find and extract the (opts: ...) form from formals

Helper: Find and extract the (rest: ...) form from formals

Helper: Build let bindings for keyword parameters parsed-specs: ((name has-default default kw-obj) ...)

Helper: Build let bindings to extract required positional params Returns (bindings . rest-var-name) where rest-var-name is the variable holding remaining args after required params are extracted

Helper: Build let bindings for optional positional params opt-specs: ((name default) ...) Returns (bindings . rest-var-name)

lambda-transformer - The core implementation for extended lambda Used by both 'lambda' and 'fn' macros. Supports extended parameter forms: (opts: (name default) ...) - optional positional parameters (keys: name (name default) ...) - keyword parameters (rest: name) - rest parameter for remaining positional args If no special forms, expands to plain %lambda.

lambdasyntax

lambda - Extended lambda with optional and keyword parameter support

Supports standard lambda syntax plus extended parameter forms: (opts: (name default) ...) - optional positional parameters (keys: name (name default) ...) - keyword parameters (rest: name) - rest parameter for remaining positional args

For simple parameter lists, expands directly to %lambda (no overhead).

;; Simple lambda (expands to %lambda directly)
(lambda (x y) (+ x y))

;; With optional parameter
(lambda (x (opts: (y 0))) (+ x y))

;; With keyword parameter
(lambda (name (keys: (greeting "Hello")))
  (string-append greeting ", " name))

define-transformer - Extended define with function shorthand and keyword support

Handles both simple definitions and function shorthand: (define x 42) => (%define x 42) (define (f x) body...) => (%define (f x) body...) (define (f x (opts: ...)) body...) => (%define f (lambda ...))

Simple function shorthand is preserved so the C compiler can apply docstrings. Extended parameter syntax (opts:, keys:, rest:) requires lambda conversion. The input form's docstring is propagated to the output for doc attachment.

chainsyntax

Thread a value through a sequence of expressions.

Similar to SRFI-197's chain. Uses _ as the placeholder symbol. When a step contains _, the threaded value is substituted there. When no _ is present, the value is inserted as the first argument.

;; Thread-first (no placeholder)
(chain 5 (+ 3) (* 2))
; => 16 (same as (* (+ 5 3) 2))

;; Explicit placeholder
(chain '(1 2 3)
       (map (lambda (x) (* x 2)) _)
       (apply + _))
; => 12

;; Placeholder in various positions
(chain 10 (- 20 _))   ; => 10 (= 20 - 10)
(chain 5 (list 1 2 _ 4))  ; => (1 2 5 4)
some->syntax

Thread value through steps, short-circuiting on #f.

Like ->, but stops and returns #f if any step produces #f. Useful for optional/nullable value pipelines.

;; Returns #f if any step fails
(some-> user
        (dict-ref _ name:)
        (string-split " " _)
        car)

;; Short-circuits on #f
(some-> #f (+ 1 _))  ; => #f (doesn't call +)

;; Continues while truthy
(some-> 5 (+ 1 _) (* 2 _))  ; => 12
printsyntax

Print a formatted string to standard output.

Uses format directives: ~a (display), ~s (write), ~% (newline). Does not add a trailing newline.

(print "Processing ~a..." filename)
printlnsyntax

Print a formatted string to standard output with a newline.

The recommended way to print output in Sigil programs.

(println "Hello, ~a!" name)
(println "Result: ~a" (* 6 7))
eprintsyntax

Print a formatted string to standard error.

Use for error messages and diagnostics.

(eprint "Warning: ~a" message)
eprintlnsyntax

Print a formatted string to standard error with a newline.

(eprintln "Error: ~a" error-message)