https://github.com/ar-nelson/schemepunk
A batteries-included extended standard library for seven R7RS Scheme dialects.
https://github.com/ar-nelson/schemepunk
chibi-scheme chicken gauche gerbil kawa larceny r7rs-scheme sagittarius scheme scheme-library
Last synced: 4 months ago
JSON representation
A batteries-included extended standard library for seven R7RS Scheme dialects.
- Host: GitHub
- URL: https://github.com/ar-nelson/schemepunk
- Owner: ar-nelson
- License: other
- Created: 2020-03-30T02:53:33.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2021-05-12T14:07:38.000Z (about 5 years ago)
- Last Synced: 2025-03-15T00:12:54.969Z (over 1 year ago)
- Topics: chibi-scheme, chicken, gauche, gerbil, kawa, larceny, r7rs-scheme, sagittarius, scheme, scheme-library
- Language: Scheme
- Homepage:
- Size: 1.38 MB
- Stars: 94
- Watchers: 11
- Forks: 4
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Schemepunk
A kitchen-sink utility library for several R7RS Scheme dialects.
This library is **unfinished and under heavy development**. It's optimized for
the needs of a few related projects I'm working on, mostly programming language
interpreters and compilers.
To use this library, drop this repository in a `schemepunk` directory in your
project, ideally as a Git submodule. The shell scripts in `scripts` can run unit
tests or Scheme applications in all of Schemepunk's supported Scheme dialects,
and they know how to find and include `.sld` library dependencies, even in
Schemes that don't natively support this.
## Supported Schemes
- [Chibi][chibi]
- [Chicken][chicken]\*
- [Gauche][gauche]
- [Gerbil][gerbil]
- [Kawa][kawa]
- [Larceny][larceny]
- [Sagittarius][sagittarius]
\* Chicken requires these eggs: `r7rs`, `utf8`, `box`, `srfi-41`, `srfi-69`,
`srfi-99`, `srfi-113`, `srfi-128`, `srfi-133`, and `ioctl`. (`ioctl` is only
required on Unix-based OSes.)
Schemepunk can also be built as a Chicken egg. Just run `chicken-install`
(possibly with `-sudo`) in the repo's root directory.
## Modules
- [`(schemepunk box)` - Boxes](#schemepunk-box)
- [`(schemepunk btree)` - Persistent B-trees](#schemepunk-btree)
- [`(schemepunk command)` - Command-line argument parsing](#schemepunk-command)
- [`(schemepunk comparator)` - Comparators](#schemepunk-comparator)
- [`(schemepunk datalog)` - Logic programming (WIP)](#schemepunk-datalog)
- [`(schemepunk flexvector)` - Flexvectors (dynamic arrays)](#schemepunk-flexvector)
- [`(schemepunk function)` - Functional programming utilities](#schemepunk-function)
- [`(schemepunk generator)` - Generators and accumulators](#schemepunk-generator)
- [`(schemepunk hash-table)` - Hash tables](#schemepunk-hash-table)
- [`(schemepunk hook)` - Hooks](#schemepunk-hook)
- [`(schemepunk json)` - JSON](#schemepunk-json)
- [`(schemepunk list)` - List utilities](#schemepunk-list)
- [`(schemepunk mapping)` - Persistent mappings](#schemepunk-mapping)
- [`(schemepunk multimap)` - Multimaps](#schemepunk-multimap)
- [`(schemepunk path)` - File path utilities](#schemepunk-path)
- [`(schemepunk random)` - Random number generation](#schemepunk-random)
- [`(schemepunk set)` - Sets and bags](#schemepunk-set)
- [`(schemepunk show)` - Monadic text formatting](#schemepunk-show)
- [`(schemepunk show debug)` - Simple pretty-printing](#schemepunk-show-debug)
- [`(schemepunk show report)` - Stylish error reports](#schemepunk-show-report)
- [`(schemepunk sort)` - Sorting](#schemepunk-sort)
- [`(schemepunk stream)` - Streams](#schemepunk-stream)
- [`(schemepunk string)` - String utilities](#schemepunk-string)
- [`(schemepunk syntax)` - Utility macros](#schemepunk-syntax)
- [`(schemepunk term-colors)` - ANSI terminal colors](#schemepunk-term-colors)
- [`(schemepunk test)` - Unit test framework](#schemepunk-test)
- [`(schemepunk vector)` - Vector library](#schemepunk-vector)
### `(schemepunk box)`
Polyfilled alias for [SRFI 111 (Boxes)][srfi111]. Exports one additional
procedure:
- `(update-box! )` is equivalent to
`(set-box! ( (unbox )))`.
### `(schemepunk btree)`
An original implementation of persistent B-trees, used to implement `(schemepunk
mapping)` on all Schemes except Gauche¹.
Schemepunk's B-tree mappings are frequently 2-3 times faster than the
red-black-tree reference implementation of SRFI 146, and significantly faster
when constructing large mappings. This library includes linear-update
`!`-suffixed mutation procedures, for yet another performance boost.
You usually want to use this module through `(schemepunk mapping)`, but, if you
want to use the B-tree data structure directly, this module provides these
low-level procedures:
- `(btree )`
- `(btree? )`
- `(btree-key-comparator )`
- `(btree-empty? )`
- `(btree-copy )`
- `(btree-ref )` *(`failure-proc` is optional)*
- `(btree-set )`
- `(btree-set! )`
- `(btree-delete )`
- `(btree-delete! )`
- `(btree-pop )` *(returns two values: `(key . value)` and modified btree)*
- `(btree-pop! )` *(returns one value: `(key . value)`)*
- `(btree-fold )`
- `(btree-fold-right )`
- `(alist->btree )`
- `(btree->alist )`
- `(btree-subset? )`
- `(btree=? )`
- `(btree )`
- `(btree-hash )`
- `(make-btree-comparator )`
- `btree-comparator`
¹ _B-trees are faster than most Schemes' SRFI 146, but Gauche's `` is
usually even faster._
### `(schemepunk command)`
A command-line argument parser, loosely based on Chibi Scheme's
[`(chibi app)`][chibi-app]. The parser procedures take _app specifications_,
which are nested alists. For example, the zoo demo from the `(chibi app)`
documentation can be written like this for `(schemepunk command)`:
```scheme
'((name "Zookeeper Application")
(doc "Example application from (chibi app) documentation, adapted for \
(schemepunk command).")
(copyright "Copyright (c) 2020")
(options
(animals
(type (list symbol))
(doc "list of animals to act on (default all)"))
(lions
(short #\l)
(doc "also apply the action to lions")))
(commands
(feed
(short-doc "feed the animals")
(doc-args ...))
(wash
(short-doc "wash the animals")
(doc-args ...)
(options (soap)))
(help
(short-doc "print help")))
(require-command #t))
```
`(schemepunk command)` supports both `-` short options and `--` long options.
Short options can be grouped: `-xyz` = `-x -y -z`. Values after option names can
follow either a space or `=`. Git-style commands, with their own documentation
and option lists, are also supported.
#### Procedures
- `(run-application )` parses the list of
command-line arguments `` using the specification ``.
The first element of `` should be the executable name.
If parsing is successful, `` is tail-called with five arguments:
- `options`, an alist of the `-` or `--` options passed to the app
- `args`, a list of all non-option and non-command arguments passed to the
app, as strings
- `command`, the command name passed to the app, or `#f` if there is no
command
- `command-options`, an alist of all options that occurred after the command
name
- `command-args`, a list of all non-option arguments that occurred after the
command name, as strings
If parsing fails, a usage message is printed to `(current-error-port)`, and
then Scheme is terminated with `(exit 1)`.
- `(parse-app )` parses the list of command-line arguments
`` using the specification ``, and returns five values,
corresponding to the five arguments passed to `run-application`'s ``. If
parsing fails, it will raise an error object for which `command-error?` is
`#t`.
- `(app-usage )` is a `(schemepunk show)` formatter that
prints a usage message for the app specification ``. The executable name
is taken from the first element of the list ``.
- `(command-usage )` is a `(schemepunk show)`
formatter that prints a usage message for the command `` in the app
specification ``. The executable name is taken from the first element of
the list ``.
- `app-help` and `command-help` are like `app-usage` and `command-usage`, but
also include `name`, `doc`, and `copyright` if they are present in the
specification.

- `(command-error? )` is a type predicate for the error objects raised by
`parse-app`.
#### App specification
All alist keys are optional; the empty specification `'()` is valid but has no
documentation and accepts no options.
- `name` - name of the application, displayed at the start of the app's help
text
- `doc` - documentation paragraph, displayed at the start of the app's help text
- `doc-args` - symbols or strings that describe the app's arguments in usage
text; e.g., ` "[]"`
- `copyright` - copyright message displayed at bottom of help text
- `options` - alist of options for the app; each option's key is also its
default long option name
- `commands` - alist of commands for the app; each command's key is also its
name
- `require-command` - if `#t`, app exits with an error if no command is provided
- `default-help-option` - if `#t`, an option is added with long name `--help`
and short name `-h` that, if present, causes `run-application` to print the
app's help text and exit
- `default-help-command` - if `#t`, a command named `help` is added that, if
selected and passed a command name as its only argument, causes
`run-application` to display that command's help text and exit
##### Option
- `type` - data type of the option's value, defaults to `boolean`; options are
`boolean`, `symbol`, `char`, `string`, `integer`, `real`, `sexp`, and
`(list )`
- `long` - long option aliases for this option (symbols or strings)
- `short` - short option aliases for this option (chars)
- `doc` - description of this option, displayed in usage text
- `doc-value` - name of the option's value, displayed in usage text, defaults to
value of `type`
##### Command
- `short-doc` - documentation shown in the app's usage text
- `doc` - longer documentation shown in the command's usage text
- `doc-args` - symbols or strings that describe the command's arguments in usage
text; e.g., ` "[]"`
- `options` - alist of options for the command; each option's key is also its
default long option name
### `(schemepunk comparator)`
Polyfilled alias for [SRFI 128 (Comparators)][srfi128] with [SRFI 162
(Comparators sublibrary)][srfi162] extensions. These comparators are used by all
of Schemepunk's ordered data structures: sets, bags, hash tables, mappings, and
multimaps.
In addition to SRFIs 128 and 162, this module exports several extra procedures,
macros, and comparators:
- `symbol-comparator` is a default comparator for symbols.
- `number-comparator` is a default comparator for numbers that is more general
than SRFI 162's `real-comparator`.
- `fixnum-comparator` is a default comparator for fixnums (small integers).
- `(make-sum-comparator …)` creates a comparator for the _sum type_
of the types represented by each comparator in ``. For example,
`(make-sum-comparator boolean-comparator number-comparator string-comparator)`
returns a comparator for values that may be either booleans, numbers, or
strings.
- `(hash-lambda () …)` is equivalent to
`(lambda () …)`, except that it takes and ignores an optional
second argument. This macro should be used to define hash functions. Some
Schemes' SRFI 128 or SRFI 69 implementations expect hash functions to take one
parameter, others expect two, and this is the only way to write hash functions
that are compatible with all of them.
- `(identity-hash )` is a reference-identity-based hash function, used by
`eq-comparator`. It should always return different hashes for values that are
not `eq?`. This is a primitive operator that cannot be implemented portably,
so it is always an alias for the host Scheme's identity hash function.
- `(identity )` is an identity-based ordering function, used by
`eq-comparator`. It compares the `identity-hash` of `` and ``.
### `(schemepunk datalog)`
WIP simple Datalog logic programming library. Still unfinished, not much to see
here. So far, it supports semi-naive evaluation and stratified negation.
### `(schemepunk flexvector)`
Polyfilled alias for [SRFI 214 (Flexvectors)][srfi214]. No additional exports.
### `(schemepunk function)`
Combinators commonly used in functional languages like Haskell or ML.
- `(identity )` returns ``.
- `(const )` returns a procedure that takes one argument, ignores it, and
returns ``.
- `(flip )` takes a procedure of two arguments ``, and returns a new
procedure `(g x y)` that calls `( y x)`.
- `(compose …)` composes procedures right-to-left: `(compose f g)` returns
a procedure `(composed x)` that calls `(f (g x))`.
- `(bind …)` composes procedures left-to-right: `(bind f g)` returns a
procedure `(composed x)` that calls `(g (f x))`.
- `(complement )` takes a predicate `` and returns its complement
(a predicate that always returns the opposite boolean value).
### `(schemepunk generator)`
Polyfilled alias for [SRFI 158 (Generators and Accumulators)][srfi158]. Exports
one additional procedure:
- `(gfork )` returns two values, both of which are generators that produce
the same sequence of values as ``.
### `(schemepunk hash-table)`
Polyfilled alias for [SRFI 125 (Intermediate Hash Tables)][srfi125]. No
additional exports. Uses comparators from `(schemepunk comparator)`.
### `(schemepunk hook)`
Polyfilled alias for [SRFI 173 (Hooks)][srfi173]. No additional exports.
### `(schemepunk json)`
Minimal JSON parser. Can encode and decode JSON to/from a simple Scheme
representation:
| JSON value | Scheme representation |
| ------------------ | ----------------------- |
| `null` | The symbol `null` |
| `true` | The symbol `true` |
| `false` | The symbol `false` |
| `3.14` | `3.14` |
| `"foo"` | `"foo"` |
| `[1, 2, 3]` | `#(1 2 3)` |
| `{}` | `()` |
| `{"a": 1, "b": 2}` | `(("a" . 1) ("b" . 2))` |
- `(read-json )` reads one JSON value from a port and returns it. ``
is optional.
- `(write-json )` writes one JSON value to a port. Anything that
is not a valid Scheme representation of JSON will be written as ``.
`` is optional.
- `string->json` and `json->string` convert JSON strings to/from their Scheme
representations.
A simple event-based parser is also available, for performance:
- `(make-json-context)` creates a new context object.
- `(read-json-event )` reads one JSON event from a port. It
returns two values: `(event payload)`, where `event` is the event type and
`payload` is an optional value. It takes a context object, which keeps track
of nesting and object keys. `` is optional.
| Event | Payload |
| -------------- | ---------------------- |
| `null` | `#f` |
| `boolean` | Value (`#t` or `#f`) |
| `number` | Value (number) |
| `string` | Value (string) |
| `array-start` | `#f` |
| `array-end` | `#f` |
| `object-start` | `#f` |
| `key` | Key name (string) |
| `object-end` | `#f` |
| `error` | Error message (string) |
### `(schemepunk list)`
Alias for [SRFI 1 (List Library)][srfi1]. Because all supported Schemes include
this SRFI, there is no polyfill.
In addition to SRFI 1, this module exports several extra procedures:
- `(snoc )` is a reverse `cons`; it constructs a list by appending
`elem` to the end of `list`.
- `(map-with-index )` is like `map`, but it expects `fn` to take two
arguments. The second argument is the index of the list item.
- `(intercalate )` constructs a new list by inserting
`` between each pair of elements in ``.
- `(list-gen )` is a generator-style unfold. `fn` is a lambda that takes
two arguments, usually named `yield` and `done`. `(yield x)` adds `x` to the
end of the list being constructed, then recursively calls `fn`. `done` is the
current list (not a procedure!), and should be returned to end the recursion.
For example, this reads characters from `(current-input-port)` into a list
until EOF:
```scheme
(list-gen (lambda (yield done)
(let ((ch (read-char)))
(if (eof-object? ch) done (yield ch)))))
```
- `(fold-by-pairs )` is like `fold`, but reads `list` two
elements at a time. It calls `fn` with three arguments. It raises an error if
`list` does not contain an even number of elements.
- `(fold-right-by-pairs )` is `fold-by-pairs` in reverse.
- `(topological-sort )` sorts a list of dependencies in dependency
order.
`dependencies` is an alist, in which the car of each element is a dependency,
and the cdr of each element is a list of its dependencies, each of which must
be the car of another element. The list must contain no dependency cycles.
### `(schemepunk mapping)`
Polyfilled alias for [SRFI 146 (Mappings)][srfi146]. No additional exports.
Uses comparators from `(schemepunk comparator)`. Does not include `(srfi 146
hash)`.
All Schemes except Gauche use Schemepunk's implementation, which is based on
`(schemepunk btree)`. Gauche's `(srfi 146)` is native and faster than
`(schemepunk btree)`, so it is used when possible.
### `(schemepunk multimap)`
Mappings from one key to a set of values, based on `(schemepunk mapping)` and
`(schemepunk set)`. Uses comparators from `(schemepunk comparator)`.
#### Constructors
- `(multimap )` constructs a new, empty
multimap. A multimap requires comparators for both keys and values.
- `(multimap-copy )` returns a distinct copy of ``.
#### Accessors
- `(multimap? )` is the type predicate for multimaps.
- `(multimap-key-comparator )` and `(multimap-value-comparator )`
return the comparators used by ``.
- `(multimap-ref )` returns the set of values for `` in
``.
- `(multimap->mapping )` returns the underlying mapping of ``. Its
keys are the same as ``'s, and its values are sets.
- `(multimap-contains? )` returns `#t` if `` contains the
value `` in any key's value set, and `#f` otherwise.
- `(multimap-contains-key? )` returns `#t` if `` contains the
key ``, `#f` otherwise.
- `(multimap-keys )` returns a list of the keys in ``.
- `(multimap-values )` returns a list of all values in all value sets in
``.
- `(multimap-value-sets )` returns a list of the value sets in ``.
- `(multimap-key-count )` returns the number of keys in ``.
- `(multimap-value-count )` returns the total number of values in all
value sets in ``.
- `(multimap-empty? )` returns `#t` if `` is empty, `#f` otherwise.
#### Mutators
- `(multimap-adjoin )` and
`(multimap-adjoin! )` return a new multimap with ``
added to the set of values for `` in ``. `multimap-adjoin!` mutates
`` in-place before returning it.
- `(multimap-adjoin-set )` and
`(multimap-adjoin-set! )` return a new multimap with all
values in the set `` added to the set of values for `` in ``.
`multimap-adjoin-set!` mutates `` in-place before returning it.
- `(multimap-delete-key )` and `(multimap-delete-key! )`
return a new multimap with all values for `` in `` removed.
`multimap-delete-key!` mutates `` in-place before returning it.
- `(multimap-delete-value )` and
`(multimap-delete-value! )` return a new multimap with
`` removed from the set of values for `` in ``.
`multimap-delete-value!` mutates `` in-place before returning it.
- `(multimap-clear! )` mutates `` by removing all keys and values.
- `(multimap-union )` and `(multimap-union! )` return a
multimap containing all key/value pairs from both `` and ``. If both
multimaps contain the same key, the returned multimap will contain the union
of both maps' value sets for that key. `multimap-union!` mutates ``
in-place before returning it.
- `(multimap-difference )` returns a multimap that is the result of
removing all key/value pairs in `` from ``.
### `(schemepunk path)`
Procedures for manipulating file path strings. These use the path format of the
current OS; there are separate implementations for Windows and Unix-like OSes.
- `(current-directory)` returns the current working directory.
- `(path-join …)` appends each `` to the root path
`` using the OS path separator.
- `(path-normalize )` converts `` to an equivalent, normalized form
by removing any unnecessary `.` or `..` elements, correcting path separators,
and (on Windows) adding a missing drive name.
- `(path-root? )` returns whether `` is an absolute root path (e.g.,
`/` on Unix or `C:\` on Windows).
- `(path-directory )` returns the path of the parent directory of
``.
- `(path-strip-directory )` returns the final path element of ``.
- `(path-absolute? )` returns whether `` is an absolute path.
- `(path-relative? )` returns whether `` is a relative path.
- `(relative-path->absolute-path )` converts a relative path to an
absolute path, assuming that the path is relative to `(current-directory)`.
### `(schemepunk random)`
Generates random numbers.
- `(random-integer )` generates a random exact integer between `0` and
``, exclusive.
- `(random-real)` generates a random real number between `0` and `1`.
### `(schemepunk set)`
Polyfilled alias for [SRFI 113 (Sets and Bags)][srfi113]. No additional exports.
Uses comparators from `(schemepunk comparator)`.
### `(schemepunk show)`
A full-featured, original implementation of [SRFI 166 (Monadic Text
Formatting)][srfi166]. Supports colorized pretty-printing, Unicode-aware
alignment and truncation, columns, tables, and more.
This implementation is based on SRFI 158 generators. A formatter is a procedure
that takes a mapping of state variables and returns a generator of spans. A span
is a record containing a string, a type (`text`, `whitespace`, or `newline`) and
a color.
Schemepunk's SRFI 166 includes several additional operators and submodules. The
additional exports, grouped by submodule, are as follows:
#### `(schemepunk show base)`
- `(call-with-output-generator )` is like `call-with-output`, but
passes a generator to `` instead of a string.
#### `(schemepunk show color)`
Includes ANSI light colors: `as-light-red`, `as-light-blue`, `as-light-green`,
`as-light-cyan`, `as-light-yellow`, `as-light-magenta`, `as-light-white`,
`as-light-black`, and `as-gray` (alias for `as-light-black`).
#### `(schemepunk show columnar)`
- `(boxed …)` returns a formatter that draws a box around `` using
box drawing characters. `boxed/double` and `boxed/ascii` are variants that
draw a double-line box and an ASCII-only box.
- `(boxed/custom …)` is the box
drawing formatter used by `boxed`.
- `` is a procedure that takes a formatter and returns a procedure.
It is used to apply a color to the box outline. For example, if ``
is `as-red`, the box outline will be red. If the box should not be
colored, `` should be `each`.
- `` and `` are the horizontal and vertical line characters used to
draw the box.
- ``, ``, ``, and `` are the corner characters used to draw
the box. They are the top-left, top-right, bottom-left, and bottom-right
corners, respectively.
- `(collapsed-if-one-line …)` returns a formatter that prints ``
with all adjacent whitespace collapsed to single spaces, as in `wrapped`, if
and only if the entire collapsed string would fit in a single line. Otherwise,
it prints `` unchanged.
#### `(schemepunk show pretty)`
- `pretty-json` and `pretty-json-color` are equivalents to `pretty` and
`pretty-color` for `(schemepunk json)`-compatible JSON data structures. They
print JSON.
- `indent-size` is a state variable for the number of spaces in a single
pretty-printing indentation level. Defaults to `2`.
#### `(schemepunk show debug)`
A simple interface to `(schemepunk show pretty)` for print-statement debugging.
- `(write-debug