UTILS module – various utility functions

Various utility functions

This module contains a variety of utility functions which are otherwise missing from the implementation.

Standard scheme functions

‘Standard’ scheme functions:

Miscellaneous utilities:

Character wrangling

Case modifications:

ctype-style character classes:

These commands take both characters and integers as arguments, and match ctype(3) when given arguments in the ASCII range.

They will also behave correctly when given Unicode codepoints (as integer); thus char-alnum? will return true for Unicode general categories L or N, and so on. As a special case char-space? will return true for category Z plus the ASCII whitespace characters below U+0020, for which isspace returns true (these are category ‘C’ for Unicode). All of these functions will return #f without error, if given an argument other than a character or integer. Also note that these functions are (currently) Unicode-aware only for characters in the Base Multilingual Plane (BMP), and will return #f for any codepoints beyond that (ie, from Linear-B upwards).

The function uchar-alphabetic? identifies a character as ‘alphabetic’ in the Unicode sense, which is slightly broader than char-alnum?. See the unicode module for more discussion.

The following functions are analogous, but have no ctype counterparts.

The following functions match the ctype ones, but have no Unicode-related extensions.

The following functions are the ones defined in R5RS. They (currently) work only on characters, and are not defined on integers.

SRFIs

From SRFI-1 (a partial implementation, in some cases):

...plus intersperse, which feels like it ought to be in SRFI-1, but isn't.

From SRFI-13:

Functions

Index:

absolute-path?

Return #t if path is an absolute path, and #f otherwise.

any

(any pred? l) : Applies the predicate across the list, returning true if the predicate returns true on any application (from SRFI-1; simple case of a single list).

any applies pred to the first element of the list. If this application returns a true value, any immediately returns that value. Otherwise, it iterates, applying pred to the second element of the list, then the third, and so forth. The iteration stops when a true value is produced or the list runs out of values; in the latter case, any returns #f.

If l is a list, then the application of pred to the last element of the list is a tail call.

build-path

(build-path base sub ...) : creates a path given a base path and any number of sub-path extensions. If base is an absolute path, the result is an absolute path, otherwise the result is a relative path.

The base and each sub must be either a relative path, the symbol 'up (indicating the relative parent directory), or the symbol 'same (indicating the relative current directory).

call-with-values

The standard call-with-values procedure.

Usage: (call-with-values (lambda () (values ...)) (lambda (a1 ...) ...))

char-alnum?

Return #t if the argument is character or integer, and is alphanumeric (Unicode L or N), and #f otherwise

char-alpha?

Return #t if the argument is character or integer, and is alphabetic (Unicode L), and #f otherwise

char-blank?

Return #t if the argument is character or integer, and is blank (in terms of ctype.h), and #f otherwise

char-cntrl?

Return #t if the argument is character or integer, and is control (ctype iscntrl, plus Unicode Cc & Cf), and #f otherwise

char-digit?

Return #t if the argument is character or integer, and is a digit (Unicode N), and #f otherwise

char-graph?

Return #t if the argument is character or integer, and is graphic (in terms of ctype.h), and #f otherwise

char-lower?

Return #t if the argument is character or integer, and is lower-case alphabetic (Unicode Ll), and #f otherwise

char-mark?

Return #t if the argument is character or integer, and is mark (Unicode M), and #f otherwise

char-nbsp?

Return #t if the argument is character or integer, and is true if the specified codepoint is a non-breaking space, and specifically whether it is U+00A0 NBSP, or U+2007 Figure Space or U+202F Narrow NBSP. Compare char-wordbreak?., and #f otherwise

char-print?

Return #t if the argument is character or integer, and is printing (in terms of ctype.h), and #f otherwise

char-punct?

Return #t if the argument is character or integer, and is punctuation (Unicode P), and #f otherwise

char-space?

Return #t if the argument is character or integer, and is a space (Unicode Z, but including the ASCII whitespace characters below U+20).

There is more than one reasonable definition of whitespace. The whitespace characters below U+20, such as newline and tab, are not whitespace in Unicode terms, but we include them here in order to match POSIX/ctype isspace; this also includes non-breaking spaces as whitespace (though, eg, Java's whitespace definition doesn't)., and #f otherwise

char-symbol?

Return #t if the argument is character or integer, and is symbol (Unicode S), and #f otherwise

char-upper?

Return #t if the argument is character or integer, and is upper-case alphabetic (Unicode Lu or Lt), and #f otherwise

char-wordbreak?

Return #t if the argument is character or integer, and is true if the specified code point is a whitespace character according to Java/ICU.

This is similar to char-space?, except that it does not include the non-breaking space codepoints (U+00A0 NBSP, or U+2007 Figure Space or U+202F Narrow NBSP). It is therefore defined to match the Java Character.isWhitespace function; See Unicode ICU docs uisWhitespace function for further discussion., and #f otherwise

char-xdigit?

Return #t if the argument is character or integer, and is a hex-digit (in terms of ctype.h), and #f otherwise

circular-list

Constructs a circular list of the elements (from SRFI-1).

(circular-list 'z 'q) => (z q z q z q ...)`

current-directory

(current-directory) : return the current working directory, as a string.

define-values

Standard form: (define-values (a b) (values 1 2)) defines a and b to have the given values.

define/trace

Like (define ...). but tracing calls to the function (for debugging)

delay

(delay body ...) : Creates a ‘promise’ that, when forced, evaluates the bodys to produce the value of the last expression in the body. The result is then cached, so further uses of force produce the cached value immediately.

drop

(drop l i) : return all but the first i elements of list l (from SRFI-1)

drop-right

(drop-right l i) : returns all but the last i elements of l (from SRFI-1)

every

(every pred? l) : Applies the predicate across the list or iterator, returning true if the predicate returns true on every application (from SRFI-1; simple case of a single list).

every applies pred to the first element of the list parameter. If this application returns false, every immediately returns false. Otherwise, it iterates, applying pred to the second element of the list, then the third, and so forth. The iteration stops when a false value is produced or the list runs out of values. In the latter case, every returns the true value produced by its final application of pred.

When l is a list, the application of pred to the last element of the list is a tail call.; when l is an iterator, the function still returns the last application of pred?, but it is not a tail-call.

If the list or iterator has no elements, every simply returns #t.

explode-path

(explode-path path) : split the path into a list of path components.

If the path is absolute, then the first component in the list will be "/". Path elements "." and ".." will be replaced by symbols same and up respectively.

filter

(filter pred? list) : Return all the elements of list that satisfy predicate pred?. The list is not disordered -- elements that appear in the result list occur in the same order as they occur in the argument list.

The input ‘list’ may also be an iterator, or something which has an implicit iterator.

From SRFI-1.

flatten

(flatten v) : Flattens an arbitrary S-expression structure of proper lists into a single list. More precisely, v is treated as a binary tree where pairs are interior nodes, and the resulting list contains all of the non-null leaves of the tree in the same order as an in-order traversal.

Example:

> (flatten '((a) b (c (d) e) ()))
'(a b c d e)
> (flatten 'a)
'(a)

[specification taken from Racket, but with the added requirement that the input have no improper lists].

fold

(fold kons knil l) : The fundamental list iterator.

Given a list (e1 e2 ... en), this evaluates to

(kons en ... (kons e2 (kons e1 knil)) ... )

The input ‘list’ may also be an iterator, or something which has an implicit iterator.

From SRFI-1.

force

(force v) : If v is a promise, then the promise is forced to obtain a value. If the promise has not been forced before, then the result is recorded in the promise so that future forces on the promise produce the same value.

If v is not a promise, then it is returned as the result.

getopt

(getopt spec [:command-line '("command" "arg" ...) : Given a command-line (which defaults to *command-line* if the second argument is not present), parse it according to the option spec in the first argument.

The spec is a list of lists with at least three elements: either (#\c "docstring" expr ...) or (#\c arg "docstring" expr ...). This will detect an option -c (or -c arg in the second case), and evaluate the expr ..., for side-effects.

Example:

(getopt '((#\a "set 'a' true" (set! a-flag #t))))

will take a *command-line* of '("name" "-a" "one" "two"), set a-flag to true, and evaluate to '("one" "two").

If there is no -h option, then this synthesises one from the docstrings.

Returns the command name (the first item in *command-line*), an alist of detected options plus the return from their handler, and the remainder of the argument list, as multiple values.

intersperse

(intersperse inter l) : return a new list, with object inter between each element of the list l.

Thus (intersperse 'x '(a b c)) evaluates to (a x b x c).

last

(last l) : return the last element of the non-empty, finite list L (from SRFI-1)

last-pair

(last-pair l) : return the last pair in the non-empty, finite list L (from SRFI-1)

make-set/eqv

(make-set/eqv l) : lookup, (listof symbol?) -> (symbol? -> boolean?). Given a list of symbols, return a function f s.t. (f 'x) is true if 'x was in the list. Also

path->complete-path

(path->complete-path path [base]) : turn a path into a complete path. If path is already complete, then it is returned; if not, it is appended to base. It is an error if base is not a complete path.

path-replace-extension

(path-replace-extension path ext) : Returns a path that is the same as path, except that the extension for the last element of the path (including the extension separator) is changed to ext. If the last element of path has no extension, then ext is added to the path.

An extension is defined as a . that is not at the start of the path element followed by any number of non-. characters/bytes at the end of the path element, as long as the path element is not a directory indicator like "..".

promise?

(promise? p) : true if p is a promise, created by (delay)

receive

(receive (v ...) expr body...) : receive multiple values [from SRFI-8].

Example:

(receive (v1 v2)
    (values 1 2)
  (printf "v1=~s~%" v1)
  (list v2 v1))

prints v1=1 and evaluates to (2 1).

relative-path?

Return #t if path is an relative path, and #f otherwise.

resolve-file

(resolve-file/kpse fn ext [:error-if-not-found? #t]) : Resolve a file to a full path, using kpsewhich. Given a file fn, try to resolve this to a full path, using the kpathsea mechanism, and trying both without and with the ext appended.

If keyword :error-if-not-found? is true (the default), then throw a beastie-error if no file is found; if this is false return #f if no file can be found.

Since it uses kpsewhich, it respects the environment variables $BIBINPUTS, etc.

setenv

(setenv envvar (or/c string? #f)) : set the environment variable envvar to the given value. If the value is #f, the environment variable is deleted.

showbytes/hex

Debugging: show the bytes in the given string.

split-at

(split-at l idx) : splits the list L at index I, returning a list of the first I elements, and the remaining tail, as multiple values. It is equivalent to

(values (take x i) (drop x i))

(from SRFI-1)

split-path

(split-path path) : splits a filesystem path into components

(split-path string?) -> (or/c string? 'relative #f)
                        (or/c string? 'up 'same)
                        boolean?

Deconstructs path into a smaller path and an immediate directory or file name. Three values are returned:

base is either

name is either

must-be-dir? is #t if path explicitly specifies a directory (e.g., with a trailing separator), #f otherwise.

This doesn't do any processing of redundant separators.

string->hash

string->hash : string? -> integer? : Given a string, return an integer hash for it. This is an unsophisticated hash function, merely using the K&R/Java hash function

string-index

(string-index s c [:start 0] [:end #f]) : Return the index of the first character in s which is c, where c is a procedure, character, or string; in the last case, the procedure returns the first index containing any character in the string c [From SRFI-13, but with 'char-class' represented as a string].

The :start and :end keyword arguments delimit the scan, and default to the start and end of the string; these arguments are indexes into the string, with end indicating the index one past the last character to be considered; end may be #f to indicate the end of the string.

Returns #f if the character is not present.

string-index-right

(string-index-right s c [:start 0] [:end #f]) : As string-index, but searching leftwards from the end.

string-join

(string-join l [delim [grammar]]) : join the list of strings l, separated by string delim (default " ").

The grammar argument is a symbol that determines how the delimiter is used, and defaults to 'infix.

string-prefix?

(string-prefix? s1 s2) : Is s1 a prefix of s2? (SRFI-13 without optional arguments)

string-split

(string-split s c) : Split a string at a given character. Argument s must be a string?. Argument c can be a character, a predicate, or a string containing split characters. The empty string is split to an empty list (This isn't in SRFI-13, which instead has string-tokenize, which splits based on the char-set of the items to be included).

Repeated separator characters result in empty fields. That is (string-split "a:b::c" #\:) produces '("a" "b" "" "c").

string-suffix?

(string-suffix? s1 s2) : Is s1 a suffix of s2? (SRFI-13 without optional arguments)

string-tokenize

(string-tokenize s) : split the string s into a list of substrings, where each substring is a maximal non-empty contiguous sequence of characters separated by whitespace.

This is a (still) cut-down version of the function from SRFI-13, restricted to whitespace, and without the start and end parameters.

string-trim

(string-trim s c) : Trim whitespace from the start of string s. Argument c can be a character, a predicate, or a string containing characters to trim. (from SRFI-13, but currently without the start/end arguments)

string-trim-both

As with string-trim, but trimming from both sides

string-trim-right

As with string-trim, but trimming from the right

stringify

(stringify x) : Turn X into a string, one way or another.

stringify/true

(stringify/true x) : like (stringify x), unless x is #f, when it evaluates to #f. Special-casing #f means this is useful alongside functions such as maybe-sprintf`.

subprocess

subprocess : string? ... -> (or string? #f)(subprocess "program" ...) : Call the first argument, as a command, passing the others as arguments. Returns stdout as a string, or #f if the command returns non-zero, or raise 'subprocess if the command can't be run.

If the PROGRAM doesn't start with a slash, '/', it is looked up in the path.

symbol<?

symbol<? : symbol? ... -> boolean? : true if the symbols s1... are strictly ordered. The comparison is equivalent to that which would arise from using symbol->string.

take

(take l i) :return the first i elements of list l (from SRFI-1)

take-right

(take-right l i) : returns the last i elements of list l (from SRFI-1)

uchar-alphabetic?

Returns #t if the character has the Unicode ‘Alphabetic’ property. That is, it is lowercase, uppercase, of classes Lt, Lm, Lo, or Nl, or is ‘other alphabetic’. See the Unicode Character Database for details.

The induced set of characters is a superset of that induced by char-letter?. This function is also distinct from the s7 char-alphabetic? function, which is defined only for ASCII characters (but it overlaps with that function in that range).

uchar-downcase

Change the given character to lowercase. Analogous to uchar-upcase, qv.

uchar-titlecase

Change the given character to titlecase. Analogous to uchar-upcase, qv.

uchar-upcase

(uchar-upcase c) : change the given character to uppercase.

This matches char-upcase for ASCII characters, but it also works correctly for other Unicode characters. The function accepts either a character or an integer argument, and returns an integer. If given an argument of another type, including string types, it returns the argument unchanged.

uchar-word-character?

Returns #t if the character argument should be regarded as a part of a word. The induced character set includes uchar-alphabetic? (and thus char-alpha?), but includes (the Unicode categories) diacritics, extender characters and join-control characters.

There isn't a formal definition of this set within Unicode, but this set has been described as ‘a decent approximation of what is (naively) expected to fall within an “alphabetic” string for most scripts’.

zip

(zip l1 l2 ...) -> list : If zip is passed n lists, it returns a list as long as the shortest of these lists, each element of which is an n-element list comprised of the corresponding elements from the parameter lists.

(zip '(one two three)
     '(1 2 3)
     '(odd even odd even odd even odd even))
    => ((one 1 odd) (two 2 even) (three 3 odd))

(zip '(1 2 3)) => ((1) (2) (3))

At least one of the argument lists must be finite:

(zip '(3 1 4 1) (circular-list #f #t))
    => ((3 #f) (1 #t) (4 #f) (1 #t))

(from SRFI-1)

Norman
2026 August 02