Control Feature Procedures

Overview

This section documents procedures that do not operate on a specific data type but instead provide general-purpose facilities for program control, execution, and convenience.

Control and Evaluation

eval and apply are the core meta-programming facilities inherited from Scheme’s Lisp heritage. eval allows programs to construct and evaluate expressions at runtime, bridging the gap between data and code — a natural consequence of Scheme’s homoiconicity, where code and data share the same list representation. apply allows a procedure to be called with its arguments supplied as a list, which is invaluable when the number of arguments is not known until runtime. Both are standard R7RS procedures, though this implementation’s eval deviates in being unary — evaluation always takes place in the global environment.

System Interface

load reads and evaluates a file of Scheme source code, providing the primary mechanism for organising programs across multiple files. exit terminates the interpreter with an optional status code, following the Unix convention that zero denotes success and non-zero denotes failure. The boolean shorthand — #t for success, #f for failure — is a convenience that maps naturally onto Scheme idioms. command-line provides access to the arguments passed to a script, enabling programs to behave differently based on their invocation context.

Polymorphic Convenience Procedures

len, idx, and rev are non-standard extensions that provide a uniform interface across the ordered and compound types: lists, vectors, bytevectors, and strings. Rather than remembering which type-specific procedure applies in a given context — string-length versus vector-length versus list-length — these procedures dispatch automatically on the type of their argument. They are particularly useful in generic or polymorphic code where the specific sequence type is not known in advance, and in interactive use where brevity is valued. Code that requires the clarity of explicit type dispatch should prefer the type-specific procedures.

Procedure Documentation

eval

(eval expr)

Evaluates expr as a Scheme expression in the global environment and returns the result. expr may be any object that has a valid external representation as an expression, including a quoted list representing a procedure call.

Note

This implementation’s eval is unary and always evaluates in the global environment. R7RS specifies a second argument for the environment in which evaluation takes place (e.g. (interaction-environment)), but first-class environments are not currently supported. Any environment argument passed will be silently ignored.

Parameters:

expr (any) – The expression to evaluate.

Returns:

The result of evaluating expr.

Return type:

any

Example:

--> (eval '(+ 1 2))
3
--> (eval '(define x 42))
--> x
42
--> (eval (list '+ 1 2 3))
6
--> (let ((op '+)) (eval (list op 10 20)))
30

apply

(apply proc arg1 ... args)

Calls proc with the elements of the list formed by appending any individual arg1 … arguments to the final args list as its actual arguments. The final argument must be a proper list; all preceding arguments after proc are prepended to it individually.

apply is implemented as a tail call: the result is returned as a tail-call sentinel to the interpreter’s evaluator for further evaluation, meaning it participates correctly in tail-call optimisation and does not consume additional stack depth.

Parameters:
  • proc (procedure) – The procedure to call.

  • arg1 (any) – Zero or more individual arguments to prepend to args.

  • args (list) – A proper list of the remaining arguments to pass to proc.

Returns:

The result of calling proc with the assembled argument list.

Return type:

any

Example:

--> (apply + '(1 2 3))
6
--> (apply + 1 2 '(3 4))
10
--> (apply string '(#\h #\e #\l #\l #\o))
"hello"
--> (apply max '(3 1 4 1 5 9 2 6))
9
--> (apply map (list char-upcase '("hello" "world")))
("HELLO" "WORLD")

load

(load filename)

Reads and evaluates Scheme expressions and definitions from the file named by filename sequentially in the global environment. Returns #t on success, or #f if an error is encountered during loading, in which case a message is printed to standard error.

Note

R7RS specifies an optional second environment argument to load. This implementation always loads into the global environment; no environment argument is supported.

Parameters:

filename (string) – The path to a file containing Scheme source code.

Returns:

#t on success, #f on error.

Return type:

boolean

Example:

--> (load "mylib.scm")
#t
--> (load "init.scm")
#f

exit

(exit [code])

Terminates the running program. If code is omitted, exits with status 0 (success). If code is a boolean, #t maps to exit status 0 and #f maps to exit status 1. If code is an integer, it is passed directly to the system as the exit status code. If running in the REPL, the session history is saved before exiting.

Parameters:

code (boolean or integer) – An optional exit status. A boolean #t exits with 0, #f exits with 1, and an integer exits with that value directly.

Returns:

This procedure does not return.

Example:

--> (exit)
--> (exit #t)
--> (exit #f)
--> (exit 42)

command-line

(command-line)

Returns a list of command-line arguments passed to the script being interpreted. The zeroth element is always the script name. When called from the REPL, returns the empty list.

Script arguments must be separated from interpreter arguments using --, so that the interpreter can distinguish between arguments intended for itself and those intended for the script. For example:

$ cozenage myscript.scm -- arg1 arg2
Returns:

A list of strings representing the command-line arguments, or the empty list when called from the REPL.

Return type:

list

Example:

--> (command-line)
()

When invoked as cozenage myscript.scm -- foo bar, within myscript.scm:

--> (command-line)
("myscript.scm" "foo" "bar")

len

(len obj)

Returns the length of obj as an exact integer. Accepts lists, vectors, bytevectors, strings, sets, and hashes. For strings, returns the number of characters (Unicode code points), not the number of underlying bytes. For sets and hashes, returns the number of members or key-value pairs respectively. Raises an error if obj is not a compound or sequence type.

Note

This is a non-standard convenience procedure. For type-specific length procedures, see list-length, vector-length, string-length, and bytevector-length.

Parameters:

obj (list, vector, bytevector, string, set, or hash) – A compound or sequence object.

Returns:

The length of obj.

Return type:

integer

Example:

--> (len '(1 2 3))
3
--> (len #(1 2 3))
3
--> (len "café")
4
--> (len #{1 2 3})
3
--> (len #["a" 1 "b" 2])  ; For hashes, key/value pairs count as one item
2
--> (len "")
0

idx

(idx seq i)
(idx seq start end)
(idx seq start end step)

Polymorphic subscript and slicing procedure. With a single index i, returns the element of seq at that position. With start and end, returns a new sequence containing elements from start (inclusive) to end (exclusive). With step, returns every step-th element in that range. Accepts lists, vectors, bytevectors, and strings. All indices are zero-based.

With a single index, delegates to the type-specific ref procedure for each type (list-ref, vector-ref, bytevector-ref, string-ref). Slicing is supported for lists and vectors; bytevectors and strings support single-element access only.

Note

This is a non-standard convenience procedure.

Parameters:
  • seq (list, vector, bytevector, or string) – A sequence to subscript or slice.

  • i (integer) – A zero-based index for single-element access.

  • start (integer) – The index of the first element to include in a slice.

  • end (integer) – The index past the last element to include in a slice.

  • step (integer) – The stride between selected elements. Defaults to 1.

Returns:

The selected element or a new sequence containing the selected elements.

Return type:

any, list, or vector

Example:

--> (idx '(a b c d) 1)
b
--> (idx #(10 20 30 40 50) 2)
30
--> (idx '(a b c d e) 1 4)
(b c d)
--> (idx #(0 1 2 3 4 5 6) 0 7 2)
#(0 2 4 6)
--> (idx "hello" 1)
#\e

rev

(rev seq)

Returns a new sequence containing the elements of seq in reverse order. Accepts lists, vectors, bytevectors, and strings. For strings, reversal is grapheme-aware: multi-codepoint grapheme clusters (such as accented characters and emoji with combining sequences) are kept intact rather than having their constituent code points reversed independently.

Note

This is a non-standard convenience procedure. For the type-specific list procedure, see reverse.

Parameters:

seq (list, vector, bytevector, or string) – A sequence to reverse.

Returns:

A new sequence with the elements of seq in reverse order.

Return type:

list, vector, bytevector, or string

Example:

--> (rev '(1 2 3))
(3 2 1)
--> (rev #(1 2 3))
#(3 2 1)
--> (rev "hello")
"olleh"
--> (rev "café")
"éfac"