{"id":19426410,"url":"https://github.com/ar-nelson/schemepunk","last_synced_at":"2026-03-01T02:32:07.945Z","repository":{"id":51386908,"uuid":"251185680","full_name":"ar-nelson/schemepunk","owner":"ar-nelson","description":"A batteries-included extended standard library for seven R7RS Scheme dialects.","archived":false,"fork":false,"pushed_at":"2021-05-12T14:07:38.000Z","size":1444,"stargazers_count":94,"open_issues_count":4,"forks_count":4,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-15T00:12:54.969Z","etag":null,"topics":["chibi-scheme","chicken","gauche","gerbil","kawa","larceny","r7rs-scheme","sagittarius","scheme","scheme-library"],"latest_commit_sha":null,"homepage":"","language":"Scheme","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ar-nelson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-30T02:53:33.000Z","updated_at":"2025-02-20T00:37:39.000Z","dependencies_parsed_at":"2022-09-02T07:11:57.478Z","dependency_job_id":null,"html_url":"https://github.com/ar-nelson/schemepunk","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ar-nelson/schemepunk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fschemepunk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fschemepunk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fschemepunk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fschemepunk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ar-nelson","download_url":"https://codeload.github.com/ar-nelson/schemepunk/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ar-nelson%2Fschemepunk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29959055,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T01:47:18.291Z","status":"online","status_checked_at":"2026-03-01T02:00:07.437Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chibi-scheme","chicken","gauche","gerbil","kawa","larceny","r7rs-scheme","sagittarius","scheme","scheme-library"],"created_at":"2024-11-10T14:07:32.325Z","updated_at":"2026-03-01T02:32:07.924Z","avatar_url":"https://github.com/ar-nelson.png","language":"Scheme","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Schemepunk\n\nA kitchen-sink utility library for several R7RS Scheme dialects.\n\nThis library is **unfinished and under heavy development**. It's optimized for\nthe needs of a few related projects I'm working on, mostly programming language\ninterpreters and compilers.\n\nTo use this library, drop this repository in a `schemepunk` directory in your\nproject, ideally as a Git submodule. The shell scripts in `scripts` can run unit\ntests or Scheme applications in all of Schemepunk's supported Scheme dialects,\nand they know how to find and include `.sld` library dependencies, even in\nSchemes that don't natively support this.\n\n## Supported Schemes\n\n- [Chibi][chibi]\n- [Chicken][chicken]\\*\n- [Gauche][gauche]\n- [Gerbil][gerbil]\n- [Kawa][kawa]\n- [Larceny][larceny]\n- [Sagittarius][sagittarius]\n\n\\* Chicken requires these eggs: `r7rs`, `utf8`, `box`, `srfi-41`, `srfi-69`,\n`srfi-99`, `srfi-113`, `srfi-128`, `srfi-133`, and `ioctl`. (`ioctl` is only\nrequired on Unix-based OSes.)\n\nSchemepunk can also be built as a Chicken egg. Just run `chicken-install`\n(possibly with `-sudo`) in the repo's root directory.\n\n## Modules\n\n- [`(schemepunk box)` - Boxes](#schemepunk-box)\n- [`(schemepunk btree)` - Persistent B-trees](#schemepunk-btree)\n- [`(schemepunk command)` - Command-line argument parsing](#schemepunk-command)\n- [`(schemepunk comparator)` - Comparators](#schemepunk-comparator)\n- [`(schemepunk datalog)` - Logic programming (WIP)](#schemepunk-datalog)\n- [`(schemepunk flexvector)` - Flexvectors (dynamic arrays)](#schemepunk-flexvector)\n- [`(schemepunk function)` - Functional programming utilities](#schemepunk-function)\n- [`(schemepunk generator)` - Generators and accumulators](#schemepunk-generator)\n- [`(schemepunk hash-table)` - Hash tables](#schemepunk-hash-table)\n- [`(schemepunk hook)` - Hooks](#schemepunk-hook)\n- [`(schemepunk json)` - JSON](#schemepunk-json)\n- [`(schemepunk list)` - List utilities](#schemepunk-list)\n- [`(schemepunk mapping)` - Persistent mappings](#schemepunk-mapping)\n- [`(schemepunk multimap)` - Multimaps](#schemepunk-multimap)\n- [`(schemepunk path)` - File path utilities](#schemepunk-path)\n- [`(schemepunk random)` - Random number generation](#schemepunk-random)\n- [`(schemepunk set)` - Sets and bags](#schemepunk-set)\n- [`(schemepunk show)` - Monadic text formatting](#schemepunk-show)\n    - [`(schemepunk show debug)` - Simple pretty-printing](#schemepunk-show-debug)\n    - [`(schemepunk show report)` - Stylish error reports](#schemepunk-show-report)\n- [`(schemepunk sort)` - Sorting](#schemepunk-sort)\n- [`(schemepunk stream)` - Streams](#schemepunk-stream)\n- [`(schemepunk string)` - String utilities](#schemepunk-string)\n- [`(schemepunk syntax)` - Utility macros](#schemepunk-syntax)\n- [`(schemepunk term-colors)` - ANSI terminal colors](#schemepunk-term-colors)\n- [`(schemepunk test)` - Unit test framework](#schemepunk-test)\n- [`(schemepunk vector)` - Vector library](#schemepunk-vector)\n\n### `(schemepunk box)`\n\nPolyfilled alias for [SRFI 111 (Boxes)][srfi111]. Exports one additional\nprocedure:\n\n- `(update-box! \u003cbox\u003e \u003cproc\u003e)` is equivalent to\n  `(set-box! \u003cbox\u003e (\u003cproc\u003e (unbox \u003cbox\u003e)))`.\n\n### `(schemepunk btree)`\n\nAn original implementation of persistent B-trees, used to implement `(schemepunk\nmapping)` on all Schemes except Gauche¹.\n\nSchemepunk's B-tree mappings are frequently 2-3 times faster than the\nred-black-tree reference implementation of SRFI 146, and significantly faster\nwhen constructing large mappings. This library includes linear-update\n`!`-suffixed mutation procedures, for yet another performance boost.\n\nYou usually want to use this module through `(schemepunk mapping)`, but, if you\nwant to use the B-tree data structure directly, this module provides these\nlow-level procedures:\n\n- `(btree \u003ccomparator\u003e \u003cmax-size\u003e)`\n- `(btree? \u003cbtree\u003e)`\n- `(btree-key-comparator \u003cbtree\u003e)`\n- `(btree-empty? \u003cbtree\u003e)`\n- `(btree-copy \u003cbtree\u003e)`\n- `(btree-ref \u003ckey\u003e \u003cvalue\u003e \u003cfailure-proc\u003e)` *(`failure-proc` is optional)*\n- `(btree-set \u003cbtree\u003e \u003ckey\u003e \u003cvalue\u003e)`\n- `(btree-set! \u003cbtree\u003e \u003ckey\u003e \u003cvalue\u003e)`\n- `(btree-delete \u003cbtree\u003e \u003ckey\u003e)`\n- `(btree-delete! \u003cbtree\u003e \u003ckey\u003e)`\n- `(btree-pop \u003cbtree\u003e \u003ckey\u003e)` *(returns two values: `(key . value)` and modified btree)*\n- `(btree-pop! \u003cbtree\u003e \u003ckey\u003e)` *(returns one value: `(key . value)`)*\n- `(btree-fold \u003cfn\u003e \u003cseed\u003e \u003cbtree\u003e)`\n- `(btree-fold-right \u003cfn\u003e \u003cseed\u003e \u003cbtree\u003e)`\n- `(alist-\u003ebtree \u003calist\u003e \u003ccomparator\u003e \u003cmax-size\u003e)`\n- `(btree-\u003ealist \u003cbtree\u003e)`\n- `(btree-subset? \u003cvalue-comparator\u003e \u003cbtree1\u003e \u003cbtree2\u003e)`\n- `(btree=? \u003cvalue-comparator\u003e \u003cbtree1\u003e \u003cbtree2\u003e)`\n- `(btree\u003c? \u003cvalue-comparator\u003e \u003cbtree1\u003e \u003cbtree2\u003e)`\n- `(btree-hash \u003cvalue-comparator\u003e \u003cbtree\u003e)`\n- `(make-btree-comparator \u003cvalue-comparator\u003e)`\n- `btree-comparator`\n\n¹ _B-trees are faster than most Schemes' SRFI 146, but Gauche's `\u003ctree-map\u003e` is\nusually even faster._\n\n### `(schemepunk command)`\n\nA command-line argument parser, loosely based on Chibi Scheme's\n[`(chibi app)`][chibi-app]. The parser procedures take _app specifications_,\nwhich are nested alists. For example, the zoo demo from the `(chibi app)`\ndocumentation can be written like this for `(schemepunk command)`:\n\n```scheme\n'((name \"Zookeeper Application\")\n  (doc \"Example application from (chibi app) documentation, adapted for \\\n        (schemepunk command).\")\n  (copyright \"Copyright (c) 2020\")\n  (options\n    (animals\n      (type (list symbol))\n      (doc \"list of animals to act on (default all)\"))\n    (lions\n      (short #\\l)\n      (doc \"also apply the action to lions\")))\n  (commands\n    (feed\n      (short-doc \"feed the animals\")\n      (doc-args \u003canimals\u003e ...))\n    (wash\n      (short-doc \"wash the animals\")\n      (doc-args \u003canimals\u003e ...)\n      (options (soap)))\n    (help\n      (short-doc \"print help\")))\n  (require-command #t))\n```\n\n`(schemepunk command)` supports both `-` short options and `--` long options.\nShort options can be grouped: `-xyz` = `-x -y -z`. Values after option names can\nfollow either a space or `=`. Git-style commands, with their own documentation\nand option lists, are also supported.\n\n#### Procedures\n\n- `(run-application \u003cspec\u003e \u003ccommand-line\u003e \u003cproc\u003e)` parses the list of\n  command-line arguments `\u003ccommand-line\u003e` using the specification `\u003cspec\u003e`.\n  The first element of `\u003ccommand-line\u003e` should be the executable name.\n\n    If parsing is successful, `\u003cproc\u003e` is tail-called with five arguments:\n\n    - `options`, an alist of the `-` or `--` options passed to the app\n    - `args`, a list of all non-option and non-command arguments passed to the\n      app, as strings\n    - `command`, the command name passed to the app, or `#f` if there is no\n      command\n    - `command-options`, an alist of all options that occurred after the command\n      name\n    - `command-args`, a list of all non-option arguments that occurred after the\n      command name, as strings\n\n    If parsing fails, a usage message is printed to `(current-error-port)`, and\n    then Scheme is terminated with `(exit 1)`.\n\n- `(parse-app \u003cspec\u003e \u003ccommand-line\u003e)` parses the list of command-line arguments\n  `\u003ccommand-line\u003e` using the specification `\u003cspec\u003e`, and returns five values,\n  corresponding to the five arguments passed to `run-application`'s `\u003cproc\u003e`. If\n  parsing fails, it will raise an error object for which `command-error?` is\n  `#t`.\n\n- `(app-usage \u003cspec\u003e \u003ccommand-line\u003e)` is a `(schemepunk show)` formatter that\n  prints a usage message for the app specification `\u003cspec\u003e`. The executable name\n  is taken from the first element of the list `\u003ccommand-line\u003e`.\n\n- `(command-usage \u003cspec\u003e \u003ccommand\u003e \u003ccommand-line\u003e)` is a `(schemepunk show)`\n  formatter that prints a usage message for the command `\u003ccommand\u003e` in the app\n  specification `\u003cspec\u003e`. The executable name is taken from the first element of\n  the list `\u003ccommand-line\u003e`.\n\n- `app-help` and `command-help` are like `app-usage` and `command-usage`, but\n  also include `name`, `doc`, and `copyright` if they are present in the\n  specification.\n\n    ![Screenshot of app-help output](.readme-images/app-help.png)\n\n- `(command-error? \u003cdatum\u003e)` is a type predicate for the error objects raised by\n  `parse-app`.\n\n#### App specification\n\nAll alist keys are optional; the empty specification `'()` is valid but has no\ndocumentation and accepts no options.\n\n- `name` - name of the application, displayed at the start of the app's help\n  text\n- `doc` - documentation paragraph, displayed at the start of the app's help text\n- `doc-args` - symbols or strings that describe the app's arguments in usage\n  text; e.g., `\u003cinput-file\u003e \"[\u003coutput-file\u003e]\"`\n- `copyright` - copyright message displayed at bottom of help text\n- `options` - alist of options for the app; each option's key is also its\n  default long option name\n- `commands` - alist of commands for the app; each command's key is also its\n  name\n- `require-command` - if `#t`, app exits with an error if no command is provided\n- `default-help-option` - if `#t`, an option is added with long name `--help`\n  and short name `-h` that, if present, causes `run-application` to print the\n  app's help text and exit\n- `default-help-command` - if `#t`, a command named `help` is added that, if\n  selected and passed a command name as its only argument, causes\n  `run-application` to display that command's help text and exit\n\n##### Option\n\n- `type` - data type of the option's value, defaults to `boolean`; options are\n  `boolean`, `symbol`, `char`, `string`, `integer`, `real`, `sexp`, and\n  `(list \u003ctype\u003e)`\n- `long` - long option aliases for this option (symbols or strings)\n- `short` - short option aliases for this option (chars)\n- `doc` - description of this option, displayed in usage text\n- `doc-value` - name of the option's value, displayed in usage text, defaults to\n  value of `type`\n\n##### Command\n\n- `short-doc` - documentation shown in the app's usage text\n- `doc` - longer documentation shown in the command's usage text\n- `doc-args` - symbols or strings that describe the command's arguments in usage\n  text; e.g., `\u003cinput-file\u003e \"[\u003coutput-file\u003e]\"`\n- `options` - alist of options for the command; each option's key is also its\n  default long option name\n\n### `(schemepunk comparator)`\n\nPolyfilled alias for [SRFI 128 (Comparators)][srfi128] with [SRFI 162\n(Comparators sublibrary)][srfi162] extensions. These comparators are used by all\nof Schemepunk's ordered data structures: sets, bags, hash tables, mappings, and\nmultimaps.\n\nIn addition to SRFIs 128 and 162, this module exports several extra procedures,\nmacros, and comparators:\n\n- `symbol-comparator` is a default comparator for symbols.\n\n- `number-comparator` is a default comparator for numbers that is more general\n  than SRFI 162's `real-comparator`.\n\n- `fixnum-comparator` is a default comparator for fixnums (small integers).\n\n- `(make-sum-comparator \u003ccomparators\u003e…)` creates a comparator for the _sum type_\n  of the types represented by each comparator in `\u003ccomparators\u003e`. For example,\n  `(make-sum-comparator boolean-comparator number-comparator string-comparator)`\n  returns a comparator for values that may be either booleans, numbers, or\n  strings.\n\n- `(hash-lambda (\u003cparam\u003e) \u003cbody\u003e…)` is equivalent to\n  `(lambda (\u003cparam\u003e) \u003cbody\u003e…)`, except that it takes and ignores an optional\n  second argument. This macro should be used to define hash functions. Some\n  Schemes' SRFI 128 or SRFI 69 implementations expect hash functions to take one\n  parameter, others expect two, and this is the only way to write hash functions\n  that are compatible with all of them.\n\n- `(identity-hash \u003cx\u003e)` is a reference-identity-based hash function, used by\n  `eq-comparator`. It should always return different hashes for values that are\n  not `eq?`. This is a primitive operator that cannot be implemented portably,\n  so it is always an alias for the host Scheme's identity hash function.\n\n- `(identity\u003c? \u003cx\u003e \u003cy\u003e)` is an identity-based ordering function, used by\n  `eq-comparator`. It compares the `identity-hash` of `\u003cx\u003e` and `\u003cy\u003e`.\n\n### `(schemepunk datalog)`\n\nWIP simple Datalog logic programming library. Still unfinished, not much to see\nhere. So far, it supports semi-naive evaluation and stratified negation.\n\n### `(schemepunk flexvector)`\n\nPolyfilled alias for [SRFI 214 (Flexvectors)][srfi214]. No additional exports.\n\n### `(schemepunk function)`\n\nCombinators commonly used in functional languages like Haskell or ML.\n\n- `(identity \u003cx\u003e)` returns `\u003cx\u003e`.\n\n- `(const \u003cx\u003e)` returns a procedure that takes one argument, ignores it, and\n  returns `\u003cx\u003e`.\n\n- `(flip \u003cf\u003e)` takes a procedure of two arguments `\u003cf\u003e`, and returns a new\n  procedure `(g x y)` that calls `(\u003cf\u003e y x)`.\n\n- `(compose \u003cfs\u003e…)` composes procedures right-to-left: `(compose f g)` returns\n  a procedure `(composed x)` that calls `(f (g x))`.\n\n- `(bind \u003cfs\u003e…)` composes procedures left-to-right: `(bind f g)` returns a\n  procedure `(composed x)` that calls `(g (f x))`.\n\n- `(complement \u003cpred?\u003e)` takes a predicate `\u003cpred?\u003e` and returns its complement\n  (a predicate that always returns the opposite boolean value).\n\n### `(schemepunk generator)`\n\nPolyfilled alias for [SRFI 158 (Generators and Accumulators)][srfi158]. Exports\none additional procedure:\n\n- `(gfork \u003cgen\u003e)` returns two values, both of which are generators that produce\n  the same sequence of values as `\u003cgen\u003e`.\n\n### `(schemepunk hash-table)`\n\nPolyfilled alias for [SRFI 125 (Intermediate Hash Tables)][srfi125]. No\nadditional exports. Uses comparators from `(schemepunk comparator)`.\n\n### `(schemepunk hook)`\n\nPolyfilled alias for [SRFI 173 (Hooks)][srfi173]. No additional exports.\n\n### `(schemepunk json)`\n\nMinimal JSON parser. Can encode and decode JSON to/from a simple Scheme\nrepresentation:\n\n| JSON value         | Scheme representation   |\n| ------------------ | ----------------------- |\n| `null`             | The symbol `null`       |\n| `true`             | The symbol `true`       |\n| `false`            | The symbol `false`      |\n| `3.14`             | `3.14`                  |\n| `\"foo\"`            | `\"foo\"`                 |\n| `[1, 2, 3]`        | `#(1 2 3)`              |\n| `{}`               | `()`                    |\n| `{\"a\": 1, \"b\": 2}` | `((\"a\" . 1) (\"b\" . 2))` |\n\n- `(read-json \u003cport\u003e)` reads one JSON value from a port and returns it. `\u003cport\u003e`\n  is optional.\n\n- `(write-json \u003cjson\u003e \u003cport\u003e)` writes one JSON value to a port. Anything that\n  is not a valid Scheme representation of JSON will be written as `\u003cNOT JSON\u003e`.\n  `\u003cport\u003e` is optional.\n\n- `string-\u003ejson` and `json-\u003estring` convert JSON strings to/from their Scheme\n  representations.\n\nA simple event-based parser is also available, for performance:\n\n- `(make-json-context)` creates a new context object.\n\n- `(read-json-event \u003ccontext\u003e \u003cport\u003e)` reads one JSON event from a port. It\n  returns two values: `(event payload)`, where `event` is the event type and\n  `payload` is an optional value. It takes a context object, which keeps track\n  of nesting and object keys. `\u003cport\u003e` is optional.\n\n| Event          | Payload                |\n| -------------- | ---------------------- |\n| `null`         | `#f`                   |\n| `boolean`      | Value (`#t` or `#f`)   |\n| `number`       | Value (number)         |\n| `string`       | Value (string)         |\n| `array-start`  | `#f`                   |\n| `array-end`    | `#f`                   |\n| `object-start` | `#f`                   |\n| `key`          | Key name (string)      |\n| `object-end`   | `#f`                   |\n| `error`        | Error message (string) |\n\n### `(schemepunk list)`\n\nAlias for [SRFI 1 (List Library)][srfi1]. Because all supported Schemes include\nthis SRFI, there is no polyfill.\n\nIn addition to SRFI 1, this module exports several extra procedures:\n\n- `(snoc \u003clist\u003e \u003celem\u003e)` is a reverse `cons`; it constructs a list by appending\n  `elem` to the end of `list`.\n\n- `(map-with-index \u003cfn\u003e \u003clist\u003e)` is like `map`, but it expects `fn` to take two\n  arguments. The second argument is the index of the list item.\n\n- `(intercalate \u003cdelimiter\u003e \u003clist\u003e)` constructs a new list by inserting\n  `\u003cdelimiter\u003e` between each pair of elements in `\u003clist\u003e`.\n\n- `(list-gen \u003cfn\u003e)` is a generator-style unfold. `fn` is a lambda that takes\n  two arguments, usually named `yield` and `done`. `(yield x)` adds `x` to the\n  end of the list being constructed, then recursively calls `fn`. `done` is the\n  current list (not a procedure!), and should be returned to end the recursion.\n\n    For example, this reads characters from `(current-input-port)` into a list\n    until EOF:\n\n    ```scheme\n    (list-gen (lambda (yield done)\n                (let ((ch (read-char)))\n                  (if (eof-object? ch) done (yield ch)))))\n    ```\n\n- `(fold-by-pairs \u003cfn\u003e \u003cseed\u003e \u003clist\u003e)` is like `fold`, but reads `list` two\n  elements at a time. It calls `fn` with three arguments. It raises an error if\n  `list` does not contain an even number of elements.\n\n- `(fold-right-by-pairs \u003cfn\u003e \u003cseed\u003e \u003clist\u003e)` is `fold-by-pairs` in reverse.\n\n- `(topological-sort \u003cdependencies\u003e)` sorts a list of dependencies in dependency\n  order.\n\n    `dependencies` is an alist, in which the car of each element is a dependency,\n    and the cdr of each element is a list of its dependencies, each of which must\n    be the car of another element. The list must contain no dependency cycles.\n\n### `(schemepunk mapping)`\n\nPolyfilled alias for [SRFI 146 (Mappings)][srfi146]. No additional exports.\nUses comparators from `(schemepunk comparator)`. Does not include `(srfi 146\nhash)`.\n\nAll Schemes except Gauche use Schemepunk's implementation, which is based on\n`(schemepunk btree)`. Gauche's `(srfi 146)` is native and faster than\n`(schemepunk btree)`, so it is used when possible.\n\n### `(schemepunk multimap)`\n\nMappings from one key to a set of values, based on `(schemepunk mapping)` and\n`(schemepunk set)`. Uses comparators from `(schemepunk comparator)`.\n\n#### Constructors\n\n- `(multimap \u003ckey-comparator\u003e \u003cvalue-comparator\u003e)` constructs a new, empty\n  multimap. A multimap requires comparators for both keys and values.\n- `(multimap-copy \u003cmmap\u003e)` returns a distinct copy of `\u003cmmap\u003e`.\n\n#### Accessors\n\n- `(multimap? \u003cdatum\u003e)` is the type predicate for multimaps.\n- `(multimap-key-comparator \u003cmmap\u003e)`  and `(multimap-value-comparator \u003cmmap\u003e)`\n  return the comparators used by `\u003cmmap\u003e`.\n- `(multimap-ref \u003cmmap\u003e \u003ckey\u003e)` returns the set of values for `\u003ckey\u003e` in\n  `\u003cmmap\u003e`.\n- `(multimap-\u003emapping \u003cmmap\u003e)` returns the underlying mapping of `\u003cmmap\u003e`. Its\n  keys are the same as `\u003cmmap\u003e`'s, and its values are sets.\n- `(multimap-contains? \u003cmmap\u003e \u003cvalue\u003e)` returns `#t` if `\u003cmmap\u003e` contains the\n  value `\u003cvalue\u003e` in any key's value set, and `#f` otherwise.\n- `(multimap-contains-key? \u003cmmap\u003e \u003ckey\u003e)` returns `#t` if `\u003cmmap\u003e` contains the\n  key `\u003ckey\u003e`, `#f` otherwise.\n- `(multimap-keys \u003cmmap\u003e)` returns a list of the keys in `\u003cmmap\u003e`.\n- `(multimap-values \u003cmmap\u003e)` returns a list of all values in all value sets in\n  `\u003cmmap\u003e`.\n- `(multimap-value-sets \u003cmmap\u003e)` returns a list of the value sets in `\u003cmmap\u003e`.\n- `(multimap-key-count \u003cmmap\u003e)` returns the number of keys in `\u003cmmap\u003e`.\n- `(multimap-value-count \u003cmmap\u003e)` returns the total number of values in all\n  value sets in `\u003cmmap\u003e`.\n- `(multimap-empty? \u003cmmap\u003e)` returns `#t` if `\u003cmmap\u003e` is empty, `#f` otherwise.\n\n#### Mutators\n\n- `(multimap-adjoin \u003cmmap\u003e \u003ckey\u003e \u003cvalue\u003e)` and\n  `(multimap-adjoin! \u003cmmap\u003e \u003ckey\u003e \u003cvalue\u003e)` return a new multimap with `\u003cvalue\u003e`\n  added to the set of values for `\u003ckey\u003e` in `\u003cmmap\u003e`. `multimap-adjoin!` mutates\n  `\u003cmmap\u003e` in-place before returning it.\n- `(multimap-adjoin-set \u003cmmap\u003e \u003ckey\u003e \u003cvals\u003e)` and\n  `(multimap-adjoin-set! \u003cmmap\u003e \u003ckey\u003e \u003cvals\u003e)` return a new multimap with all\n  values in the set `\u003cvals\u003e` added to the set of values for `\u003ckey\u003e` in `\u003cmmap\u003e`.\n  `multimap-adjoin-set!` mutates `\u003cmmap\u003e` in-place before returning it.\n- `(multimap-delete-key \u003cmmap\u003e \u003ckey\u003e)` and `(multimap-delete-key! \u003cmmap\u003e \u003ckey\u003e)`\n  return a new multimap with all values for `\u003ckey\u003e` in `\u003cmmap\u003e` removed.\n  `multimap-delete-key!` mutates `\u003cmmap\u003e` in-place before returning it.\n- `(multimap-delete-value \u003cmmap\u003e \u003ckey\u003e \u003cvalue\u003e)` and\n  `(multimap-delete-value! \u003cmmap\u003e \u003ckey\u003e \u003cvalue\u003e)` return a new multimap with\n   `\u003cvalue\u003e` removed from the set of values for `\u003ckey\u003e` in `\u003cmmap\u003e`.\n  `multimap-delete-value!` mutates `\u003cmmap\u003e` in-place before returning it.\n- `(multimap-clear! \u003cmmap\u003e)` mutates `\u003cmmap\u003e` by removing all keys and values.\n- `(multimap-union \u003clhs\u003e \u003crhs\u003e)` and `(multimap-union! \u003clhs\u003e \u003crhs\u003e)` return a\n  multimap containing all key/value pairs from both `\u003clhs\u003e` and `\u003crhs\u003e`. If both\n  multimaps contain the same key, the returned multimap will contain the union\n  of both maps' value sets for that key. `multimap-union!` mutates `\u003clhs\u003e`\n  in-place before returning it.\n- `(multimap-difference \u003clhs\u003e \u003crhs\u003e)` returns a multimap that is the result of\n  removing all key/value pairs in `\u003crhs\u003e` from `\u003clhs\u003e`.\n\n### `(schemepunk path)`\n\nProcedures for manipulating file path strings. These use the path format of the\ncurrent OS; there are separate implementations for Windows and Unix-like OSes.\n\n- `(current-directory)` returns the current working directory.\n- `(path-join \u003cpath\u003e \u003csuffix\u003e…)` appends each `\u003csuffix\u003e` to the root path\n  `\u003cpath\u003e` using the OS path separator.\n- `(path-normalize \u003cpath\u003e)` converts `\u003cpath\u003e` to an equivalent, normalized form\n  by removing any unnecessary `.` or `..` elements, correcting path separators,\n  and (on Windows) adding a missing drive name.\n- `(path-root? \u003cpath\u003e)` returns whether `\u003cpath\u003e` is an absolute root path (e.g.,\n  `/` on Unix or `C:\\` on Windows).\n- `(path-directory \u003cpath\u003e)` returns the path of the parent directory of\n  `\u003cpath\u003e`.\n- `(path-strip-directory \u003cpath\u003e)` returns the final path element of `\u003cpath\u003e`.\n- `(path-absolute? \u003cpath\u003e)` returns whether `\u003cpath\u003e` is an absolute path.\n- `(path-relative? \u003cpath\u003e)` returns whether `\u003cpath\u003e` is a relative path.\n- `(relative-path-\u003eabsolute-path \u003cpath\u003e)` converts a relative path to an\n  absolute path, assuming that the path is relative to `(current-directory)`.\n\n### `(schemepunk random)`\n\nGenerates random numbers.\n\n- `(random-integer \u003cmax\u003e)` generates a random exact integer between `0` and\n  `\u003cmax\u003e`, exclusive.\n- `(random-real)` generates a random real number between `0` and `1`.\n\n### `(schemepunk set)`\n\nPolyfilled alias for [SRFI 113 (Sets and Bags)][srfi113]. No additional exports.\nUses comparators from `(schemepunk comparator)`.\n\n### `(schemepunk show)`\n\nA full-featured, original implementation of [SRFI 166 (Monadic Text\nFormatting)][srfi166]. Supports colorized pretty-printing, Unicode-aware\nalignment and truncation, columns, tables, and more.\n\nThis implementation is based on SRFI 158 generators. A formatter is a procedure\nthat takes a mapping of state variables and returns a generator of spans. A span\nis a record containing a string, a type (`text`, `whitespace`, or `newline`) and\na color.\n\nSchemepunk's SRFI 166 includes several additional operators and submodules. The\nadditional exports, grouped by submodule, are as follows:\n\n#### `(schemepunk show base)`\n\n- `(call-with-output-generator \u003cfmt\u003e \u003cproc\u003e)` is like `call-with-output`, but\n  passes a generator to `\u003cproc\u003e` instead of a string.\n\n#### `(schemepunk show color)`\n\nIncludes ANSI light colors: `as-light-red`, `as-light-blue`, `as-light-green`,\n`as-light-cyan`, `as-light-yellow`, `as-light-magenta`, `as-light-white`,\n`as-light-black`, and `as-gray` (alias for `as-light-black`).\n\n#### `(schemepunk show columnar)`\n\n- `(boxed \u003cfmts\u003e…)` returns a formatter that draws a box around `\u003cfmts\u003e` using\n  box drawing characters. `boxed/double` and `boxed/ascii` are variants that\n  draw a double-line box and an ASCII-only box.\n\n- `(boxed/custom \u003ccolor\u003e \u003ch\u003e \u003cv\u003e \u003cnw\u003e \u003cne\u003e \u003csw\u003e \u003cse\u003e \u003cfmts\u003e…)` is the box\n  drawing formatter used by `boxed`.\n\n    - `\u003ccolor\u003e` is a procedure that takes a formatter and returns a procedure.\n      It is used to apply a color to the box outline. For example, if `\u003ccolor\u003e`\n      is `as-red`, the box outline will be red. If the box should not be\n      colored, `\u003ccolor\u003e` should be `each`.\n    - `\u003ch\u003e` and `\u003cv\u003e` are the horizontal and vertical line characters used to\n      draw the box.\n    - `\u003cnw\u003e`, `\u003cne\u003e`, `\u003csw\u003e`, and `\u003cse\u003e` are the corner characters used to draw\n      the box. They are the top-left, top-right, bottom-left, and bottom-right\n      corners, respectively.\n\n- `(collapsed-if-one-line \u003cfmts\u003e…)` returns a formatter that prints `\u003cfmts\u003e`\n  with all adjacent whitespace collapsed to single spaces, as in `wrapped`, if\n  and only if the entire collapsed string would fit in a single line. Otherwise,\n  it prints `\u003cfmts\u003e` unchanged.\n\n#### `(schemepunk show pretty)`\n\n- `pretty-json` and `pretty-json-color` are equivalents to `pretty` and\n  `pretty-color` for `(schemepunk json)`-compatible JSON data structures. They\n  print JSON.\n\n- `indent-size` is a state variable for the number of spaces in a single\n  pretty-printing indentation level. Defaults to `2`.\n\n#### `(schemepunk show debug)`\n\nA simple interface to `(schemepunk show pretty)` for print-statement debugging.\n\n- `(write-debug \u003cdatum\u003e)` prints `\u003cdatum\u003e` to `(current-output-port)` using\n  `pretty-color`, then prints a newline.\n\n    ![Screenshot of write-debug output](.readme-images/write-debug.png)\n\n- `(write-debug-json \u003cjson\u003e)` prints `\u003cjson\u003e` to `(current-output-port)` using\n  `pretty-json-color`, then prints a newline.\n\n#### `(schemepunk show report)`\n\nFormatters for detailed error reports, similar to the error reports in languages\nlike Rust and Elm. `(schemepunk test)` uses this to print test errors.\n\n- `(reported \u003ctitle\u003e \u003cfmts\u003e…)` is a formatter that prints a header line with\n  `\u003ctitle\u003e` embedded into it, followed by `\u003cfmts\u003e`.\n\n    ![Screenshot of reported output](.readme-images/reported.png)\n\n- `report-line` is a formatter that prints a single horizontal line the width of\n  `width`, colored to match `reported`'s headers. Use this at the end of a\n  sequence of reports.\n\n- `(wrapped/blocks \u003cfmts\u003e…)` is a variant of `wrapped` that handles newlines in\n  subformatters. If a non-string formatter in `\u003cfmts\u003e` contains a newline or is\n  longer than 2/3 of `width`, that formatter is broken out into its own\n  paragraph, without wrapping, with two newlines above and below it.\n\n    Can be used in reports to include pretty-printed Scheme data in wrapped text\n    blocks; the Scheme data will appear as either inline code or standalone code\n    blocks, depending on its size.\n\n- `(code-snapshot \u003cfilename\u003e \u003csource\u003e \u003cline-numbers?\u003e \u003cannotations\u003e…)` prints a\n  snippet of the string or formatter `\u003csource\u003e`, adjusted to fit within the\n  terminal, with annotations pointing to specific lines and columns. It can\n  print line-and-column error traces with multiple messages, in the style of\n  Rust:\n\n    ![Screenshot of code-snapshot output](.readme-images/code-snapshot.png)\n\n    `\u003cannotations\u003e` is composed of one or more five-element lists:\n    `(\u003cline\u003e \u003cstart-col\u003e \u003cend-col\u003e \u003ccolor\u003e \u003cmessage\u003e)`. `\u003cline\u003e` is the 0-based\n    line of the annotation, and `\u003cstart-col\u003e`-`\u003cend-col\u003e` are the 0-based column\n    range of the annotation. `\u003ccolor\u003e` is a color formatter procedure, like\n    `as-red`, and should be `each` if the annotation is not colored. `\u003cmessage\u003e`\n    is the annotation message itself, and can be a string or `#f`. If\n    `\u003cmessage\u003e` is `#f`, the annotation will be an underline with no message.\n\n#### `(schemepunk show span)`\n\nDefines the span data structure. Formatters return generators of spans. Spans\ninclude color data that is not part of their text content. They can also be\nmarked as whitespace or newlines, which speeds up operations like `wrapped` and\nis used by the pretty-printing indentation algorithm.\n\n- `(span? \u003cdatum\u003e)` is a type predicate for spans.\n- `(span-type \u003cspan\u003e)` returns the type of `\u003cspan\u003e` (`text`, `whitespace`, or\n  `newline`).\n- `(span-text \u003cspan\u003e)` returns the text content of `\u003cspan\u003e` as a string.\n- `(span-color \u003cspan\u003e)` returns the color of `\u003cspan\u003e` (a\n  `(schemepunk term-color)` ANSI color, or `#f`).\n- `(text-span \u003cstr\u003e \u003ccolor\u003e)` constructs a `text` span from a string. `\u003ccolor\u003e`\n  is optional and defaults to `#f`.\n- `(whitespace-span \u003cstr\u003e)` constructs a `whitespace` span from a string.\n  `\u003cstr\u003e` is optional and defaults to `\" \"`.\n- `(newline-span \u003cstr\u003e)` constructs a `newline` span from a string. `\u003cstr\u003e` is\n  optional and defaults to the string printed by `(newline)`.\n- `(span-map-text \u003cproc\u003e \u003cspan\u003e)` returns a copy of `\u003cspan\u003e` whose text content\n  is the result of applying `\u003cproc\u003e` to `(span-text \u003cspan\u003e)`.\n- `(span-with-color \u003cspan\u003e \u003ccolor\u003e)` returns a copy of `\u003cspan\u003e` with the color\n  `\u003ccolor\u003e`.\n- `(char-generator-\u003espan-generator \u003cgen\u003e \u003cword-separator?\u003e \u003cread-ansi-escapes?\u003e)`\n  takes a generator of chars (`\u003cgen\u003e`) and returns a generator of spans. Any\n  `#\\newline` character becomes a `newline` span, any group of characters for\n  which `word-separator?` returns true becomes a `whitespace` span, and all\n  groups of characters between these become `text` spans.\n\n    - `\u003cword-separator?\u003e` is an optional predicate and defaults to\n      `char-whitespace?`.\n    - `\u003cread-ansi-escapes?\u003e` is an optional boolean and defaults to `#f`. If it is\n      `#t`, this procedure will check for ANSI escapes in the character stream\n      and include them in the generated spans as color values.\n- `(write-span \u003cspan\u003e \u003cport\u003e)` writes the text of `\u003cspan\u003e` to `\u003cport\u003e`, wrapped\n  in ANSI escapes if the span has a color. `\u003cport\u003e` is optional and defaults to\n  `(current-output-port)`.\n\n### `(schemepunk sort)`\n\nPolyfilled alias for [SRFI 132 (Sort Libraries)][srfi132]. No additional\nexports.\n\n### `(schemepunk stream)`\n\nAlias for [SRFI 41 (Streams)][srfi41]. Because all supported Schemes include\nthis SRFI, there is no polyfill. No additional exports.\n\n### `(schemepunk string)`\n\nPolyfilled alias for [SRFI 152 (String Library (Reduced))][srfi152]. The\npolyfill is not a full SRFI 152 implementation; it imports either\n[SRFI 13][srfi13] or [SRFI 130][srfi130], then fills in the missing SRFI 152\nprocedures. No additional exports.\n\n**Compatibility note:** The `string\u003c?` and `string-ci\u003c?` family of comparison\nprocedures in `(schemepunk string)` do not strictly match the specification.\nThey are simple reexports of the matching procedures from `(scheme base)` and\n`(scheme char)`, and as such they only accept exactly two arguments. This was\ndone because, in some Schemes, it is an error to import two different\ndefinitions with the same name. If they were defined according to the\nspecification, it would be impossible to import `(scheme base)` and `(schemepunk\nstring)` in the same module without excluding these imports.\n\n### `(schemepunk syntax)`\n\nA collection of utility macros. Includes [SRFI 2 (`and-let*`)][srfi2], [SRFI 8\n(`receive`)][srfi8], [SRFI 26 (`cut` and `cute`)][srfi26], [SRFI 28\n(`format`)][srfi28], [SRFI 145 (`assume`)][srfi145], [SRFI 156 (`is`)][srfi156],\nand [SRFI 197 (`chain`)][srfi197].\n\n- `λ` is shorthand for `lambda`. Parentheses may be omitted for a single\n  argument name: `(λ x (+ x 1))` = `(lambda (x) (+ x 1))`. Arguments may contain\n  destructuring assigments (see `match`).\n\n    **Caution: `λ` is not substitutable for `lambda` in all situations.**\n    `(lambda x …)` takes any numer of arguments, but `(λ x …)` takes one.\n\n- `chain` is similar to [Clojure threading macros][clojure-threading], but with\n  `_` as an explicit argument marker. This macro is fully defined in\n  [SRFI 197][srfi197].\n\n    ```scheme\n    (chain x (foo y _) (bar _ z)) ; =\u003e (bar (foo y x) z)\n    ```\n\n- `chain-lambda` defines a lambda using a `chain` pipeline. `(chain-lambda (foo\n  y _) (bar _ z))` = `(lambda (x) (chain x (foo y _) (bar _ z)))`. `λ=\u003e` is\n  shorthand for `chain-lambda`.\n\n- `(let1 \u003cname\u003e \u003cvalue\u003e \u003cbody\u003e…)` is shorthand for `let` with a single\n  variable.\n\n- `(if-let \u003cname\u003e \u003cvalue\u003e \u003cthen\u003e \u003celse\u003e)` is a version of `if` that assigns the\n  predicate `\u003cvalue\u003e` to a variable `\u003cname\u003e`.\n\n- `(let/cc \u003cname\u003e \u003cbody\u003e…)` is shorthand for\n  `(call/cc (lambda (\u003cname\u003e) \u003cbody\u003e…))`.\n\n- `(match \u003cvalue\u003e (\u003cpattern\u003e \u003cexpr\u003e…)…)` is a hygenic pattern-matching macro,\n  based on Alex Shinn's `match-simple.scm`, which is itself based on Andrew\n  Wright's `match`. It is a portable subset of the functionality of the `match`\n  packages in Chibi and Gauche.\n\n    It supports only the basic features of [`(chibi match)`][chibi-match]. It is\n    missing the `=\u003e`, `@`, `$`, `=`, `..1`, `get!`, and `set!` operators, and it\n    does not support the symbol `...` as an ellipsis operator (use `___` or `…`\n    instead).\n\n- `(match-let ((\u003cpattern\u003e \u003cvalue\u003e)…) \u003cbody\u003e…)` uses the\n  pattern-matching syntax from `match` as destructuring assignment.\n\n    Related functions `match-let*`, `match-let1`, and `match-letrec` are also\n    available.\n\n- `(match-lambda (\u003cpattern\u003e \u003cexpr\u003e…)…)` defines a lambda of one argument\n  that matches its argument against one or more patterns. `matchλ` is an alias.\n  `match-lamda*` matches its entire argument list against the patterns.\n\n- `(match-guard ((\u003cpattern\u003e \u003chandler\u003e…)…) \u003cexpressions\u003e…)` is a `guard`\n  form with pattern-matching. It matches the raised error against each\n  `pattern`.\n\n- `(define+ (\u003cname\u003e \u003cparams\u003e… :optional \u003coptional-params\u003e… :rest \u003crest-param\u003e) \u003cbody\u003e…)`\n  is a form of `define` that supports destructuring assignment (as in `λ`) and\n  optional parameters. It uses Gauche's syntax for optional and rest parameters.\n  The `:optional` and `:rest` sections are optional.  Each `\u003coptional-param\u003e`\n  may be a symbol or a list `(\u003cname\u003e \u003cdefault\u003e)`. The `\u003cparams\u003e` and\n  `\u003crest-param\u003e` sections may be `match` patterns.\n\n### `(schemepunk term-colors)`\n\nANSI escape codes for terminal colors.\n\n`(write-in-color \u003ccolor\u003e \u003cstring\u003e)` writes `string` to `(current-output-port)`,\nwith the ANSI escape codes to make it appear as `color`. The escape codes are\nnot printed if Schemepunk detects that the current terminal does not support\nthem; this can be overridden by setting the parameter `term-colors-enabled?` to\n`#t`.\n\n`\u003ccolor\u003e` is a color object, which may be one of:\n\n- The 16 colors `black`, `red`, `yellow`, `green`, `blue`, `cyan`, `magenta`,\n  `white`, `light-black` (or `gray`), `light-red`, `light-yellow`,\n  `light-green`, `light-blue`, `light-cyan`, `light-magenta`, and `light-white`.\n- The 8 bold colors `bold-black`, `bold-red`, `bold-yellow`, `bold-green`,\n  `bold-blue`, `bold-cyan`, `bold-magenta`, and `bold-white`. Depending on your\n  terminal, these may look exactly like the light colors, or they may be\n  rendered in a bold font.\n\nColors can also be constructed with `make-color`, which takes any combination of\n[SGR parameters][sgr] from these groups:\n\n- Foreground colors `fg-black`, `fg-red`, `fg-light-red`, etc.\n- Background colors `bg-black`, `bg-red`, etc.\n- Attributes `attr-bold`, `attr-italic`, `attr-negative`, or `attr-underline`.\n\nOrder does not matter, and any or all of these can be omitted. `(make-color)`\nwith no arguments is the color reset escape code, also available as `reset`.\n\nIf your terminal supports 256 colors or true color, `(schemepunk term-color)`\ncan also generate those escape codes, using `(make-8-bit-color \u003cr\u003e \u003cg\u003e \u003cb\u003e)` and\n`(make-24-bit-color \u003cr\u003e \u003cg\u003e \u003cb\u003e)`. 8-bit RGB values range from 0-5; 24-bit RGB\nvalues range from 0-255. Background colors are also available via\n`make-8-bit-color/bg` and `make-24-bit-color/bg`.\n\nFor more fine-grained control, `(write-color \u003ccolor\u003e)` writes a single ANSI\nescape code. Make sure to reset with `(reset-color)` after writing!\n\n### `(schemepunk test)`\n\nA unit test framework modeled after Javascript's [Mocha][mocha]. Although its\npreferred API differs from [SRFI 64][srfi64], it includes compatibility macros\nthat allow it to run SRFI 64 tests without modifications.\n\n![Screenshot of unit test results](.readme-images/unit-test.png)\n\nTest suites are defined as `(test-group \u003cname\u003e \u003ctests\u003e…)`, where `\u003ctests\u003e` is\none or more `(test \u003cname\u003e \u003cexpressions\u003e…)` clauses. Test suite files have the\n`.test.scm` extension.\n\nTests are made up of assertions. `(schemepunk test)` provides these assertion\nfunctions:\n\n- `(assert-true \u003cmessage\u003e \u003cvalue\u003e)` *(`message` is optional)*\n- `(assert-false \u003cmessage\u003e \u003cvalue\u003e)` *(`message` is optional)*\n- `(assert-eq \u003cactual\u003e \u003cexpected\u003e)`\n- `(assert-eqv \u003cactual\u003e \u003cexpected\u003e)`\n- `(assert-equal \u003cactual\u003e \u003cexpected\u003e)`\n- `(assert-approximate \u003cactual\u003e \u003cexpected\u003e \u003cerror\u003e)`\n- `(fail \u003cmessage\u003e)`\n\n`(end-test-runner)` prints a report of passed/failed tests and ends the process\nwith the approporate return code, but you shouldn't need to call this on your\nown. The test runner scripts in `scripts` take care of finding all `.test.scm`\nfiles in the project, running all of them, and running `(end-test-runner)` at\nthe end.\n\nThe `Makefile` contains usage examples for the test runner scripts. Finding the\ntest files and running the tests are split into two separate scripts, because\nsome of my projects need to search only specific subdirectories for test files.\n\n### `(schemepunk vector)`\n\nPolyfilled alias for [SRFI 133 (Vector Library)][srfi133]. Exports one\nadditional procedure:\n\n- `(vector-filter \u003cpred?\u003e \u003cvec\u003e)` is the vector equivalent of `filter`. It\n  returns a new vector containing all elements of `\u003cvec\u003e` for which `pred?`\n  returns a non-`#f` value.\n\n## SRFI Implementation Table\n\n| SRFI           | Module                    | Description                  |\n| -------------- | ------------------------- | ---------------------------- |\n| [1][srfi1]     | `(schemepunk list)`       | List library                 |\n| [2][srfi2]     | `(schemepunk syntax)`     | `and-let*`                   |\n| [8][srfi8]     | `(schemepunk syntax)`     | `receive`                    |\n| [26][srfi26]   | `(schemepunk syntax)`     | `cut` and `cute`             |\n| [28][srfi28]   | `(schemepunk syntax)`     | `format`                     |\n| [41][srfi41]   | `(schemepunk stream)`     | Streams                      |\n| [64][srfi64]   | `(schemepunk test)`       | Unit tests                   |\n| [111][srfi111] | `(schemepunk box)`        | Boxes                        |\n| [113][srfi113] | `(schemepunk set)`        | Sets and bags                |\n| [125][srfi125] | `(schemepunk hash-table)` | Hash tables                  |\n| [128][srfi128] | `(schemepunk comparator)` | Comparators                  |\n| [132][srfi132] | `(schemepunk sort)`       | Sorting libraries (partial)  |\n| [133][srfi133] | `(schemepunk vector)`     | Vector library               |\n| [145][srfi145] | `(schemepunk syntax)`     | Assumptions                  |\n| [146][srfi146] | `(schemepunk mapping)`    | Mappings (w/o `(srfi 146 hash)`) |\n| [152][srfi152] | `(schemepunk string)`     | String library (reduced)     |\n| [156][srfi156] | `(schemepunk syntax)`     | `is` and `isnt`              |\n| [158][srfi158] | `(schemepunk generator)`  | Generators and accumulators  |\n| [162][srfi162] | `(schemepunk comparator)` | Comparators sublibrary       |\n| [166][srfi166] | `(schemepunk show)`       | Monadic formatting           |\n| [173][srfi173] | `(schemepunk hook)`       | Hooks                        |\n| [197][srfi197] | `(schemepunk syntax)`     | `chain` and related macros   |\n| [214][srfi214] | `(schemepunk flexvector)` | Flexvectors                  |\n\nThese modules are aliases for several common SRFIs and R7RS Large libraries,\nalong with implementations of these libraries for Schemes that don't provide\nthem by default. The implementations are in the `polyfills` directory; they are\ncopied from either the SRFI documents or Chibi Scheme.\n\n## License\n\nCopyright \u0026copy; 2020-2021 Adam Nelson\n\nSchemepunk is distributed under the [Blue Oak Model License][blue-oak]. It is\na MIT/BSD-style license, but with [some clarifying improvements][why-blue-oak]\naround patents, attribution, and multiple contributors.\n\nSchemepunk also includes MIT/BSD-licensed code from the following authors:\n\n- SRFI 113, 125, 132, and 133 implementations, and parts of SRFI 166\n  implementation, are taken from Chibi Scheme, copyright \u0026copy; 2009-2020 Alex\n  Shinn\n- SRFI 128 implementation copyright \u0026copy; 2015 John Cowan\n- SRFI 146 tests and original reference implementation copyright \u0026copy;\n  2016-2017 Marc Nieper-Wißkirchen\n- SRFI 152 tests and original reference implementation copyright \u0026copy; 2017\n  John Cowan\n- SRFI 156 implementation adapted from reference implementation, copyright\n  \u0026copy; 2017 Panicz Maciej Godek\n- SRFI 158 implementation copyright \u0026copy; 2015 Shiro Kawai, John Cowan, Thomas\n  Gilray\n\n[gauche]: http://practical-scheme.net/gauche/\n[chibi]: http://synthcode.com/scheme/chibi/\n[kawa]: https://www.gnu.org/software/kawa/\n[gerbil]: https://cons.io/\n[larceny]: http://www.larcenists.org/\n[chicken]: http://call-cc.org/\n[sagittarius]: https://bitbucket.org/ktakashi/sagittarius-scheme/wiki/Home\n[srfi1]: https://srfi.schemers.org/srfi-1/\n[srfi2]: https://srfi.schemers.org/srfi-2/\n[srfi8]: https://srfi.schemers.org/srfi-8/\n[srfi13]: https://srfi.schemers.org/srfi-13/\n[srfi26]: https://srfi.schemers.org/srfi-26/\n[srfi28]: https://srfi.schemers.org/srfi-28/\n[srfi41]: https://srfi.schemers.org/srfi-41/\n[srfi64]: https://srfi.schemers.org/srfi-64/\n[srfi111]: https://srfi.schemers.org/srfi-111/\n[srfi113]: https://srfi.schemers.org/srfi-113/\n[srfi125]: https://srfi.schemers.org/srfi-125/\n[srfi128]: https://srfi.schemers.org/srfi-128/\n[srfi130]: https://srfi.schemers.org/srfi-130/\n[srfi132]: https://srfi.schemers.org/srfi-132/\n[srfi133]: https://srfi.schemers.org/srfi-133/\n[srfi145]: https://srfi.schemers.org/srfi-145/\n[srfi146]: https://srfi.schemers.org/srfi-146/\n[srfi152]: https://srfi.schemers.org/srfi-152/\n[srfi156]: https://srfi.schemers.org/srfi-156/\n[srfi158]: https://srfi.schemers.org/srfi-158/\n[srfi162]: https://srfi.schemers.org/srfi-162/\n[srfi166]: https://srfi.schemers.org/srfi-166/\n[srfi173]: https://srfi.schemers.org/srfi-173/\n[srfi197]: https://srfi.schemers.org/srfi-197/\n[srfi214]: https://srfi.schemers.org/srfi-214/\n[clojure-threading]: https://clojure.org/guides/threading_macros\n[chibi-app]: http://synthcode.com/scheme/chibi/lib/chibi/app.html\n[chibi-match]: http://synthcode.com/scheme/chibi/lib/chibi/match.html\n[sgr]: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters\n[mocha]: https://mochajs.org/\n[blue-oak]: https://blueoakcouncil.org/license/1.0.0\n[why-blue-oak]: https://writing.kemitchell.com/2019/03/09/Deprecation-Notice.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Far-nelson%2Fschemepunk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Far-nelson%2Fschemepunk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Far-nelson%2Fschemepunk/lists"}