Soup: A library of useful routines
A collection of useful functions not important enough to spin off into their own packages.
1 Top level interface
(require soup-lib) | package: soup-lib |
Provides all the functions exported by the modules below.
2 Additional functions for paths and files
(require soup-lib/files) | package: soup-lib |
procedure
(make-directory* dirname [permissions]) → boolean?
dirname : path-string? permissions : (integer-in 0 65535) = 511
Returns true if the directory was created, false on failure.
procedure
(delete-file* filename) → boolean?
filename : path-string?
Returns true if the file was deleted, false on failure.
procedure
(delete-directory* dirname) → boolean?
dirname : path-string?
Returns true if the directory was deleted, false on failure.
procedure
(directory-tree dirname [ #:follow-links? follow-links?]) → (listof (flat-rec-contract entry path? (cons/c path? (listof entry)))) dirname : (and/c path-string? directory-exists?) follow-links? : any/c = #t
3 Additional for and for* style comprehensions
(require soup-lib/for) | package: soup-lib |
3.1 for loops
syntax
(for/max (for-clauses ...) body-or-break ... body)
syntax
(for*/max (for-clauses) body-or-break ... body)
syntax
(for/min (for-clauses) body-or-break ... body)
syntax
(for*/min (for-clauses) body-or-break ... body)
syntax
(for/string maybe-length (for-clauses) body-or-break ... body)
maybe-length =
| #:length len
len : exact-nonnegative-integer?
The optional #:length argument can be used to give the expected length of the result as an optimization.
syntax
(for*/string (for-clauses) body-or-break ... body)
maybe-length =
| #:length len
len : exact-nonnegative-integer?
The optional #:length argument can be used to give the expected length of the result as an optimization.
syntax
(for/bytes (for-clauses) body-or-break ... body)
maybe-length =
| #:length len
len : exact-nonnegative-integer?
The optional #:length argument can be used to give the expected length of the result as an optimization.
syntax
(for*/bytes (for-clauses) body-or-break ... body)
maybe-length =
| #:length len
len : exact-nonnegative-integer?
The optional #:length argument can be used to give the expected length of the result as an optimization.
syntax
(for/list/mv (for-clauses) body-or-break ... body)
syntax
(for*/list/mv (for-clauses) body-or-break ... body)
syntax
(for/count (for-clause ...) body-or-break ... body)
syntax
(for*/count (for-clause ...) body-or-break ... body)
3.2 Sequences
procedure
(in-char-range start end) → sequence?
start : char? end : char?
procedure
(in-list-sequence seq) → sequence?
seq : sequence?
procedure
(in-regexp-matches re source) → sequence?
re : (or/c regexp? byte-regexp? string? bytes?) source : (or/c string? bytes?)
procedure
(in-regexp-positions re source) → sequence?
re : (or/c regexp? byte-regexp? string? bytes?) source : (or/c string? bytes?)
4 Hash Table functions
(require soup-lib/hash) | package: soup-lib |
procedure
(hash->vector htab) → (vectorof pair?)
htab : hash?
procedure
(hash-keys/vector htab) → vector?
htab : hash?
procedure
(hash-values/vector htab) → vector?
htab : hash?
procedure
(hash->immutable-hash htab) → immutable-hash?
htab : hash?
procedure
(eq-func->hash eq) → immutable-hash?
eq : (or/c eq? eqv? equal? equal-always?)
syntax
(do-hash-table (key value table maybe-return) body ...+)
maybe-return =
| expr
key : identifier?
value : identifier?
table : hash?
5 List-related functions
(require soup-lib/list) | package: soup-lib |
procedure
list : list? nsublists : exact-positive-integer?
procedure
list : list? size : exact-positive-integer?
5.1 Common Lisp functions
Stuff from the cons dictionary without Racket or SRFI-1 equivalents. as well as the Serapeum library and others. Sometimes with better names.
procedure
new : any/c old : any/c tree : any/c key : (-> any/c any/c) = identity test : (-> any/c any/c any/c) = eqv?
procedure
elem : any/c list : list? key : (-> any/c any/c) = identity test : (-> any/c any/c any/c) = eqv?
procedure
proc : procedure? list : list?
procedure
(append-maplist proc list ...+) → list?
proc : procedure? list : list?
procedure
(tree-equal? tree1 tree2 [#:test test]) → boolean?
tree1 : any/c tree2 : any/c test : (-> any/c any/c any/c) = eqv?
procedure
(reuse-cons x y x-y) → pair?
x : any/c y : any/c x-y : pair?
syntax
(collecting body ...)
syntax
(with-collector (collector) body ...)
Like collecting but allows a user-defined name instead of collect.
syntax
(with-collectors (collector ...) body ...)
Like with-collector but allows multiple different collectors. Returns one value per collector.
5.2 Association List functions
procedure
alist : (listof pair?) tree : any/c key : (-> any/c any/c) = identity test : (-> any/c any/c any/c) = eqv?
procedure
(rassoc item alist [#:key key #:test test]) → (or/c pair? #f)
item : any/c alist : (listof pair?) key : (-> any/c any/c) = identity test : (-> any/c any/c any/c) = eqv?
Returns a new association list formed by mapping proc over the keys and values of alist. proc must be a function of 2 arguments which returns the new value part.
Applies proc to each pair of keys and values of alist.
6 Tree functions
Functions for working on trees made of cons cells; mostly taken from Common Lisp. A few of these functions are also provided by soup-lib/list.
(require soup-lib/tree) | package: soup-lib |
procedure
(tree-equal? tree1 tree2 [#:test test]) → boolean?
tree1 : any/c tree2 : any/c test : (-> any/c any/c any/c) = eqv?
procedure
new : any/c old : any/c tree : any/c key : (-> any/c any/c) = identity test : (-> any/c any/c any/c) = eqv?
procedure
(walk-tree fun tree [ #:tag tag #:traversal traversal]) → void? fun : (-> any/c any) tree : any/c tag : (or/c continuation-prompt-tag? #f) = #f traversal : (or/c 'preorder 'inorder 'postorder) = 'preorder
Call fun in turn over each atom and cons of tree.
fun can skip the current subtree with (abort/cc tag '()).
procedure
(map-tree fun tree [ #:tag tag #:traversal traversal]) → any/c fun : (-> any/c any/c) tree : any/c tag : (or/c continuation-prompt-tag? #f) = #f traversal : (or/c 'preorder 'inorder 'postorder) = 'preorder
Walk fun over tree and build a tree from the results.
The new tree may share structure with the old tree.
(eq? tree (map-tree identity tree)) ; #t
fun can skip the current subtree with (abort/cc tag subtree), in which case subtree will be used as the value of the subtree.
Call fun on each leaf of tree.
Call fun on each leaf of tree. Return a new tree possibly sharing structure with tree.
procedure
(occurs-if test tree [ #:key key #:traversal traversal]) →
any/c boolean? test : (-> any/c any/c) tree : any/c key : (-> any/c any/c) = identity traversal : (or/c 'preorder 'inorder 'postorder) = 'preorder
Is there a node (leaf or cons) in tree that satisfies test?
Returns two values - the node that matched (Or undefined if none did) and a boolean indicating if the node was found or not.
procedure
(occurs node tree [ #:key key #:test test #:traversal traversal]) →
any/c boolean? node : any/c tree : any/c key : (-> any/c any/c) = identity test : (-> any/c any/c any/c) = eqv? traversal : (or/c 'preorder 'inorder 'postorder) = 'preorder
Is node present in tree?
Returns two values - the node that matched (Or undefined if none did) and a boolean indicating if the node was found or not.
Remove any atoms satisfying test from tree.
Pruning is defined "modulo flatten": you should get the same result from pruning, and then flattening, that you would get from flattening, and then filtering.
Also note that pruning is not defined for trees containing improper lists.
procedure
leaf : any/c tree : list? key : (-> any/c any/c) = identity test : (-> any/c any/c any/c) = eqv?
Remove leaf from tree wherever it occurs. See prune-if for more information.
7 String functions
(require soup-lib/string) | package: soup-lib |
procedure
(string-join/vector strs [sep]) → string?
strs : (vectorof string?) sep : string? = " "
procedure
(string->vector s) → (vectorof char?)
s : string?
procedure
(vector->string vc) → string?
vc : (vectorof char?)
procedure
(string-sort! s [<?]) → void?
s : mutable-string? <? : (-> char? char? any/c) = char<?
procedure
(string-escape s mapper [start stop]) → string?
s : string? mapper : (or/c dict? (-> char? (or/c string? #f))) start : exact-nonnegative-integer? = 0 stop : exact-nonnegative-integer? = (string-length s)
8 JSON functions
(require soup-lib/json) | package: soup-lib |
procedure
js : (or/c jsexpr? struct->jsexpr?)
procedure
(struct->jsexpr? obj) → boolean?
obj : any/c
syntax
(struct example (foo bar) #:methods gen:struct->jsexpr ([define (->jsexpr ex) (hasheq 'foo (example-foo ex) 'bar (example-bar ex))])) (->jsexpr (example 1 "cat"))
syntax
(json-match maybe-unsafe jsexpr match-clause ... maybe-else)
maybe-unsafe =
| #:unsafe match-clause = (number expr ...+) | ((number id) expr ...+) | (string expr ...+) | ((string id) expr ...+) | (array expr ...+) | ((array id) expr ...+) | (object expr ...+) | ((object id) expr ...+) | (null expr ...+) | boolean-clause boolean-clause = exact-boolean-clause ... | (boolean expr ...+) | ((boolean id) expr ...+) exact-boolean-clause = (true expr ...+) | (false expr ...+) maybe-else =
| (else expr ...+)
jsexpr : jsexpr?
If the optional #:unsafe keyword is given, no check is done to make sure jsexpr is actually a jsexpr?.
Example:
(json-match "foo" (number 'num) (array 'arr) (object 'obj) (string 'str) (else 'other)) ; 'str
9 Parameter extensions
(require soup-lib/parameter) | package: soup-lib |
syntax
(define-parameter id initial-value)
(define-parameter id initial-value guard) (define-parameter id initial-value guard name)
id : identifier?
initial-value : any/c
guard : (or/c (-> any/c any/c) #f)
name : symbol?
The optional guard and name arguments are as in make-parameter. The default name is id instead of 'parameter-procedure, though.
syntax
(define-boolean-parameter id initial-value) (define-boolean-parameter id initial-value name)
id : identifier?
initial-value : boolean?
name : symbol?
The optional name argument is as in make-parameter. The default name is id instead of 'parameter-procedure, though.
10 Math functions
(require soup-lib/math) | package: soup-lib |
Written in Typed Racket.
procedure
(integer-log base num) → exact-integer?
base : exact-integer? num : exact-integer?
11 Control functions
(require soup-lib/control) | package: soup-lib |
syntax
(let/comp maybe-prompt k body ...+)
maybe-prompt =
| #:prompt prompt-tag
prompt-tag : continuation-prompt-tag?
syntax
(named-let-values name ([(id ...) producer] ...) body ...+)
name : identifier?
id : identifier?
Example:
(named-let-values loop ([(a b) (values 1 2)]) (if (= b 10) a (loop (+ a b) (+ b 1))))
syntax
(named-lambda (name kw-formals ...) body ...+)
name : identifier?
(letrec ((name (lambda (kw-formals ...) body ...))) name)
Also see rec from SRFI-31.
11.1 Common Lisp forms
Things taken from Common Lisp. Implicit blocks are supported, implicit tagbodies are not.
syntax
(lret ([id init] ...) body ...)
syntax
(lret* ([id init] ...) body ...)
syntax
(block name body ...)
name : identifier?
syntax
(return-from name)
(return-from name result)
name : identifier?
syntax
(do ((var init incr) ...) (end-case result ...) body ...)
syntax
(do* ((var init incr) ...) (end-case result ...) body ...)
syntax
(dotimes (var count-form maybe-result) body ...)
maybe-result =
| expr
var : identifier?
See Common Lisp dotimes.
syntax
(dolist (var list-form maybe-result) body ...)
maybe-result =
| expr
var : identifier?
syntax
(prog (variable-declaration ...) body ...)
variable-declaration = var | (var) | (var init-form)
var : identifier?
See Common Lisp prog.
syntax
(prog* (variable-declaration ...) body ...)
variable-declaration = var | (var) | (var init-form)
var : identifier?
See Common Lisp prog*.
12 Vector functions
(require soup-lib/vector) | package: soup-lib |
procedure
(vector-map->list f vec [stsart end]) → vector?
f : (-> any/c any/c) vec : vector? stsart : exact-nonnegative-integer? = 0 end : exact-nonnegative-integer? = (vector-length vec)
procedure
(vector-shuffle vec [start end]) → vector?
vec : vector? start : exact-nonnegative-integer? = 0 end : exact-nonnegative-integer? = (vector-length vec)
procedure
(vector-shuffle! vec [start end]) → void?
vec : mutable-vector? start : exact-nonnegative-integer? = 0 end : exact-nonnegative-integer? = (vector-length vec)
procedure
(vector-update vec index f) → vector?
vec : vector? index : exact-nonnegative-integer? f : (-> any/c any/c)
procedure
(vector-update! vec index f) → void?
vec : mutable-vector? index : exact-nonnegative-integer? f : (-> any/c any/c)
procedure
(fxvector-sort! vec [start end]) → void?
vec : fxvector? start : exact-nonnegative-integer? = 0 end : exact-nonnegative-integer? = (fxvector-length vec)
procedure
(fxvector-sort vec [start end]) → fxvector?
vec : fxvector? start : exact-nonnegative-integer? = 0 end : exact-nonnegative-integer? = (fxvector-length vec)
13 I/O functions
Many of these were inspired by the Common Lisp UIOP stream package.
(require soup-lib/port) | package: soup-lib |
procedure
(call-with-input input proc [#:mode mode]) → any
input : (or/c input-port? string? bytes? path? boolean?) proc : (-> input-port? any) mode : (or/c 'text 'binary) = 'binary
procedure
(call-with-output output proc [ #:mode mode #:exists exists #:permissions permissions #:replace-permissions? replace-permissions?]) → any output : (or/c output-port? path-string? boolean?) proc : (-> output-port? any) mode : (or/c 'binary 'text) = 'binary exists : symbol? = 'error permissions : (integer-in 0 65535) = 438 replace-permissions? : any/c = #f
procedure
(call-with-null-input proc) → any
proc : (-> input-port? any)
procedure
(with-input-from-null thunk) → any
thunk : (-> any)
procedure
(call-with-null-output proc) → any
proc : (-> output-port? any)
procedure
(with-output-to-null thunk) → any
thunk : (-> any)
syntax
(with-input-file (var filename maybe-mode) body ...+)
maybe-mode =
| #:mode mode
var : identifier?
filename : path-string?
mode : (or/c 'text 'binary)
syntax
(with-output-file (var filename kw-args ...) body ...+)
var : identifier?
filename : path-string?
syntax
(with-null-input (var) body ...+)
var : indentifier?
syntax
(with-null-output (var) body ...+)
var : indentifier?
syntax
(with-input (var input maybe-mode) body ...+)
maybe-mode =
| #:mode mode
var : identifier?
input : (or/c input-port? string? bytes? path? boolean?)
mode : (or/c 'text 'binary)
syntax
(with-output (var output kw-args ...) body ...+)
var : identifier?
output : (or/c output-port? path-string? boolean?)
procedure
(read-bytes-up-to port delim) → (or/c bytes? eof-object?)
port : input-port? delim : byte?
procedure
(read-string-up-to port delim) → (or/c string? eof-object?)
port : input-port? delim : char?
14 struct utilities
(require soup-lib/struct) | package: soup-lib |
syntax
(with-slots struct-type (slot-entry ...) instance-form body ...+)
slot-entry = slot-name | (variable-name slot-name)
slot-name : identifier?
variable-name : identifier?
15 Regular Expression utilities
(require soup-lib/regexp) | package: soup-lib |
syntax
(register-groups-bind (binding ...) (pattern input maybe-start maybe-end) body ...+)
binding = var | (fn var ...) maybe-start =
| #:start start-pos maybe-end =
| #:end end-pos
pattern : (or/c regexp? byte-regexp? string? bytes?)
input : (or/c string? bytes? path? input-port?)
start-pos : exact-nonnegative-integer?
end-pos : (or/c exact-nonnegative-integer? #f)
var : (or/c identifier? #f)
fn : (or/c (-> string? any/c) (-> bytes? any/c))
syntax
(do-register-groups (binding ...) (pattern input maybe-result maybe-start maybe-end) body ...+)
maybe-result =
| result
This and the following do macros are wrapped in implicit blocks and can be returned from.
syntax
(do-scans (match-start match-end reg-starts reg-ends pattern input maybe-result maybe-start maybe-end) body ...+)
syntax
(do-matches (match-start match-end pattern input maybe-result maybe-start maybe-end) body ...+)
syntax
(do-matches-as-strings (match-var pattern input maybe-result maybe-start maybe-end) body ...+)