From patchwork Sun Feb 13 21:51:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37228 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 232E527BBEB; Sun, 13 Feb 2022 21:55:01 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 9C3FB27BBEA for ; Sun, 13 Feb 2022 21:54:59 +0000 (GMT) Received: from localhost ([::1]:56956 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpe-0005cU-EM for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:54:58 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43402) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMok-0005bg-Rt for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45179) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMok-0001tV-Ft for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:02 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMok-0003De-FW for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 01/11] gnu: chez-scheme: Move to (gnu packages chez-and-racket-bootstrap). Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478918212183 (code B ref 53878); Sun, 13 Feb 2022 21:54:02 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:02 +0000 Received: from localhost ([127.0.0.1]:39047 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnf-00039g-Js for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:02 -0500 Received: from mail-qk1-f182.google.com ([209.85.222.182]:33337) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnc-00039A-OJ for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:52:54 -0500 Received: by mail-qk1-f182.google.com with SMTP id o10so13044418qkg.0 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:52:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=YXEzfRfk7WXdireVn5LxJcvoc08nT3yzfc0dg5tOroo=; b=XtYjrFv5LAkRNY1uTMATTZuIprTbR7ddGlMc3iraNwPWHTwHHQCWk2k3f5cxXR0Mn4 drfxHIAxEPrlM6o08kvHaYHtrvlHChNS7pevYiChCBVFo02U9+a7ZZPhfSf5ixsG9B4g DuDNdLmRQSPjx7NSJUJeVOMKSs0okz7de1kEAkWIwy/z7cdebeLhNH0VYLmR99WfCNTd 7xDfI2BzVFWoLL6CLT10c11plk28pGtDO0IIIFqtzq1hD6QzvTAFnJL+zpb8WAe8z9fD QbIlKIKBB62ivaGhXe7dqFftwlaMe5NQLhpBjYWkxZL1tlRQ8RHI/iVFDZUzX1zSKSWo pBtQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=YXEzfRfk7WXdireVn5LxJcvoc08nT3yzfc0dg5tOroo=; b=VG9eK+HpE/LubKb/Jxk1SwHQF3mnY9+igRTrRuuZaBj3W4GTSFoe1rnM/Ba0p1zUgx wvpb6HpMUYc0XF+9aaN9tkCVMCO11+RsDSAGo9koNv3NgmCE8LYO0n4l3paSBNrbB2B4 ir3jWqQUC5kfrPaH2qf81T35g9YTZwMJoQMIRAyRq2wleVhB3UAD/NUKoTw4VWWqX8ar sfD/RzIKsG3laN/AiOiruYzuyR9UZL0TOZVnWVncMh7cZ75UxzlNbt7q30MUQNqV7uoh QZis3cNsRo47bCQ3EKNFKYxH4ZsU9byMtm1QVx4zLZpzGrh7h/wJTBcOy9+XmaC6PjhM 1Bng== X-Gm-Message-State: AOAM533QdJJ/GJh4H0bAjTOWSTLRxmgs/jlJAegLudhPaoqwZMOSU/1e Lt0532aZgGLPIBRilmkM6CXtURx4atmCYmQjwz8= X-Google-Smtp-Source: ABdhPJyvctNiTnk+nNemk18lSctuuif13w62WGjLLELFjh8PhjXHE8qV2UH6SbpMD3X7JljllYhXnA== X-Received: by 2002:a05:620a:458f:: with SMTP id bp15mr5655084qkb.670.1644789166543; Sun, 13 Feb 2022 13:52:46 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id b14sm784193qkp.23.2022.02.13.13.52.46 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:52:46 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:17 -0500 Message-Id: <20220213215127.218952-2-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/packages/chez.scm (nanopass, stex, chez-scheme): Move to ... * gnu/packages/chez-and-racket-bootstrap.scm: ... this new file. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. * gnu/packages/emacs-xyz.scm: Adjust imports accordingly. * gnu/packages/loko.scm: Likewise. * gnu/packages/racket.scm: Likewise. --- gnu/local.mk | 1 + gnu/packages/chez-and-racket-bootstrap.scm | 278 +++++++++++++++++++++ gnu/packages/chez.scm | 225 +---------------- gnu/packages/emacs-xyz.scm | 2 +- gnu/packages/loko.scm | 2 +- gnu/packages/racket.scm | 2 +- 6 files changed, 283 insertions(+), 227 deletions(-) create mode 100644 gnu/packages/chez-and-racket-bootstrap.scm diff --git a/gnu/local.mk b/gnu/local.mk index 1b08b40b9c..72e086d465 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -144,6 +144,7 @@ GNU_SYSTEM_MODULES = \ %D%/packages/certs.scm \ %D%/packages/check.scm \ %D%/packages/chemistry.scm \ + %D%/packages/chez-and-racket-bootstrap.scm \ %D%/packages/chez.scm \ %D%/packages/chicken.scm \ %D%/packages/chromium.scm \ diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm new file mode 100644 index 0000000000..f102b099fb --- /dev/null +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -0,0 +1,278 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2016 Federico Beffa +;;; Copyright © 2016 Efraim Flashner +;;; Copyright © 2017, 2019 Tobias Geerinckx-Rice +;;; Copyright © 2019 Brett Gilio +;;; Copyright © 2020 Brendan Tildesley +;;; Copyright © 2021, 2022 Philip McGrath +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu packages chez-and-racket-bootstrap) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix git-download) + #:use-module (guix utils) + #:use-module (guix gexp) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:use-module (guix build-system gnu) + #:use-module (gnu packages) + #:use-module (gnu packages compression) + #:use-module (gnu packages ghostscript) + #:use-module (gnu packages linux) + #:use-module (gnu packages ncurses) + #:use-module (gnu packages netpbm) + #:use-module (gnu packages tex) + #:use-module (gnu packages xorg) + #:use-module ((guix licenses) + #:prefix license:)) + +;; Commentary: +;; +;; Alphabetically and chronologically, Chez comes before Racket. +;; +;; The bootstrapping paths for Chez Scheme and Racket are closely +;; entwined. Racket CS (the default Racket implementation) is based on (a fork +;; of) Chez Scheme. Racket's variant of Chez Scheme shares sources for +;; nanopass and stex with upstream Chez Scheme. +;; +;; Racket's variant of Chez Scheme can be bootstrapped by an older Racket +;; implementation, Racket BC, which can be bootstrapped from C. Porting that +;; code to work with upstream Chez Scheme (or finding an old version that +;; does) is our best hope for some day bootstrapping upstream Chez Scheme from +;; source. +;; +;; Putting the relevant definitions together in this module avoids having to +;; work around dependency cycles. +;; +;; Code: + +(define nanopass + (let ((version "1.9.2")) + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/nanopass/nanopass-framework-scheme") + (commit (string-append "v" version)))) + (sha256 (base32 "16vjsik9rrzbabbhbxbaha51ppi3f9n8rk59pc6zdyffs0vziy4i")) + (file-name (git-file-name "nanopass" version))))) + +(define stex + ;; This commit includes a fix, which we would otherwise want to use as + ;; patch. Let's revert to tagged releases as soon as one becomes available. + (let* ((commit "54051494434a197772bf6ca5b4e6cf6be55f39a5") + (version "1.2.2") + (version (git-version version "1" commit))) + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/dybvig/stex") + (commit commit))) + (sha256 (base32 "01jnvw8qw33gnpzwrakwhsr05h6b609lm180jnspcrb7lds2p23d")) + (file-name (git-file-name "stex" version))))) + +(define-public chez-scheme + (package + (name "chez-scheme") + (version "9.5.6") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/cisco/ChezScheme") + (commit (string-append "v" version)))) + (sha256 + (base32 "07s433hn1z2slfc026sidrpzxv3a8narcd40qqr1xrpb9012xdky")) + (file-name (git-file-name name version)) + (snippet + ;; Remove bundled libraries. + (with-imported-modules '((guix build utils)) + #~(begin + (use-modules (guix build utils)) + (for-each (lambda (dir) + (when (directory-exists? dir) + (delete-file-recursively dir))) + '("stex" + "nanopass" + "lz4" + "zlib"))))))) + (build-system gnu-build-system) + (inputs + `(("libuuid" ,util-linux "lib") + ("zlib" ,zlib) + ("zlib:static" ,zlib "static") + ("lz4" ,lz4) + ("lz4:static" ,lz4 "static") + ;; for expeditor: + ("ncurses" ,ncurses) + ;; for X11 clipboard support in expeditor: + ;; https://github.com/cisco/ChezScheme/issues/9#issuecomment-222057232 + ("libx11" ,libx11))) + (native-inputs + `(("nanopass" ,nanopass) ; source only + ;; for docs + ("stex" ,stex) + ("xorg-rgb" ,xorg-rgb) + ("texlive" ,(texlive-updmap.cfg (list texlive-dvips-l3backend + texlive-epsf + texlive-fonts-ec + texlive-oberdiek))) + ("ghostscript" ,ghostscript) + ("netpbm" ,netpbm))) + (native-search-paths + (list (search-path-specification + (variable "CHEZSCHEMELIBDIRS") + (files (list (string-append "lib/csv" version "-site")))))) + (outputs '("out" "doc")) + (arguments + `(#:modules + ((guix build gnu-build-system) + (guix build utils) + (ice-9 ftw) + (ice-9 match)) + #:test-target "test" + #:configure-flags + '("--threads") ;; TODO when we fix armhf, it doesn't support --threads + #:phases + (modify-phases %standard-phases + ;; put these where configure expects them to be + (add-after 'unpack 'unpack-nanopass+stex + (lambda* (#:key native-inputs inputs #:allow-other-keys) + (for-each (lambda (dep) + (define src + (assoc-ref (or native-inputs inputs) dep)) + (copy-recursively src dep + #:keep-mtime? #t)) + '("nanopass" "stex")))) + ;; NOTE: the custom Chez 'configure' script doesn't allow + ;; unrecognized flags, such as those automatically added + ;; by `gnu-build-system`. + (replace 'configure + (lambda* (#:key inputs outputs + (configure-flags '()) + #:allow-other-keys) + (let* ((zlib-static (assoc-ref inputs "zlib:static")) + (lz4-static (assoc-ref inputs "lz4:static")) + (out (assoc-ref outputs "out")) + ;; add flags which are always required: + (flags (cons* + (string-append "--installprefix=" out) + (string-append "ZLIB=" zlib-static "/lib/libz.a") + (string-append "LZ4=" lz4-static "/lib/liblz4.a") + ;; Guix will do compress man pages, + ;; and letting Chez try causes an error + "--nogzip-man-pages" + configure-flags))) + (format #t "configure flags: ~s~%" flags) + ;; Some makefiles (for tests) don't seem to propagate CC + ;; properly, so we take it out of their hands: + (setenv "CC" ,(cc-for-target)) + (setenv "HOME" "/tmp") + (apply invoke + "./configure" + flags)))) + ;; The binary file name is called "scheme" as is the one from MIT/GNU + ;; Scheme. We add a symlink to use in case both are installed. + (add-after 'install 'install-symlink + (lambda* (#:key outputs #:allow-other-keys) + (let* ((out (assoc-ref outputs "out")) + (bin (string-append out "/bin")) + (lib (string-append out "/lib")) + (name "chez-scheme")) + (symlink (string-append bin "/scheme") + (string-append bin "/" name)) + (map (lambda (file) + (symlink file (string-append (dirname file) + "/" name ".boot"))) + (find-files lib "scheme.boot"))))) + ;; Building explicitly lets us avoid using substitute* + ;; to re-write makefiles. + (add-after 'install-symlink 'prepare-stex + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (let* ((stex+version + (strip-store-file-name + (assoc-ref (or native-inputs inputs) "stex"))) + ;; Eventually we want to install stex as a real + ;; package so it's reusable. For now: + (stex-output "/tmp") + (doc-dir (string-append stex-output + "/share/doc/" + stex+version))) + (with-directory-excursion "stex" + (invoke "make" + "install" + (string-append "LIB=" + stex-output + "/lib/" + stex+version) + (string-append "Scheme=" + (assoc-ref outputs "out") + "/bin/scheme")) + (for-each (lambda (pth) + (install-file pth doc-dir)) + '("ReadMe" ; includes the license + "doc/stex.html" + "doc/stex.css" + "doc/stex.pdf")))))) + ;; Building the documentation requires stex and a running scheme. + ;; FIXME: this is probably wrong for cross-compilation + (add-after 'prepare-stex 'install-doc + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (let* ((chez+version (strip-store-file-name + (assoc-ref outputs "out"))) + (stex+version + (strip-store-file-name + (assoc-ref (or native-inputs inputs) "stex"))) + (scheme (string-append (assoc-ref outputs "out") + "/bin/scheme")) + ;; see note on stex-output in phase build-stex, above: + (stexlib (string-append "/tmp" + "/lib/" + stex+version)) + (doc-dir (string-append (assoc-ref outputs "doc") + "/share/doc/" + chez+version))) + (define* (stex-make #:optional (suffix "")) + (invoke "make" + "install" + (string-append "Scheme=" scheme) + (string-append "STEXLIB=" stexlib) + (string-append "installdir=" doc-dir suffix))) + (with-directory-excursion "csug" + (stex-make "/csug")) + (with-directory-excursion "release_notes" + (stex-make "/release_notes")) + (with-directory-excursion doc-dir + (symlink "release_notes/release_notes.pdf" + "release_notes.pdf") + (symlink "csug/csug9_5.pdf" + "csug.pdf")))))))) + ;; Chez Scheme does not have a MIPS backend. + ;; FIXME: Debian backports patches to get armhf working. + ;; We should too. It is the Chez machine type arm32le + ;; (no threaded version upstream yet, though there is in + ;; Racket's fork), more specifically (per the release notes) ARMv6. + (supported-systems (fold delete %supported-systems + '("mips64el-linux" "armhf-linux"))) + (home-page "https://cisco.github.io/ChezScheme/") + (synopsis "R6RS Scheme compiler and run-time") + (description + "Chez Scheme is a compiler and run-time system for the language of the +Revised^6 Report on Scheme (R6RS), with numerous extensions. The compiler +generates native code for each target processor, with support for x86, x86_64, +and 32-bit PowerPC architectures.") + (license license:asl2.0))) diff --git a/gnu/packages/chez.scm b/gnu/packages/chez.scm index 47904e7b4e..caf61a95f5 100644 --- a/gnu/packages/chez.scm +++ b/gnu/packages/chez.scm @@ -4,7 +4,6 @@ ;;; Copyright © 2017, 2019 Tobias Geerinckx-Rice ;;; Copyright © 2019 Brett Gilio ;;; Copyright © 2020 Brendan Tildesley -;;; Copyright © 2021 Philip McGrath ;;; ;;; This file is part of GNU Guix. ;;; @@ -32,234 +31,12 @@ (define-module (gnu packages chez) #:use-module (guix utils) #:use-module (guix gexp) #:use-module (guix build-system gnu) - #:use-module (gnu packages compression) - #:use-module (gnu packages ncurses) + #:use-module (gnu packages chez-and-racket-bootstrap) #:use-module (gnu packages ghostscript) - #:use-module (gnu packages linux) - #:use-module (gnu packages netpbm) #:use-module (gnu packages tex) - #:use-module (gnu packages compression) - #:use-module (gnu packages image) - #:use-module (gnu packages xorg) #:use-module (ice-9 match) #:use-module (srfi srfi-1)) -(define nanopass - (let ((version "1.9.2")) - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/nanopass/nanopass-framework-scheme") - (commit (string-append "v" version)))) - (sha256 (base32 "16vjsik9rrzbabbhbxbaha51ppi3f9n8rk59pc6zdyffs0vziy4i")) - (file-name (git-file-name "nanopass" version))))) - -(define stex - ;; This commit includes a fix, which we would otherwise want to use as - ;; patch. Let's revert to tagged releases as soon as one becomes available. - (let* ((commit "54051494434a197772bf6ca5b4e6cf6be55f39a5") - (version "1.2.2") - (version (git-version version "1" commit))) - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/dybvig/stex") - (commit commit))) - (sha256 (base32 "01jnvw8qw33gnpzwrakwhsr05h6b609lm180jnspcrb7lds2p23d")) - (file-name (git-file-name "stex" version))))) - -(define-public chez-scheme - (package - (name "chez-scheme") - (version "9.5.6") - (source - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/cisco/ChezScheme") - (commit (string-append "v" version)))) - (sha256 - (base32 "07s433hn1z2slfc026sidrpzxv3a8narcd40qqr1xrpb9012xdky")) - (file-name (git-file-name name version)) - (snippet - ;; Remove bundled libraries. - (with-imported-modules '((guix build utils)) - #~(begin - (use-modules (guix build utils)) - (for-each (lambda (dir) - (when (directory-exists? dir) - (delete-file-recursively dir))) - '("stex" - "nanopass" - "lz4" - "zlib"))))))) - (build-system gnu-build-system) - (inputs - `(("libuuid" ,util-linux "lib") - ("zlib" ,zlib) - ("zlib:static" ,zlib "static") - ("lz4" ,lz4) - ("lz4:static" ,lz4 "static") - ;; for expeditor: - ("ncurses" ,ncurses) - ;; for X11 clipboard support in expeditor: - ;; https://github.com/cisco/ChezScheme/issues/9#issuecomment-222057232 - ("libx11" ,libx11))) - (native-inputs - `(("nanopass" ,nanopass) ; source only - ;; for docs - ("stex" ,stex) - ("xorg-rgb" ,xorg-rgb) - ("texlive" ,(texlive-updmap.cfg (list texlive-dvips-l3backend - texlive-epsf - texlive-fonts-ec - texlive-oberdiek))) - ("ghostscript" ,ghostscript) - ("netpbm" ,netpbm))) - (native-search-paths - (list (search-path-specification - (variable "CHEZSCHEMELIBDIRS") - (files (list (string-append "lib/csv" version "-site")))))) - (outputs '("out" "doc")) - (arguments - `(#:modules - ((guix build gnu-build-system) - (guix build utils) - (ice-9 ftw) - (ice-9 match)) - #:test-target "test" - #:configure-flags - '("--threads") ;; TODO when we fix armhf, it doesn't support --threads - #:phases - (modify-phases %standard-phases - ;; put these where configure expects them to be - (add-after 'unpack 'unpack-nanopass+stex - (lambda* (#:key native-inputs inputs #:allow-other-keys) - (for-each (lambda (dep) - (define src - (assoc-ref (or native-inputs inputs) dep)) - (copy-recursively src dep - #:keep-mtime? #t)) - '("nanopass" "stex")))) - ;; NOTE: the custom Chez 'configure' script doesn't allow - ;; unrecognized flags, such as those automatically added - ;; by `gnu-build-system`. - (replace 'configure - (lambda* (#:key inputs outputs - (configure-flags '()) - #:allow-other-keys) - (let* ((zlib-static (assoc-ref inputs "zlib:static")) - (lz4-static (assoc-ref inputs "lz4:static")) - (out (assoc-ref outputs "out")) - ;; add flags which are always required: - (flags (cons* - (string-append "--installprefix=" out) - (string-append "ZLIB=" zlib-static "/lib/libz.a") - (string-append "LZ4=" lz4-static "/lib/liblz4.a") - ;; Guix will do compress man pages, - ;; and letting Chez try causes an error - "--nogzip-man-pages" - configure-flags))) - (format #t "configure flags: ~s~%" flags) - ;; Some makefiles (for tests) don't seem to propagate CC - ;; properly, so we take it out of their hands: - (setenv "CC" ,(cc-for-target)) - (setenv "HOME" "/tmp") - (apply invoke - "./configure" - flags)))) - ;; The binary file name is called "scheme" as is the one from MIT/GNU - ;; Scheme. We add a symlink to use in case both are installed. - (add-after 'install 'install-symlink - (lambda* (#:key outputs #:allow-other-keys) - (let* ((out (assoc-ref outputs "out")) - (bin (string-append out "/bin")) - (lib (string-append out "/lib")) - (name "chez-scheme")) - (symlink (string-append bin "/scheme") - (string-append bin "/" name)) - (map (lambda (file) - (symlink file (string-append (dirname file) - "/" name ".boot"))) - (find-files lib "scheme.boot"))))) - ;; Building explicitly lets us avoid using substitute* - ;; to re-write makefiles. - (add-after 'install-symlink 'prepare-stex - (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) - (let* ((stex+version - (strip-store-file-name - (assoc-ref (or native-inputs inputs) "stex"))) - ;; Eventually we want to install stex as a real - ;; package so it's reusable. For now: - (stex-output "/tmp") - (doc-dir (string-append stex-output - "/share/doc/" - stex+version))) - (with-directory-excursion "stex" - (invoke "make" - "install" - (string-append "LIB=" - stex-output - "/lib/" - stex+version) - (string-append "Scheme=" - (assoc-ref outputs "out") - "/bin/scheme")) - (for-each (lambda (pth) - (install-file pth doc-dir)) - '("ReadMe" ; includes the license - "doc/stex.html" - "doc/stex.css" - "doc/stex.pdf")))))) - ;; Building the documentation requires stex and a running scheme. - ;; FIXME: this is probably wrong for cross-compilation - (add-after 'prepare-stex 'install-doc - (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) - (let* ((chez+version (strip-store-file-name - (assoc-ref outputs "out"))) - (stex+version - (strip-store-file-name - (assoc-ref (or native-inputs inputs) "stex"))) - (scheme (string-append (assoc-ref outputs "out") - "/bin/scheme")) - ;; see note on stex-output in phase build-stex, above: - (stexlib (string-append "/tmp" - "/lib/" - stex+version)) - (doc-dir (string-append (assoc-ref outputs "doc") - "/share/doc/" - chez+version))) - (define* (stex-make #:optional (suffix "")) - (invoke "make" - "install" - (string-append "Scheme=" scheme) - (string-append "STEXLIB=" stexlib) - (string-append "installdir=" doc-dir suffix))) - (with-directory-excursion "csug" - (stex-make "/csug")) - (with-directory-excursion "release_notes" - (stex-make "/release_notes")) - (with-directory-excursion doc-dir - (symlink "release_notes/release_notes.pdf" - "release_notes.pdf") - (symlink "csug/csug9_5.pdf" - "csug.pdf")))))))) - ;; Chez Scheme does not have a MIPS backend. - ;; FIXME: Debian backports patches to get armhf working. - ;; We should too. It is the Chez machine type arm32le - ;; (no threaded version upstream yet, though there is in - ;; Racket's fork), more specifically (per the release notes) ARMv6. - (supported-systems (fold delete %supported-systems - '("mips64el-linux" "armhf-linux"))) - (home-page "https://cisco.github.io/ChezScheme/") - (synopsis "R6RS Scheme compiler and run-time") - (description - "Chez Scheme is a compiler and run-time system for the language of the -Revised^6 Report on Scheme (R6RS), with numerous extensions. The compiler -generates native code for each target processor, with support for x86, x86_64, -and 32-bit PowerPC architectures.") - (license asl2.0))) - (define-public chez-srfi (package (name "chez-srfi") diff --git a/gnu/packages/emacs-xyz.scm b/gnu/packages/emacs-xyz.scm index e4390bad96..02694b636a 100644 --- a/gnu/packages/emacs-xyz.scm +++ b/gnu/packages/emacs-xyz.scm @@ -145,7 +145,7 @@ (define-module (gnu packages emacs-xyz) #:use-module (gnu packages aspell) #:use-module (gnu packages audio) #:use-module (gnu packages bash) - #:use-module (gnu packages chez) + #:use-module (gnu packages chez-and-racket-bootstrap) #:use-module (gnu packages cmake) #:use-module (gnu packages code) #:use-module (gnu packages cpp) diff --git a/gnu/packages/loko.scm b/gnu/packages/loko.scm index ef9312afe3..74a649b8a1 100644 --- a/gnu/packages/loko.scm +++ b/gnu/packages/loko.scm @@ -24,7 +24,7 @@ (define-module (gnu packages loko) #:use-module (gnu packages package-management) #:use-module (gnu packages guile) #:use-module (gnu packages guile-xyz) - #:use-module (gnu packages chez)) + #:use-module (gnu packages chez-and-racket-bootstrap)) (define-public loko-scheme (package diff --git a/gnu/packages/racket.scm b/gnu/packages/racket.scm index d0a5ca494b..865fdff70f 100644 --- a/gnu/packages/racket.scm +++ b/gnu/packages/racket.scm @@ -34,7 +34,7 @@ (define-module (gnu packages racket) #:use-module (gnu packages) #:use-module (gnu packages autotools) #:use-module (gnu packages bash) - #:use-module (gnu packages chez) + #:use-module (gnu packages chez-and-racket-bootstrap) #:use-module (gnu packages compression) #:use-module (gnu packages databases) #:use-module (gnu packages fontutils) From patchwork Sun Feb 13 21:51:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37233 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 5DCE327BBE9; Sun, 13 Feb 2022 21:55:12 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id EAF6027BBEA for ; Sun, 13 Feb 2022 21:55:10 +0000 (GMT) Received: from localhost ([::1]:57796 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpp-0006Fx-VV for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:10 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43404) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMol-0005bn-Aj for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45180) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMok-0001ta-Sb for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMok-0003Dm-SY for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 02/11] gnu: chez-scheme: Use "lib/chez-scheme" for search path. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478918612201 (code B ref 53878); Sun, 13 Feb 2022 21:54:02 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:06 +0000 Received: from localhost ([127.0.0.1]:39052 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnm-0003AS-IK for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:06 -0500 Received: from mail-qk1-f176.google.com ([209.85.222.176]:38558) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMng-00039N-F7 for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:52:57 -0500 Received: by mail-qk1-f176.google.com with SMTP id o12so12991779qke.5 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:52:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=spAKc6Y38W1TlPs5i3iI5b1SXgaYKzCROU+vlNbbPq8=; b=bS8sdXzawKvauYvMn/TI7vpoDtoQ/CctUvFJeFo4FsJ+ZyBYQrQn5zxUbyUCDSdLk7 GKnL2QH28Pc8JFbLEai+tEqPXxz8SsRg4YyawlcS4tOymiScEHcdIhtxV8fbgmDY45bb Pi1/+/mmYex2x+7mlJ96cUotMrrzQ+lXguPUCtFP8OlBePX+srSfH5Z98q4KXFu4brEW K3BFvXI1NDSnj0q1Y2gp0toZavUk/7urOHHiNtDOpzheY9tgQLcVa/mzoQWq/j/AxptY EQKOWi+OeOzQLNlUnyhCIPxLZWF6059U/ghexssyM/DXjXomDXj38aPk4Im0+srAqB40 OFdg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=spAKc6Y38W1TlPs5i3iI5b1SXgaYKzCROU+vlNbbPq8=; b=R5ua7ArIn72zVxD+tJcI48LIFYWQr7MJ9c4pybx9FxgVlEgWZ2S5m6W1UKeEjbtxub X51lusurwiK3zMQXfrbWyk6dO1X5sNFqBo5O1HubPcf1dw0grHgjHuJgcL6ZqPljBP3a Q0rmOZnQrIWHvHN9c6/lgnjFpWVI0L3wqaKjkULTZYWHQyHtCumrAzxVa1xK1/41xDFn QF0GXfCE/HcapV6XtO/OFQSCGa1SInkeRaxgddgJAUAJCrsDwMU8hiBS6mcpqHrjf9HB b6/eNL7VOROMwKpfEUROBI52UNHddBLhxs389NVyEcEPqtOatg8wsYln7V/WDcmXNDv0 KiFA== X-Gm-Message-State: AOAM531tXZdwzyYT4qo8RaZb0VpYBcRNaV11iG/jZgjEmqWQmFgEAgAR sgyVDGY0m/B9q9Z1mrOc30clmu3Gg4fgT/NpD34= X-Google-Smtp-Source: ABdhPJzJ2C1oKdIUBWFP09FEUeQj0prgjRTaC5MZ0+bOCEiANiDoNnSNTQ315LQtHHjb4saG0C2/Bw== X-Received: by 2002:a05:620a:2682:: with SMTP id c2mr5764719qkp.481.1644789170633; Sun, 13 Feb 2022 13:52:50 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id e1sm7959297qtw.71.2022.02.13.13.52.50 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:52:50 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:18 -0500 Message-Id: <20220213215127.218952-3-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches There does not seem to be any widely accepted standard path to use for "CHEZSCHEMELIBDIRS". Using a path without a version number in it avoids having to compute the actual path everywhere, which would be especially unpleasant when support is added for the Racket variant of Chez Scheme, which always has a different version number than upstream. * gnu/packages/chez-and-racket-bootstrap.scm (chez-scheme)[native-search-paths]: Change to use "lib/chez-scheme" instead of "lib/csvX.Y.Z-site" for "CHEZSCHEMELIBDIRS". * gnu/packages/chez.scm (chez-srfi, chez-web, chez-sockets, chez-matchable, chez-irregex, chez-fmt, chez-mit, chez-scmutils): Update accordingly. Also, remove input labels and use G-expressions. --- gnu/packages/chez-and-racket-bootstrap.scm | 2 +- gnu/packages/chez.scm | 373 +++++++++++---------- 2 files changed, 191 insertions(+), 184 deletions(-) diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index f102b099fb..1ed4631ced 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -136,7 +136,7 @@ (define-public chez-scheme (native-search-paths (list (search-path-specification (variable "CHEZSCHEMELIBDIRS") - (files (list (string-append "lib/csv" version "-site")))))) + (files (list (string-append "lib/chez-scheme")))))) (outputs '("out" "doc")) (arguments `(#:modules diff --git a/gnu/packages/chez.scm b/gnu/packages/chez.scm index caf61a95f5..54bbee7923 100644 --- a/gnu/packages/chez.scm +++ b/gnu/packages/chez.scm @@ -37,6 +37,28 @@ (define-module (gnu packages chez) #:use-module (ice-9 match) #:use-module (srfi srfi-1)) + +;; Help function for Chez Scheme to add the current path to +;; CHEZSCHEMELIBDIRS. +(define chez-configure + #~(lambda _ + (let ((chez-env (getenv "CHEZSCHEMELIBDIRS"))) + (setenv "CHEZSCHEMELIBDIRS" + (if chez-env + (string-append ".:" chez-env) + "."))))) + +;; Help function to define make flags for some Chez Scheme custom make +;; files. +(define (chez-make-flags name version) + #~(let ((out #$output)) + (list + ;; Set 'schemedir' so that libraries are installed in + ;; 'lib/chez-scheme' like Chez's 'native-search-paths' expects. + (string-append "schemedir=" out "/lib/chez-scheme") + (string-append "PREFIX=" out) + (string-append "DOCDIR=" out "/share/doc/" #$name "-" #$version)))) + (define-public chez-srfi (package (name "chez-srfi") @@ -54,13 +76,11 @@ (define-public chez-srfi (native-inputs (list chez-scheme)) (arguments - `(#:make-flags (let ((out (assoc-ref %outputs "out"))) - (list (string-append "PREFIX=" out) - "CHEZ=chez-scheme --libdirs ./" - (string-append "chezversion=" ,(package-version chez-scheme)))) - #:test-target "test" - #:phases (modify-phases %standard-phases - (delete 'configure)))) + (list #:make-flags (chez-make-flags name version) + #:test-target "test" + #:phases #~(modify-phases %standard-phases + (replace 'configure + #$chez-configure)))) (home-page "https://github.com/fedeinthemix/chez-srfi") (synopsis "SRFI libraries for Chez Scheme") (description @@ -85,42 +105,48 @@ (define-public chez-web (base32 "1dq25qygyncbfq4kwwqqgyyakfqjwhp5q23vrf3bff1p66nyfl3b")))) (build-system gnu-build-system) (native-inputs - `(("chez-scheme" ,chez-scheme) - ("ghostscript" ,ghostscript) - ("texlive" ,(texlive-updmap.cfg (list texlive-oberdiek - texlive-epsf - texlive-metapost - texlive-charter - texlive-pdftex - texlive-context - texlive-cm - texlive-tex-plain))))) + (list chez-scheme + ghostscript + ;; FIXME: This package fails to build with the error: + ;; mktexpk: don't know how to create bitmap font for bchr8r + ;; Replacing the following with `texlive` fixes it. + ;; What is missing? + (texlive-updmap.cfg (list texlive-oberdiek + texlive-epsf + texlive-metapost + texlive-charter + texlive-pdftex + texlive-context + texlive-cm + texlive-tex-plain)))) (arguments - `(#:make-flags (list (string-append "PREFIX=" %output) - (string-append "DOCDIR=" %output "/share/doc/" - ,name "-" ,version) - (string-append "LIBDIR=" %output "/lib/chezweb") - (string-append "TEXDIR=" %output "/share/texmf-local")) - #:tests? #f ; no tests - #:phases - (modify-phases %standard-phases - ;; This package has a custom "bootstrap" script that - ;; is meant to be run from the Makefile. - (delete 'bootstrap) - (replace 'configure - (lambda* _ - (copy-file "config.mk.template" "config.mk") - (substitute* "tangleit" - (("\\./cheztangle\\.ss" all) - (string-append "chez-scheme --program " all))) - (substitute* "weaveit" - (("mpost chezweb\\.mp") - "mpost --tex=tex chezweb.mp") - (("\\./chezweave" all) - (string-append "chez-scheme --program " all))) - (substitute* "installit" - (("-g \\$GROUP -o \\$OWNER") "")) - #t))))) + (list + #:make-flags + #~(list (string-append "PREFIX=" #$output) + (string-append "DOCDIR=" #$output "/share/doc/" + #$name "-" #$version) + ;; lib/chez-scheme/chezweb ??? + (string-append "LIBDIR=" #$output "/lib/chezweb") + (string-append "TEXDIR=" #$output "/share/texmf-local")) + #:tests? #f ; no tests + #:phases + #~(modify-phases %standard-phases + ;; This package has a custom "bootstrap" script that + ;; is meant to be run from the Makefile. + (delete 'bootstrap) + (replace 'configure + (lambda* _ + (copy-file "config.mk.template" "config.mk") + (substitute* "tangleit" + (("\\./cheztangle\\.ss" all) + (string-append "scheme --program " all))) + (substitute* "weaveit" + (("mpost chezweb\\.mp") + "mpost --tex=tex chezweb.mp") + (("\\./chezweave" all) + (string-append "scheme --program " all))) + (substitute* "installit" + (("-g \\$GROUP -o \\$OWNER") ""))))))) (home-page "https://github.com/arcfide/ChezWEB") (synopsis "Hygienic Literate Programming for Chez Scheme") (description "ChezWEB is a system for doing Knuthian style WEB @@ -144,95 +170,74 @@ (define-public chez-sockets (base32 "1n5fbwwz51fdzvjackgmnsgh363g9inyxv7kmzi0469cwavwcx5m")))) (build-system gnu-build-system) (native-inputs - `(("chez-scheme" ,chez-scheme) - ("chez-web" ,chez-web) - ("texlive" ,(texlive-updmap.cfg (list texlive-pdftex))))) + (list chez-scheme + chez-web + (texlive-updmap.cfg (list texlive-pdftex)))) (arguments - `(#:tests? #f ; no tests - #:phases - (modify-phases %standard-phases - (replace 'configure - (lambda* (#:key outputs inputs #:allow-other-keys) - (let* ((out (assoc-ref outputs "out")) - (chez-web (assoc-ref inputs "chez-web")) - (chez (assoc-ref inputs "chez-scheme")) - (chez-h (dirname (car (find-files chez "scheme\\.h"))))) - (substitute* "Makefile" - (("(SCHEMEH=).*$" all var) - (string-append var chez-h))) - #t))) - (add-before 'build 'tangle - (lambda* (#:key inputs #:allow-other-keys) - (setenv "TEXINPUTS" - (string-append - (getcwd) ":" - (assoc-ref inputs "chez-web") "/share/texmf-local/tex/generic:" - ":")) - ;; just using "make" tries to build the .c files before - ;; they are created. - (and (invoke "make" "sockets") - (invoke "make")))) - (replace 'build - (lambda* (#:key outputs inputs #:allow-other-keys) - (let* ((out (assoc-ref outputs "out")) - (chez-site (string-append out "/lib/csv" - ,(package-version chez-scheme) - "-site/arcfide"))) - ;; make sure Chez Scheme can find the shared libraries. - (substitute* "sockets.ss" - (("(load-shared-object) \"(socket-ffi-values\\.[sd][oy].*)\"" - all cmd so) - (string-append cmd " \"" chez-site "/" so "\"")) - (("sockets-stub\\.[sd][oy].*" all) - (string-append chez-site "/" all))) - ;; to compile chez-sockets, the .so files must be - ;; installed (because of the absolute path we - ;; inserted above). - (for-each (lambda (f d) (install-file f d)) - '("socket-ffi-values.so" "sockets-stub.so") - (list chez-site chez-site)) - (zero? (system "echo '(compile-file \"sockets.sls\")' | scheme -q"))))) - (replace 'install - (lambda* (#:key outputs inputs #:allow-other-keys) - (let* ((out (assoc-ref outputs "out")) - (lib (string-append out "/lib/chez-sockets")) - (doc (string-append out "/share/doc/" ,name "-" ,version)) - (chez-site (string-append out "/lib/csv" - ,(package-version chez-scheme) - "-site/arcfide"))) - (for-each (lambda (f d) (install-file f d)) - '("sockets.pdf" "sockets.so") - (list doc chez-site)) - #t)))))) + (list + #:tests? #f ; no tests + #:phases + #~(modify-phases %standard-phases + (replace 'configure + (lambda* (#:key native-inputs inputs #:allow-other-keys) + (let* ((scheme (search-input-file (or native-inputs inputs) + "/bin/scheme")) + (lib (string-append (dirname scheme) "/../lib")) + (header-file (car (find-files lib "scheme\\.h"))) + (include-dir (dirname header-file))) + (substitute* "Makefile" + (("(SCHEMEH=).*$" _ var) + (string-append var include-dir)))))) + (add-before 'build 'tangle + (lambda* (#:key inputs #:allow-other-keys) + (setenv "TEXINPUTS" + (string-append + (getcwd) ":" + (assoc-ref inputs "chez-web") + "/share/texmf-local/tex/generic:" + ":")) + ;; just using "make" tries to build the .c files before + ;; they are created. + (and (invoke "make" "sockets") + (invoke "make")))) + (replace 'build + (lambda args + (let ((chez-site (string-append #$output + "/lib/chez-scheme/arcfide"))) + ;; make sure Chez Scheme can find the shared libraries. + (substitute* "sockets.ss" + (("(object \")(socket-ffi-values\\.[sd][oy][^\"]*)(\")" + _ pre file post) + (string-append pre chez-site "/" file post)) + (("(\")(sockets-stub\\.[sd][oy][^\"]*)(\")" + _ pre file post) + (string-append pre chez-site "/" file post))) + ;; to compile chez-sockets, the .so files must be + ;; installed (because of the absolute path we + ;; inserted above). + (for-each (lambda (f) + (install-file f chez-site)) + '("socket-ffi-values.so" + "sockets-stub.so")) + (invoke "bash" + "-c" + (format #f "echo '~s' | scheme -q" + '(compile-file "sockets.sls")))))) + (replace 'install + (lambda args + (install-file "sockets.so" + (string-append #$output + "/lib/chez-scheme/arcfide")) + (install-file "sockets.pdf" + (string-append #$output + "/share/doc/" + #$name "-" #$version))))))) (home-page "https://github.com/arcfide/chez-sockets") (synopsis "Extensible sockets library for Chez Scheme") (description "Chez-sockets is an extensible sockets library for Chez Scheme.") (license expat)))) -;; Help function for Chez Scheme to add the current path to -;; CHEZSCHEMELIBDIRS. -(define chez-configure - '(lambda _ - (let ((chez-env (getenv "CHEZSCHEMELIBDIRS"))) - (setenv "CHEZSCHEMELIBDIRS" - (if chez-env - (string-append ".:" chez-env) - ".")) - #t))) - -;; Help function to define make flags for some Chez Scheme custom make -;; files. -(define (chez-make-flags name version) - `(let ((out (assoc-ref %outputs "out"))) - (list - ;; Set 'chezversion' so that libraries are installed in - ;; 'lib/csvX.Y.Z-site' like Chez's 'native-search-paths' expects. - (string-append "chezversion=" ,(package-version chez-scheme)) - (string-append "PREFIX=" out) - (string-append "DOCDIR=" out "/share/doc/" - ,name "-" ,version)))) - (define-public chez-matchable (package (name "chez-matchable") @@ -253,10 +258,11 @@ (define-public chez-matchable (native-inputs (list chez-scheme)) (arguments - `(#:make-flags ,(chez-make-flags name version) - #:test-target "test" - #:phases (modify-phases %standard-phases - (replace 'configure ,chez-configure)))) + (list #:make-flags (chez-make-flags name version) + #:test-target "test" + #:phases #~(modify-phases %standard-phases + (replace 'configure + #$chez-configure)))) (synopsis "Portable hygienic pattern matcher for Scheme") (description "This package provides a superset of the popular Scheme @code{match} package by Andrew Wright, written in fully portable @@ -284,10 +290,11 @@ (define-public chez-irregex (native-inputs (list chez-scheme)) (arguments - `(#:make-flags ,(chez-make-flags name version) - #:test-target "test" - #:phases (modify-phases %standard-phases - (replace 'configure ,chez-configure)))) + (list #:make-flags (chez-make-flags name version) + #:test-target "test" + #:phases #~(modify-phases %standard-phases + (replace 'configure + #$chez-configure)))) (home-page "https://github.com/fedeinthemix/chez-irregex") (synopsis "Portable regular expression library for Scheme") (description "This package provides a portable and efficient @@ -314,17 +321,18 @@ (define-public chez-fmt (native-inputs (list chez-scheme)) (arguments - `(#:make-flags ,(chez-make-flags name version) - #:test-target "chez-check" - #:phases - (modify-phases %standard-phases - (replace 'configure ,chez-configure) - (replace 'build - (lambda* (#:key (make-flags '()) #:allow-other-keys) - (apply invoke "make" "chez-build" make-flags))) - (replace 'install - (lambda* (#:key (make-flags '()) #:allow-other-keys) - (apply invoke "make" "chez-install" make-flags)))))) + (list #:make-flags (chez-make-flags name version) + #:test-target "chez-check" + #:phases + #~(modify-phases %standard-phases + (replace 'configure + #$chez-configure) + (replace 'build + (lambda* (#:key (make-flags '()) #:allow-other-keys) + (apply invoke "make" "chez-build" make-flags))) + (replace 'install + (lambda* (#:key (make-flags '()) #:allow-other-keys) + (apply invoke "make" "chez-install" make-flags)))))) (home-page "http://synthcode.com/scheme/fmt") (synopsis "Combinator formatting library for Chez Scheme") (description "This package provides a library of procedures for @@ -354,10 +362,11 @@ (define-public chez-mit (native-inputs (list chez-scheme)) (arguments - `(#:make-flags ,(chez-make-flags name version) - #:test-target "test" - #:phases (modify-phases %standard-phases - (replace 'configure ,chez-configure)))) + (list #:make-flags (chez-make-flags name version) + #:test-target "test" + #:phases #~(modify-phases %standard-phases + (replace 'configure + #$chez-configure)))) (synopsis "MIT/GNU Scheme compatibility library for Chez Scheme") (description "This package provides a set of MIT/GNU Scheme compatibility libraries for Chez Scheme. The main goal was to provide the functionality @@ -386,46 +395,44 @@ (define-public chez-scmutils (propagated-inputs (list chez-mit chez-srfi)) (arguments - `(#:make-flags ,(chez-make-flags name version) - #:tests? #f ; no test suite - #:phases - (modify-phases %standard-phases - (replace 'configure ,chez-configure) - ;; Since the documentation is lacking, we install the source - ;; code. For things to work correctly we have to replace - ;; relative paths by absolute ones in 'include' forms. This - ;; in turn requires us to compile the files in the final - ;; destination. - (delete 'build) - (add-after 'install 'install-src - (lambda* (#:key (make-flags '()) #:allow-other-keys) - (apply invoke "make" "install-src" make-flags))) - (add-after 'install-src 'absolute-path-in-scm-files - (lambda* (#:key outputs #:allow-other-keys) - (let ((out (assoc-ref outputs "out"))) - (for-each (lambda (file) - (substitute* file - (("include +\"\\./scmutils") - (string-append "include \"" (dirname file))))) - (find-files out "\\.sls")) - (for-each (lambda (file) - (substitute* file - (("include +\"\\./scmutils/simplify") - (string-append "include \"" (dirname file))))) - (find-files out "fbe-syntax\\.scm")) - #t))) + (list + #:make-flags (chez-make-flags name version) + #:tests? #f ; no test suite + #:phases + #~(modify-phases %standard-phases + (replace 'configure + #$chez-configure) + ;; Since the documentation is lacking, we install the source + ;; code. For things to work correctly we have to replace + ;; relative paths by absolute ones in 'include' forms. This + ;; in turn requires us to compile the files in the final + ;; destination. + (delete 'build) + (add-after 'install 'install-src + (lambda* (#:key (make-flags '()) #:allow-other-keys) + (apply invoke "make" "install-src" make-flags))) + (add-after 'install-src 'absolute-path-in-scm-files + (lambda* (#:key #:allow-other-keys) + (for-each (lambda (file) + (substitute* file + (("include +\"\\./scmutils") + (string-append "include \"" (dirname file))))) + (find-files #$output "\\.sls")) + (for-each (lambda (file) + (substitute* file + (("include +\"\\./scmutils/simplify") + (string-append "include \"" (dirname file))))) + (find-files #$output "fbe-syntax\\.scm")))) (add-after 'absolute-path-in-scm-files 'build - (lambda* (#:key outputs (make-flags '()) #:allow-other-keys) - (let* ((out (assoc-ref outputs "out")) - (mk-file (car (find-files out "Makefile")))) + (lambda* (#:key (make-flags '()) #:allow-other-keys) + (let ((mk-file (car (find-files #$output "Makefile")))) (with-directory-excursion (dirname mk-file) (apply invoke "make" "build" make-flags))))) (add-after 'build 'clean-up - (lambda* (#:key outputs #:allow-other-keys) - (let* ((out (assoc-ref outputs "out"))) - (for-each delete-file - (find-files out "Makefile|compile-all\\.ss")) - #t)))))) + (lambda args + (for-each delete-file + (find-files #$output + "Makefile|compile-all\\.ss"))))))) (synopsis "Port of MIT/GNU Scheme Scmutils to Chez Scheme") (description "This package provides a port of the MIT/GNU Scheme Scmutils program to Chez Scheme. The port consists of a set of From patchwork Sun Feb 13 21:51:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37227 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id A61DA27BBE9; Sun, 13 Feb 2022 21:54:59 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 6D25827BBE9 for ; Sun, 13 Feb 2022 21:54:59 +0000 (GMT) Received: from localhost ([::1]:56958 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpe-0005cb-Cz for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:54:58 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43406) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMol-0005bs-I8 for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45181) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMol-0001tg-9G for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMol-0003Dt-91 for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 03/11] gnu: chez-scheme: Use shared zlib and lz4. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478918712208 (code B ref 53878); Sun, 13 Feb 2022 21:54:03 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:07 +0000 Received: from localhost ([127.0.0.1]:39055 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnq-0003Ak-Qa for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:07 -0500 Received: from mail-qt1-f176.google.com ([209.85.160.176]:38644) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnk-00039f-Ey for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:00 -0500 Received: by mail-qt1-f176.google.com with SMTP id r14so14012645qtt.5 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=NrUrTgUVsw38qpTKfIYl2vJbliIV3wXNuKimJY8k5Sc=; b=knl7LDfUD7f9wj7gODsWLpZQ7+iZL4ctHsMUkk99xXnZ5XJqCFbxn3Mmelx+XqB383 Y7fVpO3Dt6yY7FH492mfS95sqvd1YLYbR7YGSmDmqi7W4NZbtuRyod8V2bq767v+1mEC +h4aG7yBW4Q9MpULg2uZs4gKQ2ny3X5n4H1N0x2Il+h/dvms7zjZcPx+sEitbnwQGQF4 ZCJmR1RPeijb0fr6Zde4+2TMtrnbsWA48HwqIw7HhErimIy8sv+MKOIOXvW9dEZIb12z +qaa24hvU2c/4Hdfva2uQWaDQGdpGo0DG5CI0RYBxNUi4iRtug2nr9ahlIYJ9OngflvD crYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NrUrTgUVsw38qpTKfIYl2vJbliIV3wXNuKimJY8k5Sc=; b=fOOLG8pmsN7CWDnBrMikJSOIcoYavyB/t/5OEGrOvN+tNlwOmfojEE93dVmZ93rCFR p6SMt7QCLKgZ1fUwar0244eoom+zvOk0CL8b43DasOPzUyoVzSH3DrFlZ3Ua28KMp72x EGXVFSsuV3A6W0IDST758296dntDQLWjdhMk4Lf838vhaRMFJvvriFHXeQDDtlC3UPZ5 dZzvXNCkSvYyNX1moKz0zZDmxB7wWIGfxN1i4rqJde0ZkK2u2CTQO05wPri7LTyF4Bxw 3OlSj87RYgs23BKfGuYDpBy7qu3l/+uyN/OnPKWSwQQ6QXh7zW2BNLA+NLSsofBZhDCn xfig== X-Gm-Message-State: AOAM5325BUP7KtbRQmbRaguwqQurf9LOd1KH80biAtZV8yHmu4GiMECg UkA3mbo5Jt7s/7auy3xSXFNJrF8Pyy9b3gcIS1k= X-Google-Smtp-Source: ABdhPJzH0A7gjSpVyoeO3q/Qbwvmf22OGZK11UeuY2NARSQva05aq2GVFemjS0fPwckgmtKrIMW13A== X-Received: by 2002:a05:622a:4cc:: with SMTP id q12mr7798291qtx.561.1644789174806; Sun, 13 Feb 2022 13:52:54 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id p10sm15537738qtx.62.2022.02.13.13.52.54 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:52:54 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:19 -0500 Message-Id: <20220213215127.218952-4-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches This change also involves building 'libkernel.a' instead of 'kernel.o'. Support for these build options was merged upstream in 2019: see discussion at . * gnu/packages/chez-and-racket-bootstrap (chez-scheme)[inputs]: Remove 'zlib:static' and 'lz4:static'. [arguments]: Adjust configure phase accordingly. --- gnu/packages/chez-and-racket-bootstrap.scm | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index 1ed4631ced..11d570059b 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -114,9 +114,7 @@ (define-public chez-scheme (inputs `(("libuuid" ,util-linux "lib") ("zlib" ,zlib) - ("zlib:static" ,zlib "static") ("lz4" ,lz4) - ("lz4:static" ,lz4 "static") ;; for expeditor: ("ncurses" ,ncurses) ;; for X11 clipboard support in expeditor: @@ -169,14 +167,14 @@ (define src (lz4-static (assoc-ref inputs "lz4:static")) (out (assoc-ref outputs "out")) ;; add flags which are always required: - (flags (cons* - (string-append "--installprefix=" out) - (string-append "ZLIB=" zlib-static "/lib/libz.a") - (string-append "LZ4=" lz4-static "/lib/liblz4.a") - ;; Guix will do compress man pages, - ;; and letting Chez try causes an error - "--nogzip-man-pages" - configure-flags))) + (flags (cons* (string-append "--installprefix=" out) + "ZLIB=-lz" + "LZ4=-llz4" + "--libkernel" + ;; Guix will do compress-man-pages, + ;; and letting Chez try causes an error + "--nogzip-man-pages" + configure-flags))) (format #t "configure flags: ~s~%" flags) ;; Some makefiles (for tests) don't seem to propagate CC ;; properly, so we take it out of their hands: From patchwork Sun Feb 13 21:51:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37229 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 9A72927BBEA; Sun, 13 Feb 2022 21:55:01 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id BCEAB27BBE9 for ; Sun, 13 Feb 2022 21:55:00 +0000 (GMT) Received: from localhost ([::1]:57012 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpf-0005fN-Sv for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:54:59 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43412) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMol-0005c4-UP for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45182) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMol-0001tn-LQ for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMol-0003E0-LZ for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:03 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 04/11] gnu: chez-and-racket-bootstrap: Add utilities for Chez machine types. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478919012219 (code B ref 53878); Sun, 13 Feb 2022 21:54:03 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:10 +0000 Received: from localhost ([127.0.0.1]:39058 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnt-0003B0-4i for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:09 -0500 Received: from mail-qk1-f177.google.com ([209.85.222.177]:33342) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMno-00039u-Ko for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:05 -0500 Received: by mail-qk1-f177.google.com with SMTP id o10so13044635qkg.0 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Lox4biAAsxxoQq6Fxhf7L0m7IO8uJocQ7vmE7rh9eMo=; b=QSu4qpMq8pjrATd5vBunqgkFvoB6jFyUtXzY9a50hwT6KhueTe5sAuJM0dPyUHQqaK 9b8xFhBO84LqteCTOAK5Jr7En0bOn1ihTHb2n0PSGahBTOkO61/cYkpyq0QsTboBVwYh m8uGTaS57wDZJ+I/ZrEHYnCGoiUbVgshaR+PXrehYmC7HoWjFTcp8+wCNulaaXN1ivoY eH2HWp29Z6qMy+qiSXG8NvHxzL4exY5UIWhNih8Hl8uNETBdwz8iT8jyRNjUXtQbHxL/ E2m5jFNKXYnX5ixCnNo00qMg3dOqfez5pXWR1tIVrvrLjPrx+woftnBsKu1wIqcyW/W8 Rf0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Lox4biAAsxxoQq6Fxhf7L0m7IO8uJocQ7vmE7rh9eMo=; b=uvkU1d54ZdmexbTbeJEm7uL3trE5FX8L64WBxTIFdJkH8l3Dy3zR9AMVy8qoLPaWwW 3+8rUwUCSmdE1geNiIKXZBUzbAXZ8sqz1DATNHRcpKIKwnDnI70ht+WNWfTIHb6SMggi YUZKvbn2TTGIUQs1V8Iy8+vRwsjxZhYhWR0/N/mVwCYePeaRYNzYe3uR2mqOxF5FEzrg 3N9fcVZgCk0t1hToZJVLcIcvKLvNDHRLV9ok1jpUdFZBuoZT4Tnw/4SpBTQOLSz6KMkl +o8zcBxfKw4ZKUZNYz+r7kbwVODxVlaiXPruhOpTYjvtz34z6NNPd3c/OGxEtrct+zvM B/NQ== X-Gm-Message-State: AOAM531qVj663zYYrx5Ls+Vph80CBXSPBzlFzaAC4yZc2NEK60Mp1e+D BiYHpbTu4EhGhZ8jOy6hPQGxJdylwEuPX0jjK3A= X-Google-Smtp-Source: ABdhPJxVs7Xpyad4UMkgLrm5MjktsXpKWBxoYu7ZhaMxsWmEJJVRI7cN0K1jZyEy5egCE09R30TP6g== X-Received: by 2002:a05:620a:25cc:: with SMTP id y12mr5773709qko.94.1644789178891; Sun, 13 Feb 2022 13:52:58 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id s34sm16669359qtc.88.2022.02.13.13.52.58 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:52:58 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:20 -0500 Message-Id: <20220213215127.218952-5-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/packages/chez-and-racket-bootstrap.scm (chez-machine->unthreaded, chez-machine->upstream-restriction, chez-machine->nix-system, nix-system->chez-machine): New private functions. (%nix-arch-to-chez-alist, %nix-os-to-chez-alist): New private constants. (chez-scheme)[supported-systems]: Compute based on 'nix-system->chez-machine' and 'chez-machine->upstream-restriction'. --- gnu/packages/chez-and-racket-bootstrap.scm | 142 ++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index 11d570059b..fc1da53178 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -28,7 +28,9 @@ (define-module (gnu packages chez-and-racket-bootstrap) #:use-module (guix utils) #:use-module (guix gexp) #:use-module (ice-9 match) + #:use-module (ice-9 regex) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:use-module (guix build-system gnu) #:use-module (gnu packages) #:use-module (gnu packages compression) @@ -61,6 +63,134 @@ (define-module (gnu packages chez-and-racket-bootstrap) ;; ;; Code: +(define (chez-machine->unthreaded mach) + "Given a string MACH naming a Chez Scheme machine type, returns a string +naming the unthreaded machine type for the same architecture and OS as MACH. +The returned string may share storage with MACH." + (if (eqv? #\t (string-ref mach 0)) + (substring mach 1) + mach)) +(define (chez-machine->threaded mach) + "Like @code{chez-machine->unthreaded}, but returns the threaded machine +type." + (if (eqv? #\t (string-ref mach 0)) + mach + (string-append "t" mach))) + +;; Based on the implementation from raco-cross-lib/private/cross/platform.rkt +;; in https://github.com/racket/raco-cross. +;; For supported platforms, refer to release_notes/release_notes.stex in the +;; upstream Chez Scheme repository or to racket/src/ChezScheme/README.md +;; in https://github.com/racket/racket. +(define %nix-arch-to-chez-alist + `(("x86_64" . "a6") + ("i386" . "i3") + ("aarch64" . "arm64") + ("armhf" . "arm32") ;; Chez supports ARM v6+ + ("ppc" . "ppc32"))) +(define %nix-os-to-chez-alist + `(("w64-mingw32" . "nt") + ("darwin" . "osx") + ("linux" . "le") + ("freebsd" . "fb") + ("openbsd" . "ob") + ("netbsd" . "nb") + ("solaris" . "s2"))) + +(define (chez-machine->upstream-restriction mach) + "Given a string MACH naming a Chez Scheme machine type, returns a symbol +naming a restriction on the upstream Chez Scheme implementation compared to +the Racket variant, or @code{#f} if no such restriction exists. The +restriction is reported for the architecture--OS pair, regardless of whether +MACH specifies a threaded or an unthreaded variant. + +Possible restrictions currently include: +@itemize @bullet +@item +@code{'no-threads}: Support for native threads is not available upstream. +@item +@code{'no-support}: The upstream release doesn't claim to support this +architecture--OS combination at all. +@end itemize + +See @code{chez-machine->nix-system} for more details about acceptable values +for MACH." + (let ((mach (chez-machine->unthreaded mach))) + (cond + ((string-prefix? "arm64" mach) + 'no-support) + ((string-prefix? "arm32" mach) + (if (string-suffix? "le" mach) + 'no-threads + 'no-support)) + ((string-prefix? "ppc32" mach) + (if (string-suffix? "le" mach) + #f + 'no-support)) + (else + #f)))) + +(define (chez-machine->nix-system mach) + "Return the Nix system type corresponding to the Chez Scheme machine type +MACH. If MACH is not a string representing a known machine type, an exception +is raised. This function does not distinguish between threaded and unthreaded +variants of MACH. + +Note that this function only handles Chez Scheme machine types in the +strictest sense, not other kinds of descriptors sometimes used in place of a +Chez Scheme machine type by the Racket, such as @code{\"pb\"}, @code{#f}, or +@code{\"racket\"}. (When using such extensions, the Chez Scheme machine type +for the host system is often still relevant.)" + (let ((mach (chez-machine->unthreaded mach))) + (let find-arch ((alist %nix-arch-to-chez-alist)) + (match alist + (((nix . chez) . alist) + (if (string-prefix? chez mach) + (string-append + nix "-" (let ((mach-os (substring mach (string-length chez)))) + (let find-os ((alist %nix-os-to-chez-alist)) + (match alist + (((nix . chez) . alist) + (if (equal? chez mach-os) + nix + (find-os alist))))))) + (find-arch alist))))))) + +(define* (nix-system->chez-machine #:optional (system (%current-system)) + #:key (threads? 'always)) + "Return the Chez Scheme machine type corresponding to the Nix system +identifier SYSTEM, or @code{#f} if the translation of SYSTEM to a Chez Scheme +machine type is undefined. + +When THREADS? is @code{'always} (the default), the threaded variant of the +machine type will be returned: note that the package returned by +@code{chez-scheme-for-system} will always support native threads. When +THREADS? is @code{#f}, the unthreaded machine type will be returned. If +THREADS? is @code{'upstream} (the default), the threaded variant of the +machine type will be returned if and only if it is supported by upstream Chez +Scheme (see @code{chez-machine->upstream-restriction}). If THREADS? is any +other value, an exception is raised." + (let* ((hyphen (string-index system #\-)) + (nix-arch (substring system 0 hyphen)) + (nix-os (substring system (+ 1 hyphen))) + (chez-arch (assoc-ref %nix-arch-to-chez-alist nix-arch)) + (chez-os (assoc-ref %nix-os-to-chez-alist nix-os)) + (mach (and chez-arch chez-os (string-append chez-arch chez-os)))) + (and mach + (match threads? + ('always + (chez-machine->threaded mach)) + (#f + mach) + ('upstream + (if (chez-machine->upstream-restriction mach) + mach + (chez-machine->threaded mach))))))) + +;; +;; Chez Scheme: +;; + (define nanopass (let ((version "1.9.2")) (origin @@ -264,8 +394,16 @@ (define* (stex-make #:optional (suffix "")) ;; We should too. It is the Chez machine type arm32le ;; (no threaded version upstream yet, though there is in ;; Racket's fork), more specifically (per the release notes) ARMv6. - (supported-systems (fold delete %supported-systems - '("mips64el-linux" "armhf-linux"))) + (supported-systems + (delete + "armhf-linux" ;; <-- should work, but reportedly broken + (filter + (lambda (system) + (and=> (nix-system->chez-machine system) + (lambda (mach) + (not (eq? 'no-support + (chez-machine->upstream-restriction mach)))))) + %supported-systems))) (home-page "https://cisco.github.io/ChezScheme/") (synopsis "R6RS Scheme compiler and run-time") (description From patchwork Sun Feb 13 21:51:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37234 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 2952227BBED; Sun, 13 Feb 2022 21:55:24 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 0681F27BBEB for ; Sun, 13 Feb 2022 21:55:20 +0000 (GMT) Received: from localhost ([::1]:58486 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpz-0006i2-6x for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:19 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43416) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMom-0005cD-At for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45183) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMom-0001u7-1i for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMom-0003E8-1W for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 05/11] gnu: Add stex. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478919412245 (code B ref 53878); Sun, 13 Feb 2022 21:54:03 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:14 +0000 Received: from localhost ([127.0.0.1]:39061 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnx-0003BN-VI for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:14 -0500 Received: from mail-qk1-f179.google.com ([209.85.222.179]:40878) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMns-0003AZ-RX for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:09 -0500 Received: by mail-qk1-f179.google.com with SMTP id o25so12986185qkj.7 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=71aWypGkxk0T9T1BAj0BYQ2KTsp07bosxnaKq0p+hog=; b=FmkwmFHjb9/ItUavp/6pXLxNhNJ7YHpABPAUwaDllvtF0wUnmMPV3+wz1bnd5/tQpv 5yd0jxSekqAvbZrAt6BVnig8dxYUU+aqw/iFFIUNKhTzuiEfZY3pwV5zDl6c28WUh7In 9D97hv9tV9e7P4mzK6hfV+A/tfEObqf4uztn1BJt06yogqUZPRZu9rGQTh061ZplCfY8 Gm5+XMnbZEwdTB9EcKexI29SD2OPp01zHsgzFeOTB2du0q2iXAdN1iA+dJYas5n1kVuJ zTTxvDZFeScvMMrROGV7qZzbKJi0RMYcbl8WlFaKn/cC0JL6UyQQdM0bjjD/APJi8GtU 7aew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=71aWypGkxk0T9T1BAj0BYQ2KTsp07bosxnaKq0p+hog=; b=INhhD4UuBZBXwVx9Lvp/qCH2Arr3v8Jv9Ge6PBVGbRZoI4YuG1+oRTyi5AKdU3abs/ PGFJFw6SEURrHe7B/8Qu8YmG0VxZa4anIovfc9m+EsyqDjbxQBXDBJh4GxpCdaGIYeIt IiMfcxgk5s3LUzyFyrA1xfQhwQoCf98BAvTVqqUvBR5qzxK9Dgzxf7HoWajyn5toHi+G jmWP+++93zgX/KtUnWNke3F8j1s9BmP1mvCCsjF94D9ZQohj341cDpMyOHl0wR08j6/L QFm40I/nH1JQ3U3rn33hDgAM8sxa33T4erfxPhuvwurHvYTpWbQ9jmt9tmu+J9vszotd djBw== X-Gm-Message-State: AOAM533qimLWMWWqYVqUZAd0YeI55p1neKW9BLTChUyrZFPGXKWqPupG dNyqEyeoUiAqd5zsmjHESXuFF6li8rYNuC4Lwos= X-Google-Smtp-Source: ABdhPJy1UQREFy4PX8SDHgi2jqgMeR3mAabO/B6xLC7rzh4pcnGUwqp3XxMRB5EJgQh3WulhGilwlw== X-Received: by 2002:a05:620a:12e7:: with SMTP id f7mr5634393qkl.612.1644789183039; Sun, 13 Feb 2022 13:53:03 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id u21sm16311470qtw.80.2022.02.13.13.53.02 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:53:02 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:21 -0500 Message-Id: <20220213215127.218952-6-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/packages/chez-and-racket-bootstrap.scm (stex-bootstrap): New variable. (stex): Change from origin to package inheriting from 'stex-bootstrap'. (chez-scheme)[native-inputs]: Add 'stex-bootstrap'. Remove labels. Remove dependencies of stex-bootstrap. [inputs]: Remove labels. [arguments]: Adapt to use 'stex-bootstrap', 'search-input-file', and G-expressions. (nanopass): Make it public as a temporary workaround for Racket. * gnu/packages/racket.scm (racket-bootstrap-chez-bootfiles)[native-inputs]: Update accordingly. --- gnu/packages/chez-and-racket-bootstrap.scm | 430 ++++++++++++--------- gnu/packages/racket.scm | 5 +- 2 files changed, 258 insertions(+), 177 deletions(-) diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index fc1da53178..945d1ce2ed 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -31,6 +31,7 @@ (define-module (gnu packages chez-and-racket-bootstrap) #:use-module (ice-9 regex) #:use-module (srfi srfi-1) #:use-module (srfi srfi-26) + #:use-module (guix build-system copy) #:use-module (guix build-system gnu) #:use-module (gnu packages) #:use-module (gnu packages compression) @@ -191,113 +192,83 @@ (define* (nix-system->chez-machine #:optional (system (%current-system)) ;; Chez Scheme: ;; -(define nanopass - (let ((version "1.9.2")) - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/nanopass/nanopass-framework-scheme") - (commit (string-append "v" version)))) - (sha256 (base32 "16vjsik9rrzbabbhbxbaha51ppi3f9n8rk59pc6zdyffs0vziy4i")) - (file-name (git-file-name "nanopass" version))))) +(define unbundle-chez-submodules + #~(begin + (use-modules (guix build utils)) + (for-each (lambda (dir) + (when (directory-exists? dir) + (delete-file-recursively dir))) + '("stex" + "nanopass" + "lz4" + "zlib")))) -(define stex - ;; This commit includes a fix, which we would otherwise want to use as - ;; patch. Let's revert to tagged releases as soon as one becomes available. - (let* ((commit "54051494434a197772bf6ca5b4e6cf6be55f39a5") - (version "1.2.2") - (version (git-version version "1" commit))) - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/dybvig/stex") - (commit commit))) - (sha256 (base32 "01jnvw8qw33gnpzwrakwhsr05h6b609lm180jnspcrb7lds2p23d")) - (file-name (git-file-name "stex" version))))) +(define (unpack-nanopass+stex) + ;; delayed resolution of `nanopass` + #~(begin + (copy-recursively #$nanopass + "nanopass" + #:keep-mtime? #t) + (mkdir-p "stex") + (with-output-to-file "stex/Mf-stex" + (lambda () + ;; otherwise, it will try to download submodules + (display "# to placate ../configure"))))) (define-public chez-scheme (package (name "chez-scheme") + ;; The version should match `(scheme-version-number)`. + ;; See s/cmacros.ss c. line 360. (version "9.5.6") - (source - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/cisco/ChezScheme") - (commit (string-append "v" version)))) - (sha256 - (base32 "07s433hn1z2slfc026sidrpzxv3a8narcd40qqr1xrpb9012xdky")) - (file-name (git-file-name name version)) - (snippet - ;; Remove bundled libraries. - (with-imported-modules '((guix build utils)) - #~(begin - (use-modules (guix build utils)) - (for-each (lambda (dir) - (when (directory-exists? dir) - (delete-file-recursively dir))) - '("stex" - "nanopass" - "lz4" - "zlib"))))))) + (source (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/cisco/ChezScheme") + (commit (string-append "v" version)))) + (sha256 + (base32 + "07s433hn1z2slfc026sidrpzxv3a8narcd40qqr1xrpb9012xdky")) + (file-name (git-file-name name version)) + (snippet unbundle-chez-submodules))) (build-system gnu-build-system) (inputs - `(("libuuid" ,util-linux "lib") - ("zlib" ,zlib) - ("lz4" ,lz4) - ;; for expeditor: - ("ncurses" ,ncurses) - ;; for X11 clipboard support in expeditor: - ;; https://github.com/cisco/ChezScheme/issues/9#issuecomment-222057232 - ("libx11" ,libx11))) - (native-inputs - `(("nanopass" ,nanopass) ; source only - ;; for docs - ("stex" ,stex) - ("xorg-rgb" ,xorg-rgb) - ("texlive" ,(texlive-updmap.cfg (list texlive-dvips-l3backend - texlive-epsf - texlive-fonts-ec - texlive-oberdiek))) - ("ghostscript" ,ghostscript) - ("netpbm" ,netpbm))) + (list + `(,util-linux "lib") ;<-- libuuid + zlib + lz4 + ncurses ;<-- for expeditor + ;; for X11 clipboard support in expeditor: + ;; https://github.com/cisco/ChezScheme/issues/9#issuecomment-222057232 + libx11)) + (native-inputs (list stex-bootstrap)) (native-search-paths (list (search-path-specification (variable "CHEZSCHEMELIBDIRS") (files (list (string-append "lib/chez-scheme")))))) (outputs '("out" "doc")) (arguments - `(#:modules - ((guix build gnu-build-system) + (list + #:modules + '((guix build gnu-build-system) (guix build utils) (ice-9 ftw) (ice-9 match)) - #:test-target "test" - #:configure-flags - '("--threads") ;; TODO when we fix armhf, it doesn't support --threads - #:phases - (modify-phases %standard-phases - ;; put these where configure expects them to be - (add-after 'unpack 'unpack-nanopass+stex - (lambda* (#:key native-inputs inputs #:allow-other-keys) - (for-each (lambda (dep) - (define src - (assoc-ref (or native-inputs inputs) dep)) - (copy-recursively src dep - #:keep-mtime? #t)) - '("nanopass" "stex")))) - ;; NOTE: the custom Chez 'configure' script doesn't allow - ;; unrecognized flags, such as those automatically added - ;; by `gnu-build-system`. - (replace 'configure - (lambda* (#:key inputs outputs - (configure-flags '()) - #:allow-other-keys) - (let* ((zlib-static (assoc-ref inputs "zlib:static")) - (lz4-static (assoc-ref inputs "lz4:static")) - (out (assoc-ref outputs "out")) - ;; add flags which are always required: - (flags (cons* (string-append "--installprefix=" out) + #:test-target "test" + ;; TODO when we fix armhf, it may not support --threads + #:configure-flags #~'("--threads") + #:phases + #~(modify-phases %standard-phases + (add-after 'unpack 'unpack-nanopass+stex + (lambda args + #$(unpack-nanopass+stex))) + ;; NOTE: the custom Chez 'configure' script doesn't allow + ;; unrecognized flags, such as those automatically added + ;; by `gnu-build-system`. + (replace 'configure + (lambda* (#:key inputs (configure-flags '()) #:allow-other-keys) + ;; add flags which are always required: + (let ((flags (cons* (string-append "--installprefix=" #$output) "ZLIB=-lz" "LZ4=-llz4" "--libkernel" @@ -305,90 +276,59 @@ (define src ;; and letting Chez try causes an error "--nogzip-man-pages" configure-flags))) - (format #t "configure flags: ~s~%" flags) - ;; Some makefiles (for tests) don't seem to propagate CC - ;; properly, so we take it out of their hands: - (setenv "CC" ,(cc-for-target)) - (setenv "HOME" "/tmp") - (apply invoke - "./configure" - flags)))) - ;; The binary file name is called "scheme" as is the one from MIT/GNU - ;; Scheme. We add a symlink to use in case both are installed. - (add-after 'install 'install-symlink - (lambda* (#:key outputs #:allow-other-keys) - (let* ((out (assoc-ref outputs "out")) - (bin (string-append out "/bin")) - (lib (string-append out "/lib")) - (name "chez-scheme")) - (symlink (string-append bin "/scheme") - (string-append bin "/" name)) - (map (lambda (file) - (symlink file (string-append (dirname file) - "/" name ".boot"))) - (find-files lib "scheme.boot"))))) - ;; Building explicitly lets us avoid using substitute* - ;; to re-write makefiles. - (add-after 'install-symlink 'prepare-stex - (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) - (let* ((stex+version - (strip-store-file-name - (assoc-ref (or native-inputs inputs) "stex"))) - ;; Eventually we want to install stex as a real - ;; package so it's reusable. For now: - (stex-output "/tmp") - (doc-dir (string-append stex-output - "/share/doc/" - stex+version))) - (with-directory-excursion "stex" - (invoke "make" - "install" - (string-append "LIB=" - stex-output - "/lib/" - stex+version) - (string-append "Scheme=" - (assoc-ref outputs "out") - "/bin/scheme")) - (for-each (lambda (pth) - (install-file pth doc-dir)) - '("ReadMe" ; includes the license - "doc/stex.html" - "doc/stex.css" - "doc/stex.pdf")))))) - ;; Building the documentation requires stex and a running scheme. - ;; FIXME: this is probably wrong for cross-compilation - (add-after 'prepare-stex 'install-doc - (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) - (let* ((chez+version (strip-store-file-name - (assoc-ref outputs "out"))) - (stex+version - (strip-store-file-name - (assoc-ref (or native-inputs inputs) "stex"))) - (scheme (string-append (assoc-ref outputs "out") - "/bin/scheme")) - ;; see note on stex-output in phase build-stex, above: - (stexlib (string-append "/tmp" - "/lib/" - stex+version)) - (doc-dir (string-append (assoc-ref outputs "doc") - "/share/doc/" - chez+version))) - (define* (stex-make #:optional (suffix "")) - (invoke "make" - "install" - (string-append "Scheme=" scheme) - (string-append "STEXLIB=" stexlib) - (string-append "installdir=" doc-dir suffix))) - (with-directory-excursion "csug" - (stex-make "/csug")) - (with-directory-excursion "release_notes" - (stex-make "/release_notes")) - (with-directory-excursion doc-dir - (symlink "release_notes/release_notes.pdf" - "release_notes.pdf") - (symlink "csug/csug9_5.pdf" - "csug.pdf")))))))) + (format #t "configure flags: ~s~%" flags) + ;; Some makefiles (for tests) don't seem to propagate CC + ;; properly, so we take it out of their hands: + (setenv "CC" #$(cc-for-target)) + (setenv "HOME" "/tmp") + (apply invoke "./configure" flags)))) + ;; The binary file name is called "scheme" as is the one from + ;; MIT/GNU Scheme. We add a symlink to use in case both are + ;; installed. + (add-after 'install 'install-symlink + (lambda* (#:key outputs #:allow-other-keys) + (let* ((scheme (search-input-file outputs "/bin/scheme")) + (bin-dir (dirname scheme))) + (symlink scheme + (string-append bin-dir "/chez-scheme")) + (match (find-files (string-append bin-dir "/../lib") + "scheme.boot") + ((scheme.boot) + (symlink scheme.boot + (string-append (dirname scheme.boot) + "/chez-scheme.boot"))))))) + ;; Building the documentation requires stex and a running scheme. + ;; FIXME: this is probably wrong for cross-compilation + (add-after 'install-symlink 'install-doc + (lambda* (#:key native-inputs inputs outputs + #:allow-other-keys) + (match (assoc-ref outputs "doc") + (#f + (format #t "not installing docs~%")) + (doc-prefix + (let* ((chez+version (strip-store-file-name #$output)) + (scheme (search-input-file outputs "/bin/scheme")) + (stexlib (search-input-directory + (or native-inputs inputs) + "/lib/stex")) + (doc-dir (string-append doc-prefix + "/share/doc/" + chez+version))) + (define* (stex-make #:optional (suffix "")) + (invoke "make" "install" + (string-append "Scheme=" scheme) + (string-append "STEXLIB=" stexlib) + (string-append "installdir=" + doc-dir suffix))) + (with-directory-excursion "csug" + (stex-make "/csug")) + (with-directory-excursion "release_notes" + (stex-make "/release_notes")) + (with-directory-excursion doc-dir + (symlink "release_notes/release_notes.pdf" + "release_notes.pdf") + (symlink "csug/csug9_5.pdf" + "csug.pdf")))))))))) ;; Chez Scheme does not have a MIPS backend. ;; FIXME: Debian backports patches to get armhf working. ;; We should too. It is the Chez machine type arm32le @@ -412,3 +352,145 @@ (define* (stex-make #:optional (suffix "")) generates native code for each target processor, with support for x86, x86_64, and 32-bit PowerPC architectures.") (license license:asl2.0))) + +;; +;; Chez's bootstrap dependencies: +;; + +(define-public stex-bootstrap + ;; This commit includes a fix which we would otherwise want to use as + ;; patch. Let's revert to tagged releases as soon as one becomes available. + (let ((commit "54051494434a197772bf6ca5b4e6cf6be55f39a5") + (revision "1")) + (hidden-package + (package + (name "stex") + ;; ^ Debian calls this "stex", not "chez-stex". It is a set of + ;; command-line tools, and there isn't a Scheme API, let alone a + ;; Chez-specific one, except perhaps that the Scheme examples are + ;; assumed to be Chez-compatible. + (version (git-version "1.2.2" revision commit)) + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/dybvig/stex") + (commit commit))) + (sha256 + (base32 "01jnvw8qw33gnpzwrakwhsr05h6b609lm180jnspcrb7lds2p23d")) + (file-name (git-file-name name version)) + (snippet + #~(for-each delete-file + '("sbin/install" "doc/stex.pdf" "doc/stex.html"))))) + (outputs '("out")) + (build-system copy-build-system) + ;; N.B. Upstream does not seem to support cross-compilation, + ;; though it would probably be easy to add. + (propagated-inputs + (list xorg-rgb + (texlive-updmap.cfg + (list texlive-dvips-l3backend + texlive-hyperref + texlive-bibtex + texlive-epsf + texlive-fonts-ec + texlive-oberdiek)) + ghostscript + netpbm)) + ;; Debian uses a versionless path for STEXLIB, + ;; which is much more convienient. + (arguments + (list + #:install-plan #~`(("inputs" "lib/stex/") + ("gifs" "lib/stex/") + ("math" "lib/stex/") + ("src" "lib/stex/") ;; can run without compiling + ("Mf-stex" "lib/stex/") + ("Makefile.template" "lib/stex/")) + #:phases + #~(modify-phases %standard-phases + (add-before 'install 'patch-sources + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (define scheme + (false-if-exception + (search-input-file inputs "/bin/scheme"))) + (when scheme + (setenv "Scheme" scheme)) + (substitute* '("Makefile.template" + "doc/Makefile") + (("STEXLIB=[^\n]*") + (string-append "STEXLIB=" #$output "/lib/stex")) + (("Scheme=[^\n]*") + (string-append "Scheme=" (or scheme "scheme")))) + (substitute* '("Mf-stex" + "math/Makefile") + (("/bin/rm") + "rm")) + (substitute* "Mf-stex" + (("SHELL=bash") + ;; avoid Solaris workaround + "#SHELL=bash")))) + (add-after 'install 'maybe-compile + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (cond + ((getenv "Scheme") + => (lambda (scheme) + (define makefile + (string-append (getcwd) "/Makefile")) + (define machine + #$(nix-system->chez-machine + (or (%current-target-system) + (%current-system)))) + (with-directory-excursion + (search-input-directory outputs "/lib/stex") + (invoke "make" + "-f" makefile + (string-append "Scheme=" scheme)) + (for-each delete-file + (find-files machine "\\."))))) + (else + (format #t "not compiling~%"))))) + (add-after 'maybe-compile 'maybe-make-docs + (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) + (cond + ((assoc-ref outputs "doc") + => (lambda (doc-prefix) + (define doc-dir + (string-append doc-prefix "/share/doc/stex")) + ;; the Makefile is referenced in the documentation + (copy-recursively "doc" doc-dir) + (install-file "ReadMe" doc-dir) + (with-directory-excursion "doc" + (invoke "make") + (install-file "stex.html" doc-dir) + (install-file "stex.pdf" doc-dir)))) + (else + (format #t "not making docs~%")))))))) + (home-page "https://github.com/dybvig/stex") + (synopsis "LaTeX with embeded Scheme code and HTML generation") + (description "The @code{stex} package extends LaTeX with a handful of +commands for including Scheme code (or pretty much any other kind of code, as +long as you don't plan to use the Scheme-specific transcript support) in a +document. It provides the programs @code{scheme-prep} and @code{html-prep} to +convert @code{stex} documents to LaTeX and HTML, respectively, plus makefile +templates, style files, and other resources. The @code{stex} system is used +to typeset @cite{The Scheme Programming Language} and the @cite{Chez Scheme +User's Guix}, among other documents.") + (license license:expat))))) + +(define-public stex + (package/inherit stex-bootstrap + (inputs (modify-inputs (package-inputs stex-bootstrap) + (prepend chez-scheme))) + (outputs '("out" "doc")) + (properties '()))) + +(define-public nanopass + (let ((version "1.9.2")) + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/nanopass/nanopass-framework-scheme") + (commit (string-append "v" version)))) + (sha256 (base32 "16vjsik9rrzbabbhbxbaha51ppi3f9n8rk59pc6zdyffs0vziy4i")) + (file-name (git-file-name "nanopass" version))))) diff --git a/gnu/packages/racket.scm b/gnu/packages/racket.scm index 865fdff70f..d8338bcd6f 100644 --- a/gnu/packages/racket.scm +++ b/gnu/packages/racket.scm @@ -333,9 +333,8 @@ (define-public racket-bootstrap-chez-bootfiles `(("racket" ,(if (%current-target-system) racket-minimal racket-minimal-bc-3m)) - ("stex" ,@(assoc-ref (package-native-inputs chez-scheme) "stex")) - ("nanopass" ,@(assoc-ref (package-native-inputs chez-scheme) - "nanopass")))) + ("stex" ,(package-source stex)) + ("nanopass" ,nanopass))) (arguments `(#:phases (modify-phases %standard-phases From patchwork Sun Feb 13 21:51:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37236 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 2F73227BBEA; Sun, 13 Feb 2022 21:55:29 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 90D4627BBE9 for ; Sun, 13 Feb 2022 21:55:28 +0000 (GMT) Received: from localhost ([::1]:58928 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMq7-00070G-Nm for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:27 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43418) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMom-0005cN-MJ for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45184) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMom-0001uC-DI for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMom-0003EF-Dc for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 06/11] gnu: Add chez-nanopass. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478919512251 (code B ref 53878); Sun, 13 Feb 2022 21:54:04 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:15 +0000 Received: from localhost ([127.0.0.1]:39063 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMny-0003BS-Sh for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:15 -0500 Received: from mail-qk1-f179.google.com ([209.85.222.179]:40881) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMnw-0003Ax-It for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:12 -0500 Received: by mail-qk1-f179.google.com with SMTP id o25so12986269qkj.7 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0RoPqjGuiAdlkTJfEuvvQASmSYaOTDgT7ADK6BvAjY0=; b=SNH3cAF0xRaq78IK5sHzA1dJwvRiu138+v4cv5nSV9RK7J+XCAANYeEKK91UvBFIrc zmO3+s447pjM8v+olvD0/FsjPy3iNQsCo5pQBGamtc7XKZVXBJWpqbd2pXRMeRQH07IL baiYYMa1g06KuGMPReWWpilIUXTgnU6YYCIupxuaCvMLa0OgMa45cOhy91RsUiRDvnf5 xCtW0VmgHcxzl/L7U7hWA6CY4GbYVpeinQDZ/Iwd7wPhuAIUDC+d7cuFN4E1iIMyEbgh Au1V7FooH56DXXZB0FHZataIDbN3Uitdfvzek3Lm8Ixv82M36zWBGAThMsY7/BSKr190 4QHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0RoPqjGuiAdlkTJfEuvvQASmSYaOTDgT7ADK6BvAjY0=; b=zfm32rTkeSqa76qkPxeQYZfk8VHX5dap83qkZt268uquRQprEv8WQu1OUZM7Pt2894 qtBAxzfqoW0Fgfv/YTWk9KE6+C2L2etByTuEcttMMjbIboSP9FZXTyxEMq3ysFvZ+i3u vGcdGwN9CSWqyrGYNPGvy6paxWaA0VSuaWaXfj5wAVof6TB0tpbqZSb6wNaXWUl3ZRP7 8hlc4YzyXC5LG53gkN6Sz3M0WEZyD+UytILlZTtXbz1N7o8xcZgYuJJZGMR4M+fUbw37 3biCT/q80FKbwtxV9QIxBby3lAtdOQH3GNFcE3JESa7iXGrHRdKB/NCI/mIsZqqtylyW VQOA== X-Gm-Message-State: AOAM5312Z+C42/h6yvgWNqqUk0l/fzve0mlxTwZi2L5X2TqOW7fIqj2Q M1nQP6qBuaW1mA40Iaiq4qd/y8qCna3LQDrSmak= X-Google-Smtp-Source: ABdhPJxl1oFGTbGXdsiJLScfAl5adcMTPLpqe4jpF7b/UEc7/2TkRWNrw2UUdIB/UIZ9m/oVZCYm4g== X-Received: by 2002:a05:620a:e1d:: with SMTP id y29mr4776400qkm.274.1644789187066; Sun, 13 Feb 2022 13:53:07 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id f20sm17374305qte.14.2022.02.13.13.53.06 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:53:06 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:22 -0500 Message-Id: <20220213215127.218952-7-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/packages/chez-and-racket-bootstrap.scm (nanopass): Rename to ... (chez-nanopass-bootstrap): ... this new variable, and promote it from an origin to a package. (chez-scheme)[native-inputs]: Add it. (chez-nanopass): New variable. (unpack-nanopass+stex): Adapt accordingly. * gnu/packages/racket.scm (racket-bootstrap-chez-bootfiles)[native-inputs]: Likewise. --- gnu/packages/chez-and-racket-bootstrap.scm | 97 ++++++++++++++++++---- gnu/packages/racket.scm | 2 +- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index 945d1ce2ed..90fd63b5ae 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -203,12 +203,13 @@ (define unbundle-chez-submodules "lz4" "zlib")))) -(define (unpack-nanopass+stex) - ;; delayed resolution of `nanopass` +(define unpack-nanopass+stex #~(begin - (copy-recursively #$nanopass - "nanopass" - #:keep-mtime? #t) + (copy-recursively + (dirname (search-input-file %build-inputs + "lib/chez-scheme/nanopass.ss")) + "nanopass" + #:keep-mtime? #t) (mkdir-p "stex") (with-output-to-file "stex/Mf-stex" (lambda () @@ -241,7 +242,7 @@ (define-public chez-scheme ;; for X11 clipboard support in expeditor: ;; https://github.com/cisco/ChezScheme/issues/9#issuecomment-222057232 libx11)) - (native-inputs (list stex-bootstrap)) + (native-inputs (list chez-nanopass-bootstrap stex-bootstrap)) (native-search-paths (list (search-path-specification (variable "CHEZSCHEMELIBDIRS") @@ -261,7 +262,7 @@ (define-public chez-scheme #~(modify-phases %standard-phases (add-after 'unpack 'unpack-nanopass+stex (lambda args - #$(unpack-nanopass+stex))) + #$unpack-nanopass+stex)) ;; NOTE: the custom Chez 'configure' script doesn't allow ;; unrecognized flags, such as those automatically added ;; by `gnu-build-system`. @@ -485,12 +486,76 @@ (define-public stex (outputs '("out" "doc")) (properties '()))) -(define-public nanopass - (let ((version "1.9.2")) - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/nanopass/nanopass-framework-scheme") - (commit (string-append "v" version)))) - (sha256 (base32 "16vjsik9rrzbabbhbxbaha51ppi3f9n8rk59pc6zdyffs0vziy4i")) - (file-name (git-file-name "nanopass" version))))) +(define-public chez-nanopass-bootstrap + (hidden-package + (package + (name "chez-nanopass") + (version "1.9.2") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/nanopass/nanopass-framework-scheme") + (commit (string-append "v" version)))) + (sha256 + (base32 "16vjsik9rrzbabbhbxbaha51ppi3f9n8rk59pc6zdyffs0vziy4i")) + (file-name (git-file-name "nanopass-framework-scheme" version)) + (snippet + #~(begin + (use-modules (guix build utils)) + (when (file-exists? "doc/user-guide.pdf") + (delete-file "doc/user-guide.pdf")) + (substitute* "doc/Makefile" + (("include ~/stex/Mf-stex") + "include $(STEXLIB)/Mf-stex")))))) + (build-system copy-build-system) + (arguments + (list #:install-plan + #~`(("nanopass.ss" "lib/chez-scheme/") + ("nanopass" "lib/chez-scheme/")))) + (home-page "https://nanopass.org") + (synopsis "DSL for compiler development") + (description "The Nanopass framework is an embedded domain-specific +language for writing compilers composed of several simple passes that +operate over well-defined intermediate languages. The goal of this +organization is both to simplify the understanding of each pass, because it +is responsible for a single task, and to simplify the addition of new passes +anywhere in the compiler. Nanopass reduces the boilerplate required to +create compilers, making them easier to understand and maintain.") + (license license:expat)))) + +(define-public chez-nanopass + (package/inherit chez-nanopass-bootstrap + (properties '()) + ;; TODO: cross-compilation + (native-inputs (list chez-scheme stex)) + (arguments + (substitute-keyword-arguments (package-arguments chez-nanopass-bootstrap) + ((#:install-plan base-plan) + #~`(("nanopass.so" "lib/chez-scheme/") + ("doc/user-guide.pdf" #$(string-append + "share/doc/" + (package-name this-package) + "-" + (package-version this-package) + "/")) + ,@#$base-plan)) + ((#:phases base-phases #~%standard-phases) + #~(modify-phases #$base-phases + (add-before 'install 'compile-and-test + (lambda args + (invoke "scheme" + "--compile-imported-libraries" + "--program" "test-all.ss"))) + (add-after 'compile-and-test 'build-doc + (lambda* (#:key native-inputs inputs #:allow-other-keys) + (with-directory-excursion "doc" + (invoke "make" + (string-append "Scheme=" + (search-input-file + (or native-inputs inputs) + "/bin/scheme")) + (string-append "STEXLIB=" + (search-input-directory + (or native-inputs inputs) + "/lib/stex")))))))))))) diff --git a/gnu/packages/racket.scm b/gnu/packages/racket.scm index d8338bcd6f..e8d016c07b 100644 --- a/gnu/packages/racket.scm +++ b/gnu/packages/racket.scm @@ -334,7 +334,7 @@ (define-public racket-bootstrap-chez-bootfiles racket-minimal racket-minimal-bc-3m)) ("stex" ,(package-source stex)) - ("nanopass" ,nanopass))) + ("nanopass" ,(package-source chez-nanopass)))) (arguments `(#:phases (modify-phases %standard-phases From patchwork Sun Feb 13 21:51:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37232 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 62D6F27BBEB; Sun, 13 Feb 2022 21:55:11 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id B778627BBE9 for ; Sun, 13 Feb 2022 21:55:10 +0000 (GMT) Received: from localhost ([::1]:57810 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpp-0006GH-Pf for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:09 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43420) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMon-0005cg-2q for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45185) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMom-0001uJ-Pl for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMom-0003EM-Q3 for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:04 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 07/11] gnu: chez-scheme: Explicitly package bootstrap bootfiles. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478920112272 (code B ref 53878); Sun, 13 Feb 2022 21:54:04 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:21 +0000 Received: from localhost ([127.0.0.1]:39067 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMo5-0003Br-D6 for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:21 -0500 Received: from mail-qk1-f179.google.com ([209.85.222.179]:40884) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMo0-0003BF-Hs for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:17 -0500 Received: by mail-qk1-f179.google.com with SMTP id o25so12986324qkj.7 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CYgngiATXaLMvhaAGpIcMnIeSYTe0mOCGRZVfgJ63WI=; b=jwW6YlLJr67sTXjSSCYhaU+Ee2tKd4zfgBQZfritpRkdmyeq46bjieZWRBTLmotQnv cp9qgc24fXjD+YcrKvS7QIs1UqfyrDMjb+pLKLXCRAHYcsoftlbLbu+1KuhFMkqBkoDK WegsfAPVTBw7/Dy44TCTaYpJ8O3EtDIUYFyBm6eJpjHpKV+1LvhqJ66mWZok80gSZAiX nNuul7BohRtbMskBw3dUKEZkoovuBSUQY7PiDMem1FLO4J2ROw+GUQjmkRBhO9T7FYDa Pe46/Plk0XhElQlkUFD0lFWYj+xECM2BNLXom8HRwGU7D9pIpP3HYlIhy9cFgn1CG8gA ponA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CYgngiATXaLMvhaAGpIcMnIeSYTe0mOCGRZVfgJ63WI=; b=fN5pn4s2ew1SoBzLr1xLF911K3WfudyolH8ptYU3rxyDM+4xY4U2mYYQuQDRQYKtKd 1+O291grVSovy3NImfd9B7D7FQN6Bz6+ISnVh0nsvMjCFNYpRgmW4aTMDDAe7I5jDpN7 qW4rZOmOLlqi2CcQsAzXHDINgqFdPCarPlwoiNABXhR6E8DHB8BzU0EXEbeJJzXKrfrk 43/qGxAUUDXNRN5bZ/Xf9oO7ORdJGzPtivXrLpsxfxWQDwPu/3m4TJKt7hPKfVdVcvc+ NVOsmozv+CfWQEXQcd6Sr99IID9k4tL5NjWerC4QC26CVyJkT24QH5NHOj30PdcVfKZE 61Ag== X-Gm-Message-State: AOAM530G5Rur89Amm5b3Ik2UPx+NYZIBvvud//ehGPIKW4gABvUEozL4 xysJhFXdwD2uB0azqsbnonjIfNnScGRTAd+QFXo= X-Google-Smtp-Source: ABdhPJzBsVoWBxh3noXT2CiNvW834eIn5XQKLWRzaQ01NtfwdWfJ94aYPGV2JRBPt6ErbvKyS7tkkQ== X-Received: by 2002:a05:620a:1928:: with SMTP id bj40mr5471915qkb.520.1644789191024; Sun, 13 Feb 2022 13:53:11 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id m17sm16938970qtk.53.2022.02.13.13.53.10 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:53:10 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:23 -0500 Message-Id: <20220213215127.218952-8-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches This might seem a bit silly in isolation, but it makes the structure of the upstream Chez Scheme package the same as for the Racket variant, it sets things up for (one day, hopefully) actually being able to bootstrap the upstream Chez Scheme bootfiles, and it may be useful for cross-compilation and adding support for architectures without pre-built bootfiles from upstream. * gnu/packages/chez-and-racket-bootstrap.scm (chez-scheme-bootstrap-bootfiles): New variable. (chez-scheme)[native-inputs]: Add it. [arguments]: Add new phase 'unpack-bootfiles'. [version, source, home-page]: Derive from 'chez-scheme-bootstrap-bootfiles'. --- gnu/packages/chez-and-racket-bootstrap.scm | 57 ++++++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index 90fd63b5ae..38708ab690 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -216,9 +216,9 @@ (define unpack-nanopass+stex ;; otherwise, it will try to download submodules (display "# to placate ../configure"))))) -(define-public chez-scheme +(define-public chez-scheme-bootstrap-bootfiles (package - (name "chez-scheme") + (name "chez-scheme-bootstrap-bootfiles") ;; The version should match `(scheme-version-number)`. ;; See s/cmacros.ss c. line 360. (version "9.5.6") @@ -230,8 +230,45 @@ (define-public chez-scheme (sha256 (base32 "07s433hn1z2slfc026sidrpzxv3a8narcd40qqr1xrpb9012xdky")) - (file-name (git-file-name name version)) + (file-name (git-file-name "chez-scheme" version)) (snippet unbundle-chez-submodules))) + (build-system copy-build-system) + ;; TODO: cross compilation + (arguments + (list #:install-plan + #~`(("boot/" "lib/chez-scheme-bootfiles")))) + (supported-systems + ;; Upstream only distributes pre-built bootfiles for + ;; arm32le and t?(i3|a6)(le|nt|osx) + (filter (lambda (system) + (let ((mach (nix-system->chez-machine system #:threads? #f))) + (or (equal? "arm32le" mach) + (and mach + (member (substring mach 0 2) '("i3" "a6")) + (or-map (cut string-suffix? <> mach) + '("le" "nt" "osx")))))) + %supported-systems)) + (home-page "https://cisco.github.io/ChezScheme/") + (synopsis "Chez Scheme bootfiles (binary seed)") + (description + "Chez Scheme is a self-hosting compiler: building it requires +``bootfiles'' containing the Scheme-implemented portions compiled for the +current platform. (Chez can then cross-compile bootfiles for all other +supported platforms.) + +This package provides bootstrap bootfiles for upstream Chez Scheme. +Currently, it simply packages the binaries checked in to the upsream +repository. Hopefully we can eventually adapt Racket's @code{cs-bootstrap} to +work with upstream Chez Scheme so that we can bootstrap these files from +source.") + (properties `((hidden? . #t))) + (license license:asl2.0))) + +(define-public chez-scheme + (package + (name "chez-scheme") + (version (package-version chez-scheme-bootstrap-bootfiles)) + (source (package-source chez-scheme-bootstrap-bootfiles)) (build-system gnu-build-system) (inputs (list @@ -242,7 +279,9 @@ (define-public chez-scheme ;; for X11 clipboard support in expeditor: ;; https://github.com/cisco/ChezScheme/issues/9#issuecomment-222057232 libx11)) - (native-inputs (list chez-nanopass-bootstrap stex-bootstrap)) + (native-inputs (list chez-scheme-bootstrap-bootfiles + chez-nanopass-bootstrap + stex-bootstrap)) (native-search-paths (list (search-path-specification (variable "CHEZSCHEMELIBDIRS") @@ -263,6 +302,14 @@ (define-public chez-scheme (add-after 'unpack 'unpack-nanopass+stex (lambda args #$unpack-nanopass+stex)) + (add-after 'unpack-nanopass+stex 'unpack-bootfiles + (lambda* (#:key native-inputs inputs #:allow-other-keys) + (when (directory-exists? "boot") + (delete-file-recursively "boot")) + (copy-recursively + (search-input-directory (or native-inputs inputs) + "lib/chez-scheme-bootfiles") + "boot"))) ;; NOTE: the custom Chez 'configure' script doesn't allow ;; unrecognized flags, such as those automatically added ;; by `gnu-build-system`. @@ -345,7 +392,7 @@ (define* (stex-make #:optional (suffix "")) (not (eq? 'no-support (chez-machine->upstream-restriction mach)))))) %supported-systems))) - (home-page "https://cisco.github.io/ChezScheme/") + (home-page (package-home-page chez-scheme-bootstrap-bootfiles)) (synopsis "R6RS Scheme compiler and run-time") (description "Chez Scheme is a compiler and run-time system for the language of the From patchwork Sun Feb 13 21:51:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37235 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 44D6527BBE9; Sun, 13 Feb 2022 21:55:26 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 06ADE27BBEC for ; Sun, 13 Feb 2022 21:55:20 +0000 (GMT) Received: from localhost ([::1]:58470 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpz-0006hd-5I for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:19 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43422) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMon-0005dS-FP for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45186) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMon-0001uO-5V for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMon-0003EU-5q for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 08/11] gnu: Add chez-scheme-for-racket. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:05 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478921312307 (code B ref 53878); Sun, 13 Feb 2022 21:54:05 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:33 +0000 Received: from localhost ([127.0.0.1]:39070 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMo9-0003CD-Ps for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:33 -0500 Received: from mail-qt1-f178.google.com ([209.85.160.178]:40823) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMo5-0003Bf-6P for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:24 -0500 Received: by mail-qt1-f178.google.com with SMTP id l14so13995327qtp.7 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yykw+AWD6FY/FmvVOZ3HzSxUT5NQ0nqtFL1OavGb7xs=; b=h8UTzpf8dtGAOpfIZCpuk831L6VfT5zOVsAfQM3N5ujMSGZFLBZOhMCLNztzF97VIM CQJS7JPpsRXzxq04diYKLHg13/W43qwr6YQ8goSlhqphsMPXoPHNV57s+cnysOAdeKDE dT9oJ5VsvnUAX/LHGxvXKAor3SZB4qk9ComNYGCmThjVvdgd2xm2Dm0xJKhZEPr4nfUv ITiJzIEmfc9xR38kZ1b5MvIZzwP3E4iEmPu0ZUpre0f2pZTXaY0SPYpQk6er+un5xOma nNcOcMRxylgrRwlh04yqJRHbXPuiHOzxMCF6aESU37xwL8XwpJg0XX6X5AYxASHGLI2t I42g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=yykw+AWD6FY/FmvVOZ3HzSxUT5NQ0nqtFL1OavGb7xs=; b=OCCZonkjN+kDkayMGkvO8L/SCBWBbmG5Od+6FSJ/G89qgutJXlZAvEZJhlMOV0xVSQ UQD3lP9sWtFV3ya3Hv/LvkPuZNp4YyV+fq18hYwKGD+9H8YvdgNHswHbilRp+9rbU+j6 bNigI/RL04wULWr3OuwewWnF5v+r2XDV7mSliIGOy+CxHzDdKdRLLqTX+bSLqoBNRbi7 E61ADQFvWSnlE+JC8YHYjQrgY7Z+2U+QxAmUV4xyQHQnk9R4JcGe/QBD3NuwgnEAUjSw wQRKYlThgf2hC2Hn9RYFdIn08UPvmyNGG/pfDPXis6Mjz9WC+fjQT9emhfBOF0862AF9 nyCQ== X-Gm-Message-State: AOAM530sNiXqfV6HAZ6KgaRTANH09HPduyNFBvSVzBO0Jw04b1e2y2CG letrBUzzKM0/tqalKaX+OB7OY+ZDTw0Tvblbc4s= X-Google-Smtp-Source: ABdhPJxAyr/uQMOTja7zoxsvBgMeD1B713d6kyK+A993vY7vRygSej2dBTBOtUwVlXsgwYTBrEg9xQ== X-Received: by 2002:ac8:5cd2:: with SMTP id s18mr7582407qta.558.1644789195068; Sun, 13 Feb 2022 13:53:15 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id u36sm5611466qtc.42.2022.02.13.13.53.14 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:53:14 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:24 -0500 Message-Id: <20220213215127.218952-9-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches The Racket variant of Chez Scheme can be used to support platforms that are not yet supported by upstream Chez Scheme. In the process, we also add packages for 'racket-vm-cgc', 'racket-vm-bc', and 'racket-vm-cs'. A future commit will change 'racket-minimal' to use the Racket VM implementation that best supports the target system. * gnu/packages/patches/racket-enable-scheme-backport.patch: New patch. * gnu/local.mk (dist_patch_DATA): Add it. * gnu/packages/chez-and-racket-bootstrap.scm (racket-vm-cgc): (racket-vm-bc): (racket-vm-cs): (chez-scheme-for-racket-bootstrap-bootfiles): (chez-scheme-for-racket): New variables. --- gnu/local.mk | 1 + gnu/packages/chez-and-racket-bootstrap.scm | 489 +++++++++++++++++- .../racket-enable-scheme-backport.patch | 465 +++++++++++++++++ 3 files changed, 948 insertions(+), 7 deletions(-) create mode 100644 gnu/packages/patches/racket-enable-scheme-backport.patch diff --git a/gnu/local.mk b/gnu/local.mk index 72e086d465..8ffdd15ee2 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1787,6 +1787,7 @@ dist_patch_DATA = \ %D%/packages/patches/ripperx-missing-file.patch \ %D%/packages/patches/rpcbind-CVE-2017-8779.patch \ %D%/packages/patches/rtags-separate-rct.patch \ + %D%/packages/patches/racket-enable-scheme-backport.patch \ %D%/packages/patches/racket-minimal-sh-via-rktio.patch \ %D%/packages/patches/remake-impure-dirs.patch \ %D%/packages/patches/restic-0.9.6-fix-tests-for-go1.15.patch \ diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index 38708ab690..d2f78dfae2 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -34,8 +34,11 @@ (define-module (gnu packages chez-and-racket-bootstrap) #:use-module (guix build-system copy) #:use-module (guix build-system gnu) #:use-module (gnu packages) + #:use-module (gnu packages autotools) + #:use-module (gnu packages bash) #:use-module (gnu packages compression) #:use-module (gnu packages ghostscript) + #:use-module (gnu packages libffi) #:use-module (gnu packages linux) #:use-module (gnu packages ncurses) #:use-module (gnu packages netpbm) @@ -62,6 +65,144 @@ (define-module (gnu packages chez-and-racket-bootstrap) ;; Putting the relevant definitions together in this module avoids having to ;; work around dependency cycles. ;; +;; Anatomy of Racket: +;; ------------------ +;; +;; The main Racket Git repository () is +;; organized broadly like this: +;; +;; . +;; ├── Makefile +;; ├── pkgs/ +;; └── racket/ +;; ├── collects/ +;; └── src/ +;; ├── configure +;; ├── Makefile.in +;; ├── bc/ +;; ├── cs/ +;; ├── ChezScheme/ +;; └── ... +;; +;; The 'racket/src/' directory contains the source of the runtime system, core +;; compiler, and primitives for the major Racket implementations: this layer +;; is called the ``Racket VM''. It is basically a normal autotools +;; project. (Even when Racket VM implementations use components implemented in +;; Racket, they are compiled in special modes to produce VM primitives.) +;; (There are or have been experimental Racket VM implementations elsewhere, +;; e.g. .) One way of thinking about the +;; bounary between the Racket VM and Racket programs is that the VM implements +;; the primitives accessed by the 'ffi/unsafe/vm' library. Another perspective +;; is that DrRacket's ``Open defining file''/``Jump to definition'' features +;; can navigate into Racket programs, including into the implementation of +;; 'racket/base', but can not jump into the implementation of the Racket VM +;; itself. A third, related perspective is that Racket code is usually +;; installed with source files alongside compiled code (though this is not +;; mandatory), whereas the Racket VM is installed only in compiled form. +;; +;; The 'racket/collects/' directory contains ``built in'' Racket libraries +;; that are not part of any package, including the implementation of +;; 'racket/base': in particular, it must contain enough to implement `raco pkg +;; install'. It is theoretically possible to use the Racket VM layer without +;; the main collections, but it is not stable or useful. +;; +;; The 'pkgs/' directory contains Racket packages that are especially closely +;; tied to the implementation of the Racket VM, including 'compiler-lib', +;; 'racket-doc', and 'racket-test'. Some of these packages depend on Racket +;; packages that are developed in other Git repositories, predominantly but +;; not exclusively under the 'racket' GitHub organization. Conversely, not all +;; of the packages developed in the main Git repository are part of the main +;; Racket distribution. (Additionally, components of the Racket VM that are +;; implemented in Racket can be installed as packages, mostly for ease of +;; development.) +;; +;; The top-level 'Makefile' is more like a directory of scripts: it has +;; convienience targets for developing Racket, and it cooperates with the +;; 'distro-build' package to assemble custom Racket distributions. It is not +;; part of Racket source distributions: the root of a source distribution is +;; basically 'racket/src' with some extra package sources and configuration +;; added. +;; +;; A ''minimal Racket'' installation includes two packages: 'base', which is a +;; sort of bridge between the current ``built-in'' collections and the package +;; system's model of dependencies, and 'racket-lib', which, for installations +;; that can not rely on a system package manager, pulls in the SQLite and +;; OpenSSL shared libraries as platform-specific dependencies for use by the +;; ``built-in'' collections. +;; +;; The main Racket distribution consists of installing the 'main-distribution' +;; package and all of its dependencies. +;; +;; The default mode when building Racket (or installing it with the released +;; installers) is an ``in-place build'', which produces a self-contained, +;; relocatable, roughly FHS-like directory. (Racket also supports +;; ``Unix-style'' installations, which rearrange the parts of an in-place +;; build into Racket-specific subdirectories and generally tries to work for +;; installation into an FHS-based system.) Certain tools, e.g. 'distro-build' +;; and 'raco cross', are able to work with an in-place Racket build. +;; +;; This file defines the packages 'racket-vm-cgc', 'racket-vm-bc', and +;; 'racket-vm-cs'. All three are in-place builds of 'racket/src/' and +;; 'racket/collects/' and are installed to 'opt/racket-vm/' in the store +;; output. The function 'racket-vm-for-system' returns the recomended Racket +;; VM package for a given system. +;; +;; The file 'racket.scm' builds on these packages to define 'racket-minimal' +;; and 'racket' packages. These use Racket's support for ``layered +;; installations'', which allow an immutable base layer to be extended with +;; additional packages. They use the layer configuration directly provide +;; ready-to-install FHS-like trees, rather than relying on the built in +;; ``Unix-style install'' mechanism. +;; +;; Bootstrapping Racket: +;; --------------------- +;; +;; Here's how bootstrapping Racket works: +;; +;; - Racket BC [CGC] can be built with only a C compiler (except for +;; one caveat discussed below). +;; - Racket BC [3M] needs an existing Racket to run "xform", +;; which transforms its own C source code to add additional annotations +;; for the precise garbage collector. +;; - Racket CS needs (bootfiles for) Racket's fork of Chez Scheme. +;; It also needs an existing Racket to compile Racket-implemented +;; parts of the runtime system to R6RS libraries. +;; - Chez Scheme also needs bootfiles for itself, but Racket can simulate +;; enough of Chez Scheme to load Racket's fork of the Chez Scheme compiler +;; purely from source into Racket and apply the compiler to itself, +;; producing the needed bootfiles (albeit very slowly). +;; Any variant of Racket since version 7.1 can run the simulation. +;; +;; So, we build CGC to build 3M to build bootfiles and CS. +;; +;; (Note: since the CGC variant is basically only for bootstrapping, we +;; often use "BC" to mean "3M", consistent with `(banner)` and the +;; suffixes used on executables when more than one variant co-exists.) +;; +;; One remaining bootstrapping limitation is that Racket's reader, module +;; system, and macro expander are implemented in Racket. For Racket CS, +;; they are compiled to R6RS libraries as discussed above. This note from the +;; README file applies to all such subsystems: +;; +;; The Racket version must be practically the same as the current Racket +;; verson, although it can be the Racket BC implementation (instead of +;; the Racket CS implementation). +;; +;; Unlike Chez Scheme boot files, the files generated in "schemified" +;; are human-readable and -editable Scheme code. That provides a way +;; out of bootstrapping black holes, even without BC. +;; +;; However, other Racket subsystems implemented in Racket for Racket CS +;; use older C implementations for Racket BC, whereas the reader, expander, +;; and module system were completely replaced with the Racket implementation +;; +;; For Racket BC, the compiled "linklet" s-expressions (primitive modules) +;; are embeded in C as a static string constant. Eventually, they are further +;; compiled by the C-implemented Racket BC bytecode and JIT compilers. +;; (On platforms where Racket BC's JIT is not supported, yet another compiler +;; instead compiles the linklets to C code, but this is not a bootstrapping +;; issue.) +;; ;; Code: (define (chez-machine->unthreaded mach) @@ -189,19 +330,19 @@ (define* (nix-system->chez-machine #:optional (system (%current-system)) (chez-machine->threaded mach))))))) ;; -;; Chez Scheme: +;; Chez auxiliary G-expressions: ;; (define unbundle-chez-submodules #~(begin (use-modules (guix build utils)) (for-each (lambda (dir) - (when (directory-exists? dir) - (delete-file-recursively dir))) - '("stex" - "nanopass" - "lz4" - "zlib")))) + (when (directory-exists? dir) + (delete-file-recursively dir))) + '("stex" + "nanopass" + "lz4" + "zlib")))) (define unpack-nanopass+stex #~(begin @@ -216,6 +357,234 @@ (define unpack-nanopass+stex ;; otherwise, it will try to download submodules (display "# to placate ../configure"))))) +;; +;; Racket VM: +;; + +(define (racket-vm-common-configure-flags) + ;; under a lambda extraction to avoid evaluating bash-minimal too early + #~`(,@(cond + ((false-if-exception + (search-input-file %build-inputs "/bin/libtool")) + => (lambda (libtool) + (list (string-append "--enable-lt=" libtool)))) + (else + '())) + ,@(cond + ((false-if-exception + (search-input-file %build-inputs "/opt/racket-vm/bin/racket")) + => (lambda (racket) + (list (string-append "--enable-racket=" racket)))) + (else + '())) + ,(string-append "CPPFLAGS=-DGUIX_RKTIO_PATCH_BIN_SH=" + #$(file-append bash-minimal "/bin/sh")) + "--disable-strip" + "--enable-origtree")) + +(define-public racket-vm-cgc + ;; Eventually, it may make sense for some vm packages to not be hidden, + ;; but this one is especially likely to remain hidden. + (hidden-package + (package + (name "racket-vm-cgc") + (version "8.4") + ;; ^ Remember to also update the version of + ;; chez-scheme-for-racket-bootstrap-bootfiles + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/racket") + (commit (string-append "v" version)))) + (sha256 + (base32 "1vpl66gdgc8rnldmn8rmb7ar9l057jqjvgpfn29k57i3c5skr8s6")) + (file-name (git-file-name "racket" version)) + (patches (search-patches "racket-minimal-sh-via-rktio.patch" + ;; Remove by Racket 8.5: + "racket-enable-scheme-backport.patch")) + (modules '((guix build utils))) + (snippet + #~(begin + ;; Unbundle Chez submodules. + (with-directory-excursion "racket/src/ChezScheme" + #$unbundle-chez-submodules) + ;; Unbundle libffi. + (delete-file-recursively "racket/src/bc/foreign/libffi"))))) + (inputs (list ncurses ;; <- common to all variants (for #%terminal) + bash-minimal ;; <- common to all variants (for `system`) + libffi)) ;; <- only for BC variants + (native-inputs (list libtool)) ;; <- only for BC variants + (outputs '("out" "debug")) + (build-system gnu-build-system) + (arguments + (list + #:configure-flags + #~(cons "--enable-cgcdefault" + #$(racket-vm-common-configure-flags)) + ;; Tests are in packages like racket-test-core and + ;; main-distribution-test that aren't part of the main + ;; distribution. + #:tests? #f + ;; Upstream recommends #:out-of-source?, and it does + ;; help with debugging, but it confuses `install-license-files`. + #:modules '((ice-9 match) + (ice-9 regex) + (guix build gnu-build-system) + (guix build utils)) + #:strip-directories #~'("opt/racket-vm/bin" + "opt/racket-vm/lib") + #:phases + #~(let () + (define* ((wrap-racket-vm-outputs phase) . args) + (apply + phase + (let loop ((args args)) + (match args + ((#:outputs outputs . args) + `(#:outputs + ,(let loop ((outputs outputs)) + (match outputs + ((("out" . out) . outputs) + `(("out" . ,(string-append out "/opt/racket-vm/")) + ,@outputs)) + ((other . outputs) + (cons other (loop outputs))))) + ,@args)) + ((arg . args) + (cons arg (loop args))))))) + (modify-phases %standard-phases + (add-before 'configure 'initialize-config.rktd + (lambda* (#:key inputs #:allow-other-keys) + (define (write-racket-hash alist) + ;; inside must use dotted pair notation + (display "#hash(") + (for-each (match-lambda + ((k . v) + (format #t "(~s . ~s)" k v))) + alist) + (display ")\n")) + (define maybe-release-catalog + (let ((v #$(package-version this-package))) + (if (string-match "^[0-9]+\\.[0-9]+($|\\.[0-8][0-9]*$)" + v) + `(,(string-append + "https://download.racket-lang.org/releases/" + v + "/catalog/")) + '()))) + (mkdir-p "racket/etc") + (with-output-to-file "racket/etc/config.rktd" + (lambda () + (write-racket-hash + `((build-stamp . "") + (catalogs ,@maybe-release-catalog + #f))))))) + (add-before 'configure 'chdir + (lambda _ + (chdir "racket/src"))) + (replace 'configure + (wrap-racket-vm-outputs + (assoc-ref %standard-phases 'configure))) + (replace 'patch-shebangs + (wrap-racket-vm-outputs + (assoc-ref %standard-phases 'patch-shebangs))) + (replace 'validate-runpath + (wrap-racket-vm-outputs + (assoc-ref %standard-phases 'validate-runpath))) + (replace 'make-dynamic-linker-cache + (wrap-racket-vm-outputs + (assoc-ref %standard-phases 'make-dynamic-linker-cache))) + (replace 'patch-dot-desktop-files + (wrap-racket-vm-outputs + (assoc-ref %standard-phases 'patch-dot-desktop-files))))))) + (home-page "https://racket-lang.org") + (synopsis "Old Racket implementation used for bootstrapping") + (description "This variant of the Racket BC (``before Chez'' or +``bytecode'') implementation is not recommended for general use. It uses +CGC (a ``Conservative Garbage Collector''), which was succeeded as default in +PLT Scheme version 370 (which translates to 3.7 in the current versioning +scheme) by the 3M variant, which in turn was succeeded in version 8.0 by the +Racket CS implementation. + +Racket CGC is primarily used for bootstrapping Racket BC [3M]. It may +also be used for embedding applications without the annotations needed in C +code to use the 3M garbage collector.") + ;; https://download.racket-lang.org/license.html + ;; The LGPL components are only used by Racket BC. + (license (list license:lgpl3+ license:asl2.0 license:expat))))) + +(define-public racket-vm-bc + (package + (inherit racket-vm-cgc) + (name "racket-vm-bc") + (native-inputs + (modify-inputs (package-native-inputs racket-vm-cgc) + (prepend racket-vm-cgc))) + (arguments + (substitute-keyword-arguments (package-arguments racket-vm-cgc) + ((#:configure-flags _ '()) + #~(cons "--enable-bconly" + #$(racket-vm-common-configure-flags))))) + (synopsis "Racket BC [3M] implementation") + (description "The Racket BC (``before Chez'' or ``bytecode'') +implementation was the default before Racket 8.0. It uses a compiler written +in C targeting architecture-independent bytecode, plus a JIT compiler on most +platforms. Racket BC has a different C API and supports a slightly different +set of architectures than the current default runtime system, Racket CS (based +on ``Chez Scheme''). It is the recommended implementation for architectures +that Racket CS doesn't support. + +This package is the normal implementation of Racket BC with a precise garbage +collector, 3M (``Moving Memory Manager'')."))) + +(define-public racket-vm-cs + (package + (inherit racket-vm-bc) + (name "racket-vm-cs") + (inputs + (modify-inputs (package-inputs racket-vm-cgc) + (prepend zlib lz4) + (delete "libffi"))) + (native-inputs + (modify-inputs (package-native-inputs racket-vm-cgc) + (delete "libtool") + (prepend chez-scheme-for-racket + chez-nanopass-bootstrap + racket-vm-bc))) + (arguments + (substitute-keyword-arguments (package-arguments racket-vm-cgc) + ((#:phases those-phases #~%standard-phases) + #~(modify-phases #$those-phases + (add-after 'unpack 'unpack-nanopass+stex + (lambda args + (with-directory-excursion "racket/src/ChezScheme" + #$unpack-nanopass+stex))))) + ((#:configure-flags _ '()) + #~(cons* "--enable-csonly" + "--enable-libz" + "--enable-lz4" + (string-append "--enable-scheme=" + #$(this-package-native-input + "chez-scheme-for-racket") + "/bin/scheme") + #$(racket-vm-common-configure-flags))))) + (synopsis "Racket CS implementation") + (description "The Racket CS implementation, which uses ``Chez Scheme'' as +its core compiler and runtime system, has been the default Racket VM +implemetation since Racket 8.0. It performs better than the Racket BC +implementation for most programs. + +Using the Racket VM packages directly is not recommended: instead, install the +@code{racket-minimal} or @code{racket} packages.") + ;; https://download.racket-lang.org/license.html + ;; The LGPL components are only used by Racket BC. + (license (list license:asl2.0 license:expat)))) + +;; +;; Chez Scheme: +;; + (define-public chez-scheme-bootstrap-bootfiles (package (name "chez-scheme-bootstrap-bootfiles") @@ -401,6 +770,112 @@ (define* (stex-make #:optional (suffix "")) and 32-bit PowerPC architectures.") (license license:asl2.0))) + +(define-public chez-scheme-for-racket-bootstrap-bootfiles + (package + (inherit chez-scheme-bootstrap-bootfiles) + (name "chez-scheme-for-racket-bootstrap-bootfiles") + (version "9.5.7.3") + ;; The version should match `(scheme-fork-version-number)`. + ;; See racket/src/ChezScheme/s/cmacros.ss c. line 360. + ;; It will always be different than the upstream version! + (source (package-source racket-vm-cgc)) + (native-inputs (list chez-nanopass-bootstrap racket-vm-bc)) + (arguments + (substitute-keyword-arguments + (package-arguments chez-scheme-bootstrap-bootfiles) + ((#:phases those-phases #~%standard-phases) + #~(modify-phases #$those-phases + (add-after 'unpack 'chdir + (lambda args + (chdir "racket/src/ChezScheme"))) + (add-after 'chdir 'unpack-nanopass+stex + (lambda args + #$unpack-nanopass+stex)) + (add-before 'install 'build + (lambda* (#:key native-inputs inputs #:allow-other-keys) + (invoke (search-input-file (or native-inputs inputs) + "/opt/racket-vm/bin/racket") + "rktboot/main.rkt"))))))) + (home-page "https://github.com/racket/ChezScheme") + ;; ^ This is downstream of https://github.com/racket/racket, + ;; but it's designed to be a friendly landing place for people + ;; who want a ChezScheme-shaped repositroy. + (synopsis "Chez Scheme bootfiles bootstrapped by Racket") + (description "Chez Scheme is a self-hosting compiler: building it +requires ``bootfiles'' containing the Scheme-implemented portions compiled for +the current platform. (Chez can then cross-compile bootfiles for all other +supported platforms.) + +The Racket package @code{cs-bootstrap} (part of the main Racket Git +repository) implements enough of a Chez Scheme simulation to load the Chez +Scheme compiler purely from source into Racket and apply the compiler to +itself, thus bootstrapping Chez Scheme. Bootstrapping takes about 10 times as +long as using an existing Chez Scheme, but @code{cs-bootstrap} supports Racket +7.1 and later, including the Racket BC variant. + +Note that the generated bootfiles are specific to Racket's fork of Chez +Scheme, and @code{cs-bootstrap} does not currently support building upstream +Chez Scheme.") + (properties `()) + (license license:asl2.0))) + +(define-public chez-scheme-for-racket + (package + (inherit chez-scheme) + (name "chez-scheme-for-racket") + (version (package-version chez-scheme-for-racket-bootstrap-bootfiles)) + (source (package-source racket-vm-cgc)) + (inputs + (modify-inputs (package-inputs chez-scheme) + (delete "libx11" "util-linux:lib"))) + (native-inputs + (modify-inputs (package-native-inputs chez-scheme) + (replace "chez-scheme-bootstrap-bootfiles" + chez-scheme-for-racket-bootstrap-bootfiles))) + (arguments + (substitute-keyword-arguments (package-arguments chez-scheme) + ((#:configure-flags cfg-flags #~'()) + #~(cons "--disable-x11" #$cfg-flags)) + ((#:phases those-phases #~%standard-phases) + #~(modify-phases #$those-phases + (add-after 'unpack 'chdir + (lambda args + (chdir "racket/src/ChezScheme"))))))) + (supported-systems (filter nix-system->chez-machine + %supported-systems)) + (home-page + (package-home-page chez-scheme-for-racket-bootstrap-bootfiles)) + (synopsis "Variant of Chez Scheme extended for Racket") + (description "This variant of Chez Scheme is extended to support the +implementation of Racket. It may be useful on platforms that are not yet +supported by upstream Chez Scheme. + +Main additions to Chez Scheme in the Racket variant: +@itemize @bullet +@item +AArch64 support +@item +Portable bytes (@code{pb}) support, which is mainly useful for bootstrapping +a build on any supported platform +@item +Unboxed floating-point arithmetic and flvectors +@item +Type reconstruction during optimization (especially for safe code) +@item +Continuation attachments +@item +Parallel garbage collection, in-place garbage collection for old-generation +objects (instead of always copying), and reachability-based memory +accounting +@item +Ordered finalization, immobile (but collectable) objects, weak/ephemeron +generic hash tables, and reference bytevectors +@item +Faster multiplication and division for large exact numbers +@end itemize") + (license license:asl2.0))) + ;; ;; Chez's bootstrap dependencies: ;; diff --git a/gnu/packages/patches/racket-enable-scheme-backport.patch b/gnu/packages/patches/racket-enable-scheme-backport.patch new file mode 100644 index 0000000000..3a5a4a3d82 --- /dev/null +++ b/gnu/packages/patches/racket-enable-scheme-backport.patch @@ -0,0 +1,465 @@ +From 8d7687842f099e3e7e60d3a83fed58b2c6a92863 Mon Sep 17 00:00:00 2001 +From: Matthew Flatt +Date: Sun, 6 Feb 2022 10:36:09 -0700 +Subject: [PATCH 1/2] Chez Scheme: adapt bootfile build for supplied `Scheme=` + +(cherry picked from commit fca1e02349664060e10278ca2ce6577a949bebf5) + +(Fixed conflicts by dropping pbchunks and pbarch changes.) +--- + racket/src/ChezScheme/configure | 15 ++++++++++++++- + racket/src/ChezScheme/s/Mf-base | 4 ++-- + racket/src/ChezScheme/s/Mf-cross | 4 +++- + 3 files changed, 19 insertions(+), 4 deletions(-) + +diff --git a/racket/src/ChezScheme/configure b/racket/src/ChezScheme/configure +index 4515ffc105..0098829091 100755 +--- a/racket/src/ChezScheme/configure ++++ b/racket/src/ChezScheme/configure +@@ -45,6 +45,7 @@ threads=yes + nothreads=no + temproot="" + help=no ++forceworkarea=no + gzipmanpages=yes + installowner="" + installgroup="" +@@ -205,6 +206,9 @@ while [ $# != 0 ] ; do + --pb) + pb=yes + ;; ++ --force) ++ forceworkarea=yes ++ ;; + --installprefix=*) + installprefix=`echo $1 | sed -e 's/^--installprefix=//'` + ;; +@@ -439,6 +443,7 @@ if [ "$help" = "yes" ]; then + echo " --toolprefix= prefix tool (compiler, linker, ...) names" + echo " --[no]gzip-man-pages compress manual pages ($gzipmanpages)" + echo " --workarea= build directory ($w)" ++ echo " --force configure even without boot files" + echo " CC= C compiler" + echo " CPPFLAGS= C preprocessor flags" + echo " CFLAGS= C compiler flags" +@@ -721,8 +726,16 @@ case "${flagsmuni}" in + ;; + esac + ++if [ "$w" = "$m" ] ; then ++ configuringin="" ++else ++ configuringin=" in $w" ++fi ++ + if [ -f boot/$m/scheme.boot -o -f "$srcdir"/boot/$m/scheme.boot ] ; then +- echo "Configuring for $m" ++ echo "Configuring for $m$configuringin" ++elif [ "$forceworkarea" = yes ] ; then ++ echo "Configuring for $m$configuringin despite missing boot files" + else + if [ "$m" = "" ] ; then + maybem="" +diff --git a/racket/src/ChezScheme/s/Mf-base b/racket/src/ChezScheme/s/Mf-base +index cc6178c973..1f4a967998 100644 +--- a/racket/src/ChezScheme/s/Mf-base ++++ b/racket/src/ChezScheme/s/Mf-base +@@ -94,7 +94,7 @@ endif + # that Scheme and SCHEMEHEAPDIRS are set by Mf-cross to point to the host Scheme + # implementation + Scheme = ../bin/$m/scheme${ExeSuffix} +-export SCHEMEHEAPDIRS=../boot/%m ++export SCHEMEHEAPDIRS=../boot/$m + export CHEZSCHEMELIBDIRS=. + + # Define the libdirs separator character +@@ -691,4 +691,4 @@ reset-one: + + .PHONY: run + run: +- env SCHEMEHEAPDIRS=../boot/$m/ ../bin/$m/scheme $(ARGS) ++ env SCHEMEHEAPDIRS=${SCHEMEHEAPDIRS} ${Scheme} $(ARGS) +diff --git a/racket/src/ChezScheme/s/Mf-cross b/racket/src/ChezScheme/s/Mf-cross +index d796cbb459..397af59a28 100644 +--- a/racket/src/ChezScheme/s/Mf-cross ++++ b/racket/src/ChezScheme/s/Mf-cross +@@ -43,5 +43,7 @@ x$(xm).$(m): + $(MAKE) -f Mf-cross m=$(m) xm=$(xm) i=f o=3 d=0 xpatch + mv xpatch x$(xm).$(m) + ++ifneq ($(SCHEMEHEAPDIRS),:) + # Ensure that cross-compiling "nanopass.so" is rebuilt if the host compiler changed +-nanopass.so: ${SCHEME} ${SCHEMEHEAPDIRS}/petite.boot ${SCHEMEHEAPDIRS}/scheme.boot ++nanopass.so: ${Scheme} ${SCHEMEHEAPDIRS}/petite.boot ${SCHEMEHEAPDIRS}/scheme.boot ++endif +-- +2.32.0 + + +From 26c8e2c1d9b02ad85acef8bda40d92154cf0b699 Mon Sep 17 00:00:00 2001 +From: Matthew Flatt +Date: Sun, 6 Feb 2022 11:03:30 -0700 +Subject: [PATCH 2/2] configure: make `--enable-scheme` work with an executable + +When the same Chez Scheme version as used by Racket is already +available, then `--enable-scheme=...` can supply an executable. For +cross builds, `--enable-scheme=...` can still supply a build +directory, instead, as before. + +(cherry picked from commit 4f0e76855ce7e86107de495292a553469daf0b3f) +--- + racket/src/ChezScheme/makefiles/Makefile.in | 3 ++ + racket/src/README.txt | 30 +++++++++++--- + racket/src/configure | 8 +++- + racket/src/cs/README.txt | 6 ++- + racket/src/cs/c/Makefile.in | 44 ++++++++++++++++----- + racket/src/cs/c/configure | 24 +++++++++-- + racket/src/cs/c/configure.ac | 21 ++++++++-- + 7 files changed, 112 insertions(+), 24 deletions(-) + +diff --git a/racket/src/ChezScheme/makefiles/Makefile.in b/racket/src/ChezScheme/makefiles/Makefile.in +index c396efc851..3998ef9ccd 100644 +--- a/racket/src/ChezScheme/makefiles/Makefile.in ++++ b/racket/src/ChezScheme/makefiles/Makefile.in +@@ -59,6 +59,9 @@ reset: + %.boot: + (cd $(workarea) && $(MAKE) $*.boot) + ++auto.boot: ++ (cd $(workarea) && $(MAKE) $(defaultm).boot) ++ + # .bootquick to build boot files for + # with o=3 d=0 for the cross compiler, and only after + # building the kernel for the configured machine +diff --git a/racket/src/README.txt b/racket/src/README.txt +index 98647aebce..d77310b4a4 100644 +--- a/racket/src/README.txt ++++ b/racket/src/README.txt +@@ -354,6 +354,10 @@ variant of MinGW without "libdelayimp.a", get the implementation of + ======================================================================== + + Cross-compilation requires at least two flags to `configure`: ++`--host=OS` and either `--enable-racket=RACKET` or (for Racket CS) ++`--enable-scheme-SCHEME`. ++ ++More information: + + * `--host=OS`, where OS is something like `i386-gnu-linux` to + indicate the target platform. +@@ -374,11 +378,27 @@ Cross-compilation requires at least two flags to `configure`: + run `configure` again (with no arguments) in a "local" subdirectory + to create a build for the current platform. + +-An additional flag is needed for building Racket CS, unless the flag +-`--enable-racket=auto` is used: +- +- * `--enable-scheme=DIR`, where DIR is a path that has a "ChezScheme" +- directory where Chez Scheme is built for the host system. ++ * `--enable-scheme=SCHEME`, where SCHEME is a Chez Scheme executable ++ executable that runs on the build platform; the executable must be ++ the same version as used in Racket built for the target platform. ++ ++ Supplying `--enable-scheme=DIR` is also supported in cross-build ++ mode, where DIR is a path that has a "ChezScheme" directory where ++ Chez Scheme is built for the host system. ++ ++The `--enable-racket=RACKET` and `--enable-scheme=SCHEME` flags are ++allowed for non-cross builds, too: ++ ++ * For Racket CS, supplying either selects a Racket or Chez Scheme ++ implementation used to create boot files to the build platform. ++ Suppling Chez Scheme is a much more direct path, but when Racket is ++ supplied, its version does not have to match the version being ++ built. ++ ++ * For Racket BC, `--enable-racket=RACKET` selects a Racket for ++ prepare C sources to cooperate with garbage collection. Its version ++ needs to be close to the one being built, and potentially exactly ++ the same version. + + Some less commonly needed `configure` flags are for Racket BC: + +diff --git a/racket/src/configure b/racket/src/configure +index c9f3ba4419..1b53ec7ce2 100755 +--- a/racket/src/configure ++++ b/racket/src/configure +@@ -9,6 +9,7 @@ pb_dir="$dir/ChezScheme/boot/pb" + use_cs=maybe + use_bc=maybe + supplied_racket=no ++supplied_scheme=no + enable_boothelp= + + # We don't have to detect conflicts like `--enable-csdefault --enable-bcdefault`, +@@ -34,6 +35,9 @@ for arg in $*; do + --enable-racket=*) + supplied_racket=yes + ;; ++ --enable-scheme=*) ++ supplied_scheme=yes ++ ;; + --help | -h) + echo $0: + echo see --help-bc or --help-cs, since the Racket CS build and the +@@ -70,8 +74,8 @@ elif test "$use_cs" = "maybe" ; then + fi + + if test "$use_cs" = "yes" ; then +- if test $use_bc = no -a $supplied_racket = no -a ! -d "$pb_dir" ; then +- echo $0: must have $pb_dir or --enable-racket=... for --enable-csonly ++ if test $use_bc = no -a $supplied_racket = no -a $supplied_scheme = no -a ! -d "$pb_dir" ; then ++ echo $0: must have $pb_dir, --enable-racket=... or --enable-scheme=... for --enable-csonly + exit 1 + fi + +diff --git a/racket/src/cs/README.txt b/racket/src/cs/README.txt +index 2ece417b78..8e6fc57b74 100644 +--- a/racket/src/cs/README.txt ++++ b/racket/src/cs/README.txt +@@ -39,6 +39,11 @@ build: + installed in the "../ChezScheme/boot/pb" directory as described by + "../ChezScheme/BUILDING". + ++ Supplying `--enable-scheme=...` is also an option if you alerady ++ have the same version of Chez Scheme built on the current platform. ++ Another build will be created, anyway, but more quickly than ++ without Chez Scheme. ++ + * Racket is needed to generate the files in the "schemified" + directory from the sources in sibling directories like "../io". The + Racket version must be practically the same as the current Racket +@@ -48,7 +53,6 @@ build: + Unlike Chez Scheme boot files, the files generated in "schemified" + are human-readable and -editable Scheme code. That provides a way + out of bootstrapping black holes, even without BC. +- + + + ======================================================================== +diff --git a/racket/src/cs/c/Makefile.in b/racket/src/cs/c/Makefile.in +index 54a644a1d9..d73993f0fc 100644 +--- a/racket/src/cs/c/Makefile.in ++++ b/racket/src/cs/c/Makefile.in +@@ -12,7 +12,9 @@ CS_HOST_WORKAREA_PREFIX = @CS_HOST_WORKAREA_PREFIX@ + SCHEME_HOST_WORKAREA = $(CS_HOST_WORKAREA_PREFIX)$(SCHEME_WORKAREA) + SCHEME_BIN = $(SCHEME_HOST_WORKAREA)/$(MACH)/bin/$(MACH)/scheme + SCHEME_INC = $(SCHEME_HOST_WORKAREA)/$(MACH)/boot/$(MACH) +-SCHEME = $(SCHEME_BIN) -B $(SCHEME_INC)/petite.boot -B $(SCHEME_INC)/scheme.boot ++SCHEME_built = $(SCHEME_BIN) -B $(SCHEME_INC)/petite.boot -B $(SCHEME_INC)/scheme.boot ++SCHEME_existing = @MAKE_SCHEME_SCHEME@ ++SCHEME = $(SCHEME@USE_SCHEME_MODE@) + + TARGET_MACH = @TARGET_MACH@ + SCHEME_TARGET_INC = $(SCHEME_WORKAREA)/$(TARGET_MACH)/boot/$(TARGET_MACH) +@@ -88,7 +90,7 @@ mainsrcdir = @srcdir@/../.. + @INCLUDEDEP@ @srcdir@/../../version/version.mak + + cs: +- $(MAKE) scheme@T_CROSS_MODE@ ++ $(MAKE) scheme@MAKE_SCHEME_MODE@ + $(MAKE) racket-so + cd rktio; $(MAKE) + $(MAKE) racketcs +@@ -121,9 +123,13 @@ racket-so: + + RACKET_SO_ENV = @CONFIGURE_RACKET_SO_COMPILE@ + ++TARGET_MACH_built = $(TARGET_MACH) ++TARGET_MACH_existing = xc-$(TARGET_MACH) ++XPATCH_FILE = $(SCHEME_WORKAREA)/$(TARGET_MACH@USE_SCHEME_MODE@)/s/xpatch ++ + CS_PROGS = SCHEME="$(SCHEME)" + CS_OPTS = COMPRESS_COMP=@COMPRESS_COMP@ @ENABLE_OR_DISABLE_WPO@ +-CS_OPTScross = $(CS_OPTS) CSO=$(MACH) CROSS_COMP="--xpatch $(SCHEME_WORKAREA)/$(TARGET_MACH)/s/xpatch" ++CS_OPTScross = $(CS_OPTS) CSO=$(MACH) CROSS_COMP="--xpatch $(XPATCH_FILE)" + PASS_COMPILE_DEPS = EXTRA_COMPILE_DEPS="$(SCHEME_INC)/petite.boot $(SCHEME_INC)/scheme.boot" + + build-racket-so: +@@ -163,6 +169,15 @@ pb-bootquick: + cd $(SCHEME_WORKAREA) && $(MAKE) reset + $(SHELL) $(srcdir)/ready_boot.sh $(MACH) $(SCHEME_WORKAREA) + ++scheme-via-scheme: ++ $(MAKE) $(SCHEME_WORKAREA)/boot/$(MACH)/scheme.boot ++ $(MAKE) mach-make ++ ++$(SCHEME_WORKAREA)/boot/$(MACH)/scheme.boot: ++ mkdir -p $(SCHEME_WORKAREA) ++ $(MAKE) config-scheme CONFIG_SCHEME_MODE="$(CONFIG_SCHEME_MODE) --force" ++ cd $(SCHEME_WORKAREA) && $(MAKE) $(MACH).boot Scheme="$(SCHEME)" SCHEMEHEAPDIRS=: o=3 d=0 what=all ++ + mach-make: + $(MAKE) config-scheme + cd $(SCHEME_WORKAREA) && $(MAKE) +@@ -182,24 +197,33 @@ config-scheme: + + scheme-cross: + env MAKE_BOOT_FOR_CROSS=yes SCHEME_SRC="$(SCHEME_DIR)" SCHEME_WORKAREA=$(SCHEME_WORKAREA) MACH="$(TARGET_MACH)" $(BOOTSTRAP_RACKET) "$(SCHEME_DIR)"/rktboot/make-boot.rkt ++ $(MAKE) finish-scheme-cross ++ ++finish-scheme-cross: + $(SHELL) $(srcdir)/reset_boot.sh $(TARGET_MACH) $(SCHEME_WORKAREA) + cd $(SCHEME_WORKAREA) && "$(UP_SCHEME_DIR)"/configure @SCHEME_CROSS_CONFIG_ARGS@ $(SCHEME_CONFIG_VARS) + cd $(SCHEME_WORKAREA)/$(TARGET_MACH)/c && $(CHOST_HACK@T_CROSS_MODE@) $(MAKE) o=o cross=t +- $(MAKE) $(SCHEME_WORKAREA)/$(TARGET_MACH)/s/xpatch ++ $(MAKE) $(XPATCH_FILE) ++ ++scheme-cross-via-scheme: ++ $(MAKE) $(SCHEME_WORKAREA)/boot/$(TARGET_MACH)/scheme.boot MACH=$(TARGET_MACH) ++ $(MAKE) finish-scheme-cross + + # Rebuild patch file and cross "petite.boot" and "scheme.boot" when older +-# than the build-host "scheme.boot" or when "make-boot.rkt" touchs dummy boot files +-XPATCH_DEPS = $(SCHEME_HOST_WORKAREA)/$(MACH)/boot/$(MACH)/scheme.boot \ +- $(SCHEME_WORKAREA)/boot/$(TARGET_MACH)/scheme.boot ++# than the build- use as Racket for build; or "auto" to create +- --enable-scheme= use as host's build directory for cross ++ --enable-scheme= use as host build for cross + --enable-mach= use Chez Scheme machine type + --enable-target= cross-build for Chez Scheme machine type + --enable-portable prefer portable to host-specific +@@ -2867,7 +2870,7 @@ show_explicitly_enabled "${enable_xonx}" "Unix style" + show_explicitly_enabled "${enable_libzo}" 'Compiled ".zo" files moved to lib' + + show_explicitly_set "${enable_racket}" "Racket" +-show_explicitly_set "${enable_scheme}" "Chez Scheme build directory" ++show_explicitly_set "${enable_scheme}" "Chez Scheme for build" + show_explicitly_set "${enable_mach}" "machine type" + show_explicitly_set "${enable_target}" "cross-build machine type" + show_explicitly_enabled "${enable_portable}" "portable" +@@ -4745,9 +4748,21 @@ esac + + SCHEME_DIR=${srcdir}/../../ChezScheme + MAKE_BUILD_SCHEME=checkout ++USE_SCHEME_MODE="_built" ++MAKE_SCHEME_MODE="${T_CROSS_MODE}" + + if test "${enable_scheme}" != "" ; then +- CS_HOST_WORKAREA_PREFIX="${enable_scheme}/" ++ if test -d "${enable_scheme}" ; then ++ # Directory exists, so use it as a build directory ++ echo "Using supplied Scheme path as a build directory" ++ CS_HOST_WORKAREA_PREFIX="${enable_scheme}/" ++ else ++ # Directory does not exist, so assume it's an executable ++ echo "Using supplied Scheme path as an executable" ++ MAKE_SCHEME_MODE="${T_CROSS_MODE}-via-scheme" ++ MAKE_SCHEME_SCHEME="${enable_scheme}" ++ USE_SCHEME_MODE="_existing" ++ fi + fi + + if test "${enable_racket}" != "" ; then +@@ -6012,6 +6027,9 @@ SCHEME_CROSS_CONFIG_ARGS="--machine=${TARGET_MACH} --disable-x11 ${cs_auto_flags + + + ++ ++ ++ + + + +diff --git a/racket/src/cs/c/configure.ac b/racket/src/cs/c/configure.ac +index 464ebe1760..aaee88156d 100644 +--- a/racket/src/cs/c/configure.ac ++++ b/racket/src/cs/c/configure.ac +@@ -23,7 +23,7 @@ AC_ARG_ENABLE(compressmore, [ --enable-compressmore compress compiled code ev + AC_ARG_ENABLE(compressboot, [ --enable-compressboot compress boot files]) + m4_include(../ac/path_arg.m4) + AC_ARG_ENABLE(racket, [ --enable-racket= use as Racket for build; or "auto" to create]) +-AC_ARG_ENABLE(scheme, [ --enable-scheme= use as host's build directory for cross]) ++AC_ARG_ENABLE(scheme, [ --enable-scheme= use as host build for cross]) + AC_ARG_ENABLE(mach, [ --enable-mach= use Chez Scheme machine type ]) + AC_ARG_ENABLE(target, [ --enable-target= cross-build for Chez Scheme machine type ]) + m4_include(../ac/portable_arg.m4) +@@ -81,7 +81,7 @@ show_explicitly_disabled "${enable_compressboot}" "Compressed boot files" + show_explicitly_enabled "${enable_xonx}" "Unix style" + m4_include(../ac/path_show.m4) + show_explicitly_set "${enable_racket}" "Racket" +-show_explicitly_set "${enable_scheme}" "Chez Scheme build directory" ++show_explicitly_set "${enable_scheme}" "Chez Scheme for build" + show_explicitly_set "${enable_mach}" "machine type" + show_explicitly_set "${enable_target}" "cross-build machine type" + m4_include(../ac/portable_show.m4) +@@ -504,9 +504,21 @@ esac + + SCHEME_DIR=${srcdir}/../../ChezScheme + MAKE_BUILD_SCHEME=checkout ++USE_SCHEME_MODE="_built" ++MAKE_SCHEME_MODE="${T_CROSS_MODE}" + + if test "${enable_scheme}" != "" ; then +- CS_HOST_WORKAREA_PREFIX="${enable_scheme}/" ++ if test -d "${enable_scheme}" ; then ++ # Directory exists, so use it as a build directory ++ echo "Using supplied Scheme path as a build directory" ++ CS_HOST_WORKAREA_PREFIX="${enable_scheme}/" ++ else ++ # Directory does not exist, so assume it's an executable ++ echo "Using supplied Scheme path as an executable" ++ MAKE_SCHEME_MODE="${T_CROSS_MODE}-via-scheme" ++ MAKE_SCHEME_SCHEME="${enable_scheme}" ++ USE_SCHEME_MODE="_existing" ++ fi + fi + + if test "${enable_racket}" != "" ; then +@@ -821,6 +833,9 @@ AC_SUBST(DIFF_MACH) + AC_SUBST(CROSS_MODE) + AC_SUBST(T_CROSS_MODE) + AC_SUBST(TT_CROSS_MODE) ++AC_SUBST(MAKE_SCHEME_MODE) ++AC_SUBST(MAKE_SCHEME_SCHEME) ++AC_SUBST(USE_SCHEME_MODE) + AC_SUBST(SETUP_BOOT_MODE) + AC_SUBST(OSX) + AC_SUBST(NOT_OSX) +-- +2.32.0 + From patchwork Sun Feb 13 21:51:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37231 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 2CEFD27BBEA; Sun, 13 Feb 2022 21:55:10 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id EADD027BBE9 for ; Sun, 13 Feb 2022 21:55:09 +0000 (GMT) Received: from localhost ([::1]:57702 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMpp-0006Bw-3o for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:09 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43424) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMon-0005eV-Sn for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:06 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45187) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMon-0001uV-Iu for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMon-0003Eb-IZ for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 09/11] gnu: chez-mit: Support chez-scheme-for-racket. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:05 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478921312315 (code B ref 53878); Sun, 13 Feb 2022 21:54:05 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:33 +0000 Received: from localhost ([127.0.0.1]:39073 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMoH-0003CS-Ij for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:33 -0500 Received: from mail-qk1-f177.google.com ([209.85.222.177]:40888) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMo8-0003Bo-HU for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:24 -0500 Received: by mail-qk1-f177.google.com with SMTP id o25so12986533qkj.7 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ZRi6asVXV+QTTkm+7nvM8RjAeYcMCR/ik7tKnX79K+k=; b=D9ElHnIfUqET0Zw4Uib32IqeQb3gmR5v5cDifIOP6pU1LcUzXkv4H+NPPF4KQiPXlw ul4DRBzLOsv+d+Ld5LQ31RU85M5r86DptHV5OgCwYWq3myv7pTgtOTD4NGLjPKpVXnQd 3jDSFOYidEGIlReXyFEAzrH30j2PEKb/JPdqRG1bYdnhmdGYAEWyL4GXRlIFoSfNHl9z vU0RsATyYsDA8H8Dbk8Uzc0s/ubNoOehxbFA6pKAhc/BWBKjgv8Zl+p3hwfxMOSIaxZg /gDIGy16w8Nhvga19gxu712SYb3nLiruMnWpynLtgsAA92BS8pCe6xEWebXYEp3alGS2 Yuyw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ZRi6asVXV+QTTkm+7nvM8RjAeYcMCR/ik7tKnX79K+k=; b=whkijgWgPo/PXfIuFyj9Het+xshqR62KhTi0wQrYR0N47x3OG1eh8Il42l+T2Krbej fAiWNlsyR7RtkGuPGbPmA+5lKXPiHZjUQVQh4dA3PoYqRMKxMnzUGQ+b9Y/Zt7iZ6RLC tf9CO38erUXksjzKr5iDykO4lPrOoRf2YvFekPdi+5A95DCOsX8jY1qnQ9SQ2TfISZjt KRK5Sz+r/uUYtKSOWlU5uqSwbv9YOz544ASwGev326KSDNruqSSFR2fdG2O0NsCloM+9 PYhlu4TsoBP5CPruZd5hlR8HhsmBH8kadrKEaihnsK7NkCu0I/GcNMNwUxkluGvxiZzK /B8g== X-Gm-Message-State: AOAM531LGvtdvdZJAT09sludDgOVUZCMIyXq4JRKoLuDvSDmbsDNus7P 6nSDUJN+HXVCD/g3fn0FZGpSfmElD6Lqg8shlr4= X-Google-Smtp-Source: ABdhPJydaC1tj/XqIc+8GwBmEDB0n+ZOObxcStbVA0YniesG7fdgTwrQqRT1wccnVzq41R2Ma1rEoA== X-Received: by 2002:a05:620a:44d4:: with SMTP id y20mr5774041qkp.33.1644789199035; Sun, 13 Feb 2022 13:53:19 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id v22sm16517456qta.60.2022.02.13.13.53.18 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:53:18 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:25 -0500 Message-Id: <20220213215127.218952-10-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches Racket's variant of Chez Scheme defines 'string->uninterned-symbol', which conflicts with the definition from '(chez mit)'. See discussion at . * gnu/packages/chez.scm (chez-mit)[origin]: Add workaround for chez-scheme-for-racket. --- gnu/packages/chez.scm | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/gnu/packages/chez.scm b/gnu/packages/chez.scm index 54bbee7923..be251798c3 100644 --- a/gnu/packages/chez.scm +++ b/gnu/packages/chez.scm @@ -355,7 +355,29 @@ (define-public chez-mit (commit (string-append "v" version)))) (sha256 (base32 "0c7i3b6i90xk96nmxn1pc9272a4yal4v40dm1a4ybdi87x53zkk0")) - (file-name (git-file-name name version)))) + (file-name (git-file-name name version)) + (snippet + ;; Workaround for chez-scheme-for-racket. + ;; See: https://github.com/racket/racket/issues/4151 + #~(begin + (use-modules (guix build utils)) + (substitute* "mit/core.sls" + (("[(]import ") + "(import (only (chezscheme) import)\n") + (("[(]define string->uninterned-symbol gensym[)]") + (format #f "~s" + '(begin + (import (only (chezscheme) + meta-cond + library-exports)) + (meta-cond + ((memq 'string->uninterned-symbol + (library-exports '(chezscheme))) + (import (only (chezscheme) + string->uninterned-symbol))) + (else + (define string->uninterned-symbol + gensym))))))))))) (build-system gnu-build-system) (inputs (list chez-srfi)) ; for tests From patchwork Sun Feb 13 21:51:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37230 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 0D08127BBEA; Sun, 13 Feb 2022 21:55:04 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-2.7 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 72FEC27BBE9 for ; Sun, 13 Feb 2022 21:55:03 +0000 (GMT) Received: from localhost ([::1]:57132 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMph-0005mF-Ji for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:01 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43428) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMoo-0005el-8X for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:06 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45188) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMon-0001uf-VB for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMon-0003Ei-VM for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:05 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 10/11] gnu: chez-and-racket-bootstrap: Add 'chez-scheme-for-system'. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:05 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478921412322 (code B ref 53878); Sun, 13 Feb 2022 21:54:05 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:34 +0000 Received: from localhost ([127.0.0.1]:39075 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMoH-0003Cf-Tf for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:34 -0500 Received: from mail-qv1-f43.google.com ([209.85.219.43]:46820) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMoC-0003C0-RE for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:29 -0500 Received: by mail-qv1-f43.google.com with SMTP id n6so13388614qvk.13 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=zzxndLd3++TU95/ksnJc3+VlU1VVJv9zyyVyQPYh0hg=; b=kLH5CC0xtuNDih0aqSpqQMRiqpBmIJ4WinnDbf4nl53ku6q5kaZ7fNtbblb0tIOQEP Hs0zxRjspAP05bW7HyKleOENt2ShKYXxH6Vv1Phz7zm4ws1bo79YZqCLcOf4NBZsAG1y BtQbxF4FxKY0UpGqzUw8A0Xa6qKGQDpFX2gFZrIxaXfERTTTnoY5nu/WebUttm9iV0i4 jHrnoTMN0K8ob4PrrV/9waMqGfDpDmeuLa83oh52u7dX3fdif0a9Adaq/4+Yz8bGhzUH 6rouGze6wlcehlHohi9WXLn9IrSVlUmp+9W8p/rT8Xm/dTWC85Qamh0snf4FsD5aw3DI nbKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zzxndLd3++TU95/ksnJc3+VlU1VVJv9zyyVyQPYh0hg=; b=GnZHfgWbqB4DSUuKZQRr3evgWUhiKOAcYqvMUuOkuRI+Dyli4KadGv8kiKOTqo8GCX 7dacBcSEI4RUjNAYdQfK1G4fSUt3mVt7Z8joREKNe6pvREbrKUPtjgXcTJj0vAKAudQY rjKOjoO6pJ+ypP3+bY69CTKAasuRwOXS9Bp4p6oSSylXD7sCr6cyuF2+e+1gcPwr5Pn8 GcMLB07EOVXci6Pd8AkmjdHchhhJturV2EbMot1f+UGhLKwxn+EjQoErJ+PJ4GN28T6M 8SP2dMy+z78lnitC0lVzUD/4aTLDp5EUI1KBCUUOydnxD00cnbo3Kv288TLIeCGktsTC /cWg== X-Gm-Message-State: AOAM531Prkz9dJq5M6CRoYEo72FglLZtfL+D0TaJfkAWCGc8lk4tzZSw m+oycQneU5zq2o7HSOiEmihSjvHVTeVhL2PhSMQ= X-Google-Smtp-Source: ABdhPJyCR4sKTUrsFbxTFLXJZgv9fCkNgf5UsWd7wZToGnRoBlCoPs7rOeg4aOeL/oHZN9ow4gu/eg== X-Received: by 2002:ad4:5941:: with SMTP id eo1mr1220236qvb.45.1644789203080; Sun, 13 Feb 2022 13:53:23 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id x21sm2282445qtp.67.2022.02.13.13.53.22 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:53:22 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:26 -0500 Message-Id: <20220213215127.218952-11-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/packages/chez-and-racket-bootstrap.scm (chez-scheme-for-system): New procedure. * gnu/packages/loko.scm (loko-scheme): Use 'chez-scheme-for-system'. * gnu/packages/emacs-xyz.scm (emacs-geiser-chez): Likewise * gnu/packages/chez.scm (chez-srfi): (chez-web): (chez-sockets): (chez-matchable): (chez-irregex): (chez-fmt): (chez-mit): (chez-scmutils): Likewise. --- gnu/packages/chez-and-racket-bootstrap.scm | 13 ++++++++++++- gnu/packages/chez.scm | 16 ++++++++-------- gnu/packages/emacs-xyz.scm | 2 +- gnu/packages/loko.scm | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index d2f78dfae2..669c54729d 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -45,7 +45,8 @@ (define-module (gnu packages chez-and-racket-bootstrap) #:use-module (gnu packages tex) #:use-module (gnu packages xorg) #:use-module ((guix licenses) - #:prefix license:)) + #:prefix license:) + #:export (chez-scheme-for-system)) ;; Commentary: ;; @@ -205,6 +206,16 @@ (define-module (gnu packages chez-and-racket-bootstrap) ;; ;; Code: +(define* (chez-scheme-for-system #:optional + (system (or (%current-target-system) + (%current-system)))) + "Return 'chez-scheme' if it supports SYSTEM without restrictions; +'chez-scheme-racket-variant' otherwise." + (if (and=> (nix-system->chez-machine system) + chez-machine->upstream-restriction) + chez-scheme-for-racket + chez-scheme)) + (define (chez-machine->unthreaded mach) "Given a string MACH naming a Chez Scheme machine type, returns a string naming the unthreaded machine type for the same architecture and OS as MACH. diff --git a/gnu/packages/chez.scm b/gnu/packages/chez.scm index be251798c3..d5007e0cfd 100644 --- a/gnu/packages/chez.scm +++ b/gnu/packages/chez.scm @@ -74,7 +74,7 @@ (define-public chez-srfi (file-name (git-file-name name version)))) (build-system gnu-build-system) (native-inputs - (list chez-scheme)) + (list (chez-scheme-for-system))) (arguments (list #:make-flags (chez-make-flags name version) #:test-target "test" @@ -105,7 +105,7 @@ (define-public chez-web (base32 "1dq25qygyncbfq4kwwqqgyyakfqjwhp5q23vrf3bff1p66nyfl3b")))) (build-system gnu-build-system) (native-inputs - (list chez-scheme + (list (chez-scheme-for-system) ghostscript ;; FIXME: This package fails to build with the error: ;; mktexpk: don't know how to create bitmap font for bchr8r @@ -170,7 +170,7 @@ (define-public chez-sockets (base32 "1n5fbwwz51fdzvjackgmnsgh363g9inyxv7kmzi0469cwavwcx5m")))) (build-system gnu-build-system) (native-inputs - (list chez-scheme + (list (chez-scheme-for-system) chez-web (texlive-updmap.cfg (list texlive-pdftex)))) (arguments @@ -256,7 +256,7 @@ (define-public chez-matchable (inputs (list chez-srfi)) ; for tests (native-inputs - (list chez-scheme)) + (list (chez-scheme-for-system))) (arguments (list #:make-flags (chez-make-flags name version) #:test-target "test" @@ -288,7 +288,7 @@ (define-public chez-irregex (propagated-inputs (list chez-srfi)) ; for irregex-utils (native-inputs - (list chez-scheme)) + (list (chez-scheme-for-system))) (arguments (list #:make-flags (chez-make-flags name version) #:test-target "test" @@ -319,7 +319,7 @@ (define-public chez-fmt (propagated-inputs (list chez-srfi)) ; for irregex-utils (native-inputs - (list chez-scheme)) + (list (chez-scheme-for-system))) (arguments (list #:make-flags (chez-make-flags name version) #:test-target "chez-check" @@ -382,7 +382,7 @@ (define string->uninterned-symbol (inputs (list chez-srfi)) ; for tests (native-inputs - (list chez-scheme)) + (list (chez-scheme-for-system))) (arguments (list #:make-flags (chez-make-flags name version) #:test-target "test" @@ -413,7 +413,7 @@ (define-public chez-scmutils (inputs (list chez-srfi)) ; for tests (native-inputs - (list chez-scheme)) + (list (chez-scheme-for-system))) (propagated-inputs (list chez-mit chez-srfi)) (arguments diff --git a/gnu/packages/emacs-xyz.scm b/gnu/packages/emacs-xyz.scm index 02694b636a..f445ab0f25 100644 --- a/gnu/packages/emacs-xyz.scm +++ b/gnu/packages/emacs-xyz.scm @@ -451,7 +451,7 @@ (define-public emacs-geiser-chez (string-append "(eval-after-load 'geiser-impl '" all ")")))))))) (inputs - (list chez-scheme)) + (list (chez-scheme-for-system))) (propagated-inputs (list emacs-geiser)) (home-page "https://nongnu.org/geiser/") diff --git a/gnu/packages/loko.scm b/gnu/packages/loko.scm index 74a649b8a1..a7ab12a0c4 100644 --- a/gnu/packages/loko.scm +++ b/gnu/packages/loko.scm @@ -71,7 +71,7 @@ (define-public loko-scheme #t))))) (native-inputs `(("akku" ,akku) - ("chez-scheme" ,chez-scheme) + ("chez-scheme" ,(chez-scheme-for-system)) ("struct" ,guile-struct-pack) ("laesare" ,guile-laesare) ("pfds" ,guile-pfds) From patchwork Sun Feb 13 21:51:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Philip McGrath X-Patchwork-Id: 37237 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 1893527BBEA; Sun, 13 Feb 2022 21:56:03 +0000 (GMT) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id 1E69227BBE9 for ; Sun, 13 Feb 2022 21:55:53 +0000 (GMT) Received: from localhost ([::1]:59004 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nJMqV-00073B-Ad for patchwork@mira.cbaines.net; Sun, 13 Feb 2022 16:55:51 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43444) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nJMp3-0005mf-Av for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:23 -0500 Received: from debbugs.gnu.org ([209.51.188.43]:45189) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nJMoo-0001um-TO for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:14 -0500 Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nJMoo-0003Eq-PT for guix-patches@gnu.org; Sun, 13 Feb 2022 16:54:06 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#53878] [PATCH 11/11] gnu: racket: Update to 8.4. Resent-From: Philip McGrath Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 13 Feb 2022 21:54:06 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 53878 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 53878@debbugs.gnu.org Cc: Liliana Marie Prikler , Philip McGrath Received: via spool by 53878-submit@debbugs.gnu.org id=B53878.164478922112344 (code B ref 53878); Sun, 13 Feb 2022 21:54:06 +0000 Received: (at 53878) by debbugs.gnu.org; 13 Feb 2022 21:53:41 +0000 Received: from localhost ([127.0.0.1]:39077 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMoP-0003D1-Bm for submit@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:41 -0500 Received: from mail-qk1-f172.google.com ([209.85.222.172]:35416) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nJMoM-0003CY-Si for 53878@debbugs.gnu.org; Sun, 13 Feb 2022 16:53:39 -0500 Received: by mail-qk1-f172.google.com with SMTP id 200so13028879qki.2 for <53878@debbugs.gnu.org>; Sun, 13 Feb 2022 13:53:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philipmcgrath.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=/hZBy6HUA7KdRbSzAale2OMOdr/JyowG+AEK/cK3F+s=; b=P5iCuEc5W+u7r+y2JvEIjebfpI1eBczjYVgheFxh5+MBFiawInD1d+K857Hmbp/5lr GKx0gHRE69Zc3BB9zcVjM+5JhtPzcf0qwL+fwaurpdKLnEN6PUNKK9ugR3RYzbx2K7HC 6bTj1PkRwL1W+XBOslTVBVNEkggZmB6VsJwJ0TcQ9gwKbN7zjVcZnT8itsRFeKqSsG1Z ODXsnYNd7oU6CzEwhqbvh5goru1HwOK0UOk7ndakTINlcHVc31KDS1dGAJoZjn2V05Tp HK49yctVRCEeL5sO5CVcQ8RAr3+guT/uVbLQIRPMb94udXu2C0205cHoRVDicxb5IGd1 FF+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/hZBy6HUA7KdRbSzAale2OMOdr/JyowG+AEK/cK3F+s=; b=JiTxK8hFZ/BLRvaKVnNzPxDsRReMxI1fqQDGm238AS+iysVhpBUPef10m+9QkQ1cQ+ 2HS5fa4mhwF1xH6K2YnFWN+MLwkAL9IJqJN8WP5dg8wGZlU5n8PXt8LKJYn/37XWiFBz zUCW2OKekBQgRP5ZsUCeTPvdnP6woGIcQZ2me3JXtB0OlvrxGn0VPzKGRKt7zPpObzRe CHLy7kALDzSyNNRxK6aKT/5kZtrHXmfzIPa9WBt6Ve7QI6yT66mjI2+IgEa0NkXodXll zb+QSU4BJZHCj+hLqXCGWCbqCTbhH53AKxKt/zHv7RgDbWRVr/yRBEC52xE11syBxp7U 0L8g== X-Gm-Message-State: AOAM533YZiUIbleodljlGubOihL8dgqUR6iXFW/XY92Hr5Xl2Gg6GXWR jR94QUmS9ccvfZYYsNzfSmEBGzmGLQnFmxv4NuI= X-Google-Smtp-Source: ABdhPJxBD4R0h9sTxbML3pDtCrRunX8QnNdlzs64vhnKSMjAK88pzS0yyxyBmcN0gJcN1f8RMLQljQ== X-Received: by 2002:a37:6393:: with SMTP id x141mr5749019qkb.197.1644789210864; Sun, 13 Feb 2022 13:53:30 -0800 (PST) Received: from localhost (c-73-125-98-51.hsd1.fl.comcast.net. [73.125.98.51]) by smtp.gmail.com with UTF8SMTPSA id i12sm15592937qkn.83.2022.02.13.13.53.26 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Feb 2022 13:53:28 -0800 (PST) From: Philip McGrath Date: Sun, 13 Feb 2022 16:51:27 -0500 Message-Id: <20220213215127.218952-12-philip@philipmcgrath.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20220213215127.218952-1-philip@philipmcgrath.com> References: <20220213215127.218952-1-philip@philipmcgrath.com> MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: "Guix-patches" X-getmail-retrieved-from-mailbox: Patches * gnu/packages/patches/racket-gui-tethered-launcher-backport.patch, gnu/packages/patcheches/racket-srfi-fsdg-backport.patch: New patches. * gnu/local.mk (dist_patch_DATA): Add them. * gnu/packages/chez-and-racket-bootstrap.scm (racket-vm-for-system): New procedure. * gnu/packages/racket.scm (racket-minimal, racket): Update to 8.4. Rewrite to use 'racket-vm-for-system', label-less inputs, G-expressions, and Git origins for main-distribution packages. --- gnu/local.mk | 4 +- gnu/packages/chez-and-racket-bootstrap.scm | 11 +- ...acket-gui-tethered-launcher-backport.patch | 26 + .../patches/racket-srfi-fsdg-backport.patch | 41622 ++++++++++++++++ gnu/packages/racket.scm | 1551 +- 5 files changed, 42688 insertions(+), 526 deletions(-) create mode 100644 gnu/packages/patches/racket-gui-tethered-launcher-backport.patch create mode 100644 gnu/packages/patches/racket-srfi-fsdg-backport.patch diff --git a/gnu/local.mk b/gnu/local.mk index 8ffdd15ee2..ff72ad8565 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -41,7 +41,7 @@ # Copyright © 2020 Vinicius Monego # Copyright © 2021 Björn Höfling # Copyright © 2021 Greg Hogan -# Copyright © 2021 Philip McGrath +# Copyright © 2021, 2022 Philip McGrath # Copyright © 2021 Arun Isaac # Copyright © 2021 Sharlatan Hellseher # Copyright © 2021 Dmitry Polyakov @@ -1788,7 +1788,9 @@ dist_patch_DATA = \ %D%/packages/patches/rpcbind-CVE-2017-8779.patch \ %D%/packages/patches/rtags-separate-rct.patch \ %D%/packages/patches/racket-enable-scheme-backport.patch \ + %D%/packages/patches/racket-gui-tethered-launcher-backport.patch \ %D%/packages/patches/racket-minimal-sh-via-rktio.patch \ + %D%/packages/patches/racket-srfi-fsdg-backport.patch \ %D%/packages/patches/remake-impure-dirs.patch \ %D%/packages/patches/restic-0.9.6-fix-tests-for-go1.15.patch \ %D%/packages/patches/retroarch-LIBRETRO_DIRECTORY.patch \ diff --git a/gnu/packages/chez-and-racket-bootstrap.scm b/gnu/packages/chez-and-racket-bootstrap.scm index 669c54729d..89e659a397 100644 --- a/gnu/packages/chez-and-racket-bootstrap.scm +++ b/gnu/packages/chez-and-racket-bootstrap.scm @@ -46,7 +46,8 @@ (define-module (gnu packages chez-and-racket-bootstrap) #:use-module (gnu packages xorg) #:use-module ((guix licenses) #:prefix license:) - #:export (chez-scheme-for-system)) + #:export (chez-scheme-for-system + racket-vm-for-system)) ;; Commentary: ;; @@ -216,6 +217,14 @@ (define* (chez-scheme-for-system #:optional chez-scheme-for-racket chez-scheme)) +(define* (racket-vm-for-system #:optional + (system (or (%current-target-system) + (%current-system)))) + "Return 'racket-vm-cs' if it supports SYSTEM; 'racket-vm-bc' otherwise." + (if (nix-system->chez-machine system) + racket-vm-cs + racket-vm-bc)) + (define (chez-machine->unthreaded mach) "Given a string MACH naming a Chez Scheme machine type, returns a string naming the unthreaded machine type for the same architecture and OS as MACH. diff --git a/gnu/packages/patches/racket-gui-tethered-launcher-backport.patch b/gnu/packages/patches/racket-gui-tethered-launcher-backport.patch new file mode 100644 index 0000000000..1e018eaa79 --- /dev/null +++ b/gnu/packages/patches/racket-gui-tethered-launcher-backport.patch @@ -0,0 +1,26 @@ +From aa792e707b1fbc5cc33691bfaee5828dc3fbebaa Mon Sep 17 00:00:00 2001 +From: Matthew Flatt +Date: Mon, 31 Jan 2022 15:31:22 -0700 +Subject: [PATCH] fix creation of tethered launchers + +Related to racket/racket#4133 + +(cherry picked from commit 563c68432f127729592f234ef30c31e92618b517) +--- + gui-lib/mred/installer.rkt | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/gui-lib/mred/installer.rkt b/gui-lib/mred/installer.rkt +index b1691472..9ef06c53 100644 +--- a/gui-lib/mred/installer.rkt ++++ b/gui-lib/mred/installer.rkt +@@ -72,4 +72,5 @@ + (list "-A" (path->string (find-system-path 'addon-dir))))) + + (define (config-flags) +- (list "-G" (path->string (find-config-dir)))) ++ (list "-X" (path->string (find-collects-dir)) ++ "-G" (path->string (find-config-dir)))) +-- +2.32.0 + diff --git a/gnu/packages/patches/racket-srfi-fsdg-backport.patch b/gnu/packages/patches/racket-srfi-fsdg-backport.patch new file mode 100644 index 0000000000..75a5f46960 --- /dev/null +++ b/gnu/packages/patches/racket-srfi-fsdg-backport.patch @@ -0,0 +1,41622 @@ +From 82076308af8aeda65283ba83779302304e1a25d1 Mon Sep 17 00:00:00 2001 +From: Philip McGrath +Date: Thu, 20 Jan 2022 01:20:04 -0500 +Subject: [PATCH] Backport FSDG fix for Racket 8.4. + +This is a squashed and somewhat reduced version of commits +46e11b7, 48f8fca, and a2d0199. For detailed discussion, see + and +. +--- + srfi-doc/info.rkt | 10 +- + .../srfi/scribblings/srfi-5-doc-free.scrbl | 164 + + srfi-doc/srfi/scribblings/srfi-std/index.html | 351 +- + .../srfi/scribblings/srfi-std/racket-srfi.css | 87 + + .../srfi/scribblings/srfi-std/srfi-1.html | 2893 ++++++++++------- + .../srfi/scribblings/srfi-std/srfi-11.html | 103 +- + .../srfi/scribblings/srfi-std/srfi-13.html | 2072 +++++++----- + .../srfi/scribblings/srfi-std/srfi-14.html | 1533 +++++---- + .../srfi/scribblings/srfi-std/srfi-16.html | 101 +- + .../srfi/scribblings/srfi-std/srfi-17.html | 137 +- + .../srfi/scribblings/srfi-std/srfi-19.html | 863 ++--- + .../srfi/scribblings/srfi-std/srfi-2.html | 180 +- + .../srfi/scribblings/srfi-std/srfi-23.html | 131 +- + .../srfi/scribblings/srfi-std/srfi-25.html | 188 +- + .../srfi/scribblings/srfi-std/srfi-26.html | 408 ++- + .../srfi/scribblings/srfi-std/srfi-27.html | 695 ++-- + .../srfi/scribblings/srfi-std/srfi-28.html | 78 +- + .../srfi/scribblings/srfi-std/srfi-29.html | 88 +- + .../srfi/scribblings/srfi-std/srfi-30.html | 121 +- + .../srfi/scribblings/srfi-std/srfi-31.html | 338 +- + .../srfi/scribblings/srfi-std/srfi-34.html | 230 +- + .../srfi/scribblings/srfi-std/srfi-35.html | 222 +- + .../srfi/scribblings/srfi-std/srfi-38.html | 207 +- + .../srfi/scribblings/srfi-std/srfi-39.html | 278 +- + .../srfi/scribblings/srfi-std/srfi-4.html | 277 +- + .../srfi/scribblings/srfi-std/srfi-40.html | 232 +- + .../scribblings/srfi-std/srfi-41/srfi-41.html | 2116 ++++++------ + .../srfi/scribblings/srfi-std/srfi-42.html | 2205 +++++++------ + .../srfi/scribblings/srfi-std/srfi-43.html | 1049 +++--- + .../srfi/scribblings/srfi-std/srfi-45.html | 303 +- + .../srfi/scribblings/srfi-std/srfi-48.html | 535 +-- + .../srfi/scribblings/srfi-std/srfi-54.html | 179 +- + .../srfi/scribblings/srfi-std/srfi-57.html | 458 +-- + .../srfi/scribblings/srfi-std/srfi-59.html | 314 +- + .../srfi/scribblings/srfi-std/srfi-6.html | 156 +- + .../srfi/scribblings/srfi-std/srfi-60.html | 998 +++--- + .../srfi/scribblings/srfi-std/srfi-61.html | 64 +- + .../srfi/scribblings/srfi-std/srfi-62.html | 130 +- + .../srfi/scribblings/srfi-std/srfi-63.html | 1586 ++++----- + .../srfi/scribblings/srfi-std/srfi-64.html | 408 +-- + .../srfi/scribblings/srfi-std/srfi-66.html | 335 +- + .../srfi/scribblings/srfi-std/srfi-69.html | 346 +- + .../srfi/scribblings/srfi-std/srfi-7.html | 124 +- + .../srfi/scribblings/srfi-std/srfi-71.html | 274 +- + .../srfi/scribblings/srfi-std/srfi-74.html | 485 ++- + .../srfi/scribblings/srfi-std/srfi-78.html | 445 +-- + .../srfi/scribblings/srfi-std/srfi-8.html | 77 +- + .../srfi/scribblings/srfi-std/srfi-86.html | 202 +- + .../srfi/scribblings/srfi-std/srfi-87.html | 118 +- + .../srfi/scribblings/srfi-std/srfi-9.html | 223 +- + .../srfi/scribblings/srfi-std/srfi-98.html | 137 +- + srfi-doc/srfi/scribblings/srfi.scrbl | 70 +- + srfi-doc/srfi/scribblings/util.rkt | 17 + + srfi-lib/info.rkt | 2 + + srfi-lib/srfi/5/let.rkt | 83 +- + srfi-test/tests/srfi/5/srfi-5-test.rkt | 163 +- + srfi/info.rkt | 6 +- + 57 files changed, 14542 insertions(+), 11053 deletions(-) + create mode 100644 srfi-doc/srfi/scribblings/srfi-5-doc-free.scrbl + create mode 100644 srfi-doc/srfi/scribblings/srfi-std/racket-srfi.css + +diff --git a/srfi-doc/info.rkt b/srfi-doc/info.rkt +index 59d9611..2ce76b3 100644 +--- a/srfi-doc/info.rkt ++++ b/srfi-doc/info.rkt +@@ -2,20 +2,18 @@ + + (define collection 'multi) + ++(define version "1.1") ++ + (define build-deps '("mzscheme-doc" + "scheme-lib" + "base" + "scribble-lib" + "srfi-lib" + "racket-doc" +- "r5rs-doc" +- "r6rs-doc" ++ "racket-index" + "compatibility-lib")) + +-(define deps '("scheme-lib" +- "base" +- "scribble-lib" +- "compatibility-lib")) ++(define deps '("base")) + + (define update-implies '("srfi-lib")) + +diff --git a/srfi-doc/srfi/scribblings/srfi-5-doc-free.scrbl b/srfi-doc/srfi/scribblings/srfi-5-doc-free.scrbl +new file mode 100644 +index 0000000..5ecf3af +--- /dev/null ++++ b/srfi-doc/srfi/scribblings/srfi-5-doc-free.scrbl +@@ -0,0 +1,164 @@ ++#lang scribble/doc ++@(require "util.rkt" ++ scribble/manual ++ scribble/example ++ scriblib/render-cond ++ scribble/core ++ scribble/html-properties ++ (for-syntax scheme/base) ++ (for-label (except-in scheme/base let) ++ srfi/5 ++ racket/stream)) ++ ++@title[#:tag "srfi-5" #:style 'unnumbered]{ ++ SRFI 5: A compatible let form with signatures and rest arguments} ++@defmodule[srfi/5] ++ ++@begin[ ++ (define-syntax-rule (defrkt rkt-let) ++ (begin ++ (require (for-label racket/base)) ++ (define rkt-let (racket let)))) ++ (defrkt rkt-let) ++ (define reference-doc ++ '(lib "scribblings/reference/reference.scrbl")) ++ (define guide-doc ++ '(lib "scribblings/guide/guide.scrbl")) ++ (define srfi-nf-doc ++ '(lib "srfi/scribblings/srfi-nf.scrbl")) ++ ] ++ ++Original specification: ++@seclink[#:indirect? #t #:doc srfi-nf-doc srfi-5-std-taglet]{SRFI 5} ++ ++For @hyperlink[srfi-license-history-url]{historical ++ reasons}, the SRFI 5 specification document has a ++@seclink[#:indirect? #t #:doc srfi-nf-doc srfi-5-license-taglet]{ ++ restrictive license} and is not included in the main Racket distribution. ++ ++The implementation in @racketmodname[srfi/5] and this ++documentation are distributed under the same ++@racket-license-link{license} as Racket: only the original ++specification document is restrictively licensed. ++ ++@defform*[[(let ([id init-expr] ...) ++ body ...+) ++ (let ([id init-expr] ...+ rest-binding) ++ body ...+) ++ (let loop-id ([id init-expr] ... maybe-rest-binding) ++ body ...+) ++ (let (loop-id [id init-expr] ... maybe-rest-binding) ++ body ...+)] ++ #:grammar ++ ([maybe-rest-binding code:blank rest-binding] ++ [rest-binding (code:line rest-id rest-init-expr ...)])]{ ++ ++ Like @rkt-let from @racketmodname[racket/base], but ++ extended to support additional variants of ++ @tech[#:doc reference-doc]{named @rkt-let}. ++ ++ As with @rkt-let from @racketmodname[racket/base], SRFI 5's ++ @racket[let] form conceptually expands to the immediate ++ application of a function to the values of the ++ @racket[init-expr]s: the @racket[id]s are bound in the ++ @racket[body]s (but not in any @racket[init-expr]s or ++ @racket[rest-init-expr]s), and @racket[loop-id], if present, ++ is bound in the @racket[body]s to the function itself, ++ allowing it to be used recursively. An @racket[id] or a ++ @racket[rest-id] can shadow @racket[loop-id], but the ++ @racket[rest-id] (if given) and all @racket[is]s much be ++ distinct. ++ ++ SRFI 5's @racket[let] adds support for a syntax like ++ @racket[define]'s @seclink[#:doc guide-doc "Function_Shorthand"]{ ++ function shorthand}, which allows the bindings to be written in a ++ syntax resembling an application of the function bound to ++ @racket[loop-id]. ++ ++ Additionally, SRFI 5's @racket[let] adds support for ++ @tech[#:doc guide-doc]{rest arguments}. If a ++ @racket[rest-id] is present, the function bound to ++ @racket[loop-id] (or the conceptual anonymous function, if ++ @racket[loop-id] is not used) will accept an unlimited ++ number of additional arguments after its required ++ by-position arguments, and the @racket[rest-id] will be ++ bound in the @racket[body]s (but not in any ++ @racket[init-expr]s or @racket[rest-init-expr]s) to a list ++ of those additional arguments. The values of the ++ @racket[rest-init-expr]s are supplied as arguments to the ++ initial, implicit application when the @racket[let] form is ++ evaluated, so the initial value bound to @racket[rest-id] is ++ @racket[(list rest-init-expr ...)]. ++ ++ @margin-note{Unlike the @racket[_kw-formals] of ++ @racket[lambda] and @racket[define] or the @racket[_formals] ++ of @racket[case-lambda], the bindings of SRFI 5's ++ @racket[let], with or without a @racket[rest-binding], are ++ always a proper (syntactic) list.} ++ ++ A @racket[rest-binding] can be used with both the ++ @racket[define]-like and the ++ @tech[#:doc reference-doc]{named-@rkt-let}--like variants of ++ @racket[let]. It is also possible to use @racket[rest-id] ++ without any @racket[loop-id]; however, as specified in the ++ grammar, at least one @racket[id]--@racket[init-expr] pair ++ is required in that case. (Otherwise, there would be an ++ ambiguity with the @racket[define]-like variant). ++ ++ @examples[ ++ #:eval (make-base-eval '(require srfi/5)) #:once ++ (code:comment "define-like bindings") ++ (define (factorial n) ++ (let (fact [n n] [acc 1]) ++ (if (zero? n) ++ acc ++ (fact (sub1 n) (* n acc))))) ++ (eval:check (factorial 5) 120) ++ (eval:check (factorial 11) 39916800) ++ (code:comment "rest arguments with named-let--like bindings") ++ (eval:check (let reverse-onto ([lst '(a b c)] ++ tail) ++ (if (null? lst) ++ tail ++ (apply reverse-onto (cdr lst) (car lst) tail))) ++ '(c b a)) ++ (eval:check (let reverse-onto ([lst '(a b c)] ++ tail 'x 'y 'z) ++ (if (null? lst) ++ tail ++ (apply reverse-onto (cdr lst) (car lst) tail))) ++ '(c b a x y z)) ++ (eval:check (let no-evens (lst 1 2 3 4 5) ++ (cond ++ [(null? lst) ++ '()] ++ [(even? (car lst)) ++ (apply no-evens (cdr lst))] ++ [else ++ (cons (car lst) (apply no-evens (cdr lst)))])) ++ '(1 3 5)) ++ (code:comment "rest arguments with define-like bindings") ++ (eval:check (let (reverse-onto [lst '(a b c)] tail) ++ (if (null? lst) ++ tail ++ (apply reverse-onto (cdr lst) (car lst) tail))) ++ '(c b a)) ++ (eval:check (let (reverse-onto [lst '(a b c)] . [tail 'x 'y 'z]) ++ (if (null? lst) ++ tail ++ (apply reverse-onto (cdr lst) (car lst) tail))) ++ '(c b a x y z)) ++ (eval:check (let (loop [continue? 0] args 'a 'a1 'a2) ++ (case continue? ++ [(0) (cons args (loop 1 'b))] ++ [(1) (cons args (loop 2 'c 'd))] ++ [else (list args)])) ++ '((a a1 a2) (b) (c d))) ++ (code:comment "rest arguments without any loop-id") ++ (eval:check (let ([x 1] ++ [y 2] ++ z 3 4 5 6 7) ++ (list* x y z)) ++ '(1 2 3 4 5 6 7)) ++ ] ++} +diff --git a/srfi-doc/srfi/scribblings/srfi-std/index.html b/srfi-doc/srfi/scribblings/srfi-std/index.html +index 6f03f9b..c46dd8b 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/index.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/index.html +@@ -1,258 +1,113 @@ +- +- ++ ++ ++ + ++ + SRFI documents inside Racket ++ ++ + +- + +

SRFI documents inside Racket

+- +-

Scheme Requests for Implementation

+- +-

The "Scheme Requests for Implementation" (SRFI) process +- is a new approach to helping Scheme users to write portable and +- yet useful code. It is a forum for people interested in +- coordinating libraries and other additions to the Scheme language +- between implementations.

+- +-

This manual includes the original documentation of all +- the SRFIs already ported to Racket. For more information on +- the SRFI process, please follow +- this link.

+- +- +-

Loading

+- +-

To load a SRFI with name conflicts (currently SRFIs 1, 5, 13, 17, 19, 43, +- 45, 48, 61, 63, 69 and 87) in a module,
+- please see the note below.
+-
+- To load a SRFI, use the following form:
+-
+-     (require srfi/N)
+-
+- if you know the number of the SRFI you want to load. This is the preferred +- method. Alternatively, use this one:
+-
+-     (require srfi/N/NAME)
+-
+- if you know the `informative name' of the SRFI.
+-
+- N, is a number corresponding to the sub-collection that holds a particular +- SRFI, and NAME is a more descriptive name we assigned to the main file in +- which the SRFI is defined. For instance, to load SRFI-34 you have to do +- either one of:
+-
+-     (require srfi/34)
+-
+- or,
+-
+-     (require srfi/34/exception)
+-
+-

+- +- +

+- NOTE on SRFIs with name conflicts
+-

+- Certain SRFIs (currently SRFIs 1, 5, 13, 17, 19, 43, 45, 48, 61, 63, 69 and +- 87) provide names which conflict with names provided by the racket +- language. Attempting to require one of these SRFIs in a module written in +- the racket language will result in an error.
+-
+- To address this problem, the Racket implementations of these SRFIs provide a +- different module which renames the problematic exports to avoid these +- conflicts. For SRFI 1, this library is called list, and should be +- required like this:
+-
+-     (require srfi/1/list)
+-
+- which supplies the colliding names with a prefix of 's:' (e.g. "s:map", +- "s:reverse!") and is therefore suitable for requires in a module.
+-
+- For SRFI 19, this library is called time, and should be required like +- this:
+-
+-     (require srfi/19/time)
+-
+- which supplies the colliding names with a prefix of 'srfi:' (e.g. +- "srfi:date?", "srfi:date-second") and is therefore
+- suitable for requires in a module.
+-
++ The information that used to be on this page has moved to ++ ../index.html. +

+- +- +

+- Supported SRFIs
++ If you do nothing, you should be redirected in five seconds. +

+- +- +-

SRFI           File +- name           +- Sub-collection
+- SRFI-1         list.rkt             +- 1
+- SRFI-2         and-let.rkt          +- 2
+- SRFI-4(*1)     4.rkt
+- SRFI-5         let.rkt              +- 5
+- SRFI-6(+)      6.rkt
+- SRFI-7         program.rkt          +- 7
+- SRFI-8         receive.rkt          +- 8
+- SRFI-9         record.rkt           +- 9
+- SRFI-11(+)     11.rkt
+- SRFI-13        string.rkt           +- 13
+- SRFI-14        char-set.rkt         +- 14
+- SRFI-16(+)     16.rkt
+- SRFI-17        set.rkt              +- 17
+- SRFI-19(*2)    time.rkt             +- 19
+- SRFI-23(+)     23.rkt
+- SRFI-25        array.rkt            +- 25
+- SRFI-26        cut.rkt              +- 26
+- SRFI-27        random-bits.rkt      +- 27
+- SRFI-28(+)     28.rkt
+- SRFI-29        localization.rkt     +- 29
+- SRFI-30(+)     30.rkt
+- SRFI-31        rec.rkt              +- 31
+- SRFI-32        sort.scm            +- 32
+- SRFI-34        exception.rkt        +- 34
+- SRFI-35        condition.rkt        +- 35
+- SRFI-38(+)     38.rkt
+- SRFI-39(+)     39.rkt
+- SRFI-40        stream.rkt           +- 40
+- SRFI-42        comprehensions.rkt   +- 42
+- SRFI-43        vector-lib.rkt       +- 43
+- SRFI-45(*3)    lazy.rkt             +- 45
+- SRFI-48        format.rkt           +- 48
+- SRFI-54        cat.rkt              +- 54
+- SRFI-57        records.rkt          +- 57
+- SRFI-59        vicinity.rkt         +- 59
+- SRFI-60        60.rkt               +- 60
+- SRFI-61        cond.rkt             +- 61
+- SRFI-62(+)
+- SRFI-63        63.rkt               +- 63
+- SRFI-64        testing.rkt          +- 64
+- SRFI-66        66.rkt               +- 66
+- SRFI-67        compare.rkt          +- 67
+- SRFI-69        hash.rkt             +- 69
+- SRFI-71        letvalues.rkt        +- 71
+- SRFI-74        74.rkt               +- 74
+- SRFI-78        check.rkt            +- 78
+- SRFI-86        86.rkt               +- 86
+- SRFI-87        case.rkt             +- 87
+-

+- +- +-

Notes:

+- +- +-

+ Supported by the Racket core
+-
+- *1 The functionality is all part of racket available +- via (require ffi/unsafe), the only missing part is the i/o +- syntax.
+-
+- *2 The time module does not export its time structure +- (you have to use the time-* procedures.) It renames all +- the date-* accessors to tm:date-* so that you won't get +- errors when including this code in other modules. Care +- most be taken NOT to confuse the internal date structure +- with the Racket one, they are not the same, and all +- procedures from this library expect the former.
+-
+- *3 This port also provides promise? / srfi-45-promise?.
+-

+- +- +-

Ported SRFIs: original documents

+- +- +- +- ++ + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/racket-srfi.css b/srfi-doc/srfi/scribblings/srfi-std/racket-srfi.css +new file mode 100644 +index 0000000..661e2cb +--- /dev/null ++++ b/srfi-doc/srfi/scribblings/srfi-std/racket-srfi.css +@@ -0,0 +1,87 @@ ++/* ++ This is a substitute for "srfi.css" from ++ https://github.com/scheme-requests-for-implementation/srfi-common ++*/ ++@import "../../scribble.css"; ++@import "../../manual-style.css"; ++@import "../../manual-racket.css"; ++/* NB doc-site.css is imported at the end of this file */ ++ ++a.eponymous { ++ /* based on upstream srfi.css */ ++ font-family: 'Fira-Mono', monospace; ++ overflow-wrap: break-word; ++ word-break: break-all; ++ word-wrap: break-word; ++} ++body > p:first-of-type { ++ /* this is the SRFI author */ ++ font-family: 'Fira', sans-serif; ++ font-size: 1.3em; ++} ++body { ++ /* like .maincolumn from manual-style.css */ ++ width: auto; ++ margin-top: 4rem; ++ margin-left: 17rem; ++ margin-right: 2rem; ++ margin-bottom: 10rem; /* to avoid fixed bottom nav bar */ ++ max-width: 700px; ++ min-width: 370px; /* below this size, code samples don't fit */ ++} ++@media (max-width:720px) { ++ /* adapt to narrow screens, like .maincolumn in manual-style.css */ ++ body { ++ margin-left: 1em; ++ margin-top: 7rem; ++ margin-bottom: 0rem; ++ } ++} ++.refpara.racket-srfi-note .refcolumn { ++ /* Overrides @media rule to put .refcolumn in the margin on wide ++ screens. This is necessary because some SRFIs (e.g. 14) include ++ inline stylesheets that interfere with the way it tries to use ++ `float`. ++ */ ++ margin: inherit; ++ float: inherit; ++ clear: inherit; ++ width: inherit; ++} ++h1 { ++ /* like h2 from manual-style.css */ ++ font-family: 'Cooper-Hewitt'; ++ font-size: 2.3rem; ++ font-weight: bold; ++ line-height: 1.2; ++ width: 90%; ++} ++h2 { ++ /* like h3 -- h8 in manual-style.css */ ++ margin-top: 2em; ++ padding-top: 0.1em; ++ margin-bottom: 0.75em; ++ font-size: 2rem; ++} ++h3, h4, h5, h6, h7, h8 { ++ border: none; ++} ++span.antispam { ++ display: none; ++} ++pre, dl, dd, ol, ul { ++ /* like p from manual-style.css */ ++ margin-bottom: 1em; ++} ++li { ++ /* slightly tighter than p */ ++ margin-bottom: 0.6em; ++} ++.srfi-plt-extension { ++ /* like the background color for .boxed (blue boxes), ++ but without the gradient */ ++ background-color: hsl(216, 78%, 95%); ++} ++ ++/* Goes last, so it can override everything. */ ++@import "../../doc-site.css"; +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-1.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-1.html +index 773c03b..f1ccc40 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-1.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-1.html +@@ -1,24 +1,41 @@ +- +- ++ ++ ++ ++ ++ + +- + +- +- +- +- ++ ++ ++ ++ + SRFI 1: List Library + + + + +- + + + + + +-

Title

+-SRFI-1: List Library +-
+- +- +-

Author

++

SRFI 1: List Library

+ +-Olin Shivers +- +-
+- http://www.ai.mit.edu/~shivers/ / +- shivers@ai.mit.edu +-
++

by Olin Shivers

++

This copy of the SRFI 1 specification document ++is distributed as part of the Racket package ++srfi-doc.

The canonical source of this document is ++https://srfi.schemers.org/srfi-1/srfi-1.html.

+ + +-

Status

+- +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

+-

    +-
  • Received: 1998/11/08
  • +-
  • Draft: 1998/12/22-1999/03/09
  • +-
  • Revised: several times
  • +-
  • Final: 1999/10/09
  • +-
++

Status

++ ++

This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-1 @nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

++
    ++
  • Received: 1998-11-08
  • ++
  • Draft: 1998-12-22--1999-03-09
  • ++
  • Revised: several times
  • ++
  • Final: 1999-10-09
  • ++
  • Revised to fix errata: ++
      ++
    • 2016-08-27 (Clarify Booleans.)
    • ++
    • 2018-10-08 (Remove extra parenthesis.)
    • ++
    • 2019-10-25 (Fix broken links.)
    • ++
    • 2020-06-02 (Add note ++ about order of arguments to lset=.)
    • ++
    ++
  • ++
+ + +-

Table of contents

++

Table of contents

+ + +-
    +-
  • Abstract +-
  • Rationale +-
  • Procedure index +-
  • General discussion +- +-
  • The procedures +- +-
  • Acknowledgements +-
  • References & links +-
  • Copyright ++ + + + +-

    Abstract

    ++

    Abstract

    +

    + R5RS Scheme has an impoverished set of list-processing utilities, which is a + problem for authors of portable code. This SRFI proposes a coherent and + comprehensive set of list-processing procedures; it is accompanied by a + reference implementation of the spec. The reference implementation is ++

    +
      +-
    • portable +-
    • efficient +-
    • completely open, public-domain source ++
    • portable
    • ++
    • efficient
    • ++
    • completely open, public-domain source
    • +
    + + +-

    Rationale

    ++

    Rationale

    +

    + The set of basic list and pair operations provided by R4RS/R5RS Scheme is far + from satisfactory. Because this set is so small and basic, most +@@ -220,7 +245,7 @@ implementations provide additional utilities, such as a list-filtering + function, or a "left fold" operator, and so forth. But, of course, this + introduces incompatibilities -- different Scheme implementations provide + different sets of procedures. +- ++

    +

    + I have designed a full-featured library of procedures for list processing. + While putting this library together, I checked as many Schemes as I could get +@@ -228,43 +253,47 @@ my hands on. (I have a fair amount of experience with several of these + already.) I missed Chez -- no on-line manual that I can find -- but I hit most + of the other big, full-featured Schemes. The complete list of list-processing + systems I checked is: +-

    +- R4RS/R5RS Scheme, MIT Scheme, Gambit, RScheme, MzScheme, slib, ++

    ++
    ++ R4RS/R5RS Scheme, MIT Scheme, Gambit, RScheme, MzScheme, slib, + Common Lisp, Bigloo, guile, T, APL and the SML standard basis +
    +

    + As a result, the library I am proposing is fairly rich. ++

    +

    + Following this initial design phase, this library went through several + months of discussion on the SRFI mailing lists, and was altered in light + of the ideas and suggestions put forth during this discussion. ++

    +

    + In parallel with designing this API, I have also written a reference + implementation. I have placed this source on the Net with an unencumbered, + "open" copyright. A few notes about the reference implementation: +- ++

    +
      +
    • Although I got procedure names and specs from many Schemes, I wrote this +- code myself. Thus, there are no entanglements. ++ code myself. Thus, there are no entanglements. + Any Scheme implementor + can pick this library up with no worries about copyright problems -- both + commercial and non-commercial systems. + +-
    • The code is written for portability and should be trivial to port to ++
    • The code is written for portability and should be trivial to port to + any Scheme. It has only four deviations from R4RS, clearly discussed + in the comments:
        +
      • Use of an error procedure; +-
      • Use of the R5RS values and a simple receive macro for producing ++
      • Use of the R5RS values and a simple receive macro for producing + and consuming multiple return values; +-
      • Use of simple :optional and let-optionals macros for optional ++
      • Use of simple :optional and let-optionals macros for optional + argument parsing and defaulting; +-
      • Use of a simple check-arg procedure for argument checking. +-
      ++
    • Use of a simple check-arg procedure for argument checking. ++
    + +-
  • It is written for clarity and well-commented. The current source is ++
  • It is written for clarity and well-commented. The current source is + 768 lines of source code and 826 lines of comments and white space. + +-
  • It is written for efficiency. Fast paths are provided for common ++
  • ++ It is written for efficiency. Fast paths are provided for common + cases. Side-effecting procedures such as filter! avoid unnecessary, + redundant set-cdr!s which would thrash a generational GC's write barrier + and the store buffers of fast processors. Functions reuse longest common +@@ -272,227 +301,243 @@ implementation. I have placed this source on the Net with an unencumbered, + possible. Constant-space iterations are used in preference to recursions; + local recursions are used in preference to consing temporary intermediate + data structures. +-

    ++

    ++

    + This is not to say that the implementation can't be tuned up for + a specific Scheme implementation. There are notes in comments addressing + ways implementors can tune the reference implementation for performance. +-

++

+

+ In short, I've written the reference implementation to make it as painless + as possible for an implementor -- or a regular programmer -- to adopt this + library and get good results with it. +- ++

+ + +-

Procedure Index

++

Procedure Index

+

+ Here is a short list of the procedures provided by the list-lib package. +-R5RS procedures are shown in +-bold; +-extended R5RS +- procedures, in bold italic. +-

++R5RS procedures are shown in ++bold; ++extended R5RS ++ procedures, in bold italic. ++

++
+
+-
Constructors +-
+-
+-cons list
+-xcons cons* make-list list-tabulate 
++
Constructors ++
++
++cons list
++xcons cons* make-list list-tabulate
+ list-copy circular-list iota
+ 
+ +-
Predicates +-
+-
+-pair? null?
+-proper-list? circular-list? dotted-list? 
++
Predicates ++
++
++pair? null?
++proper-list? circular-list? dotted-list?
+ not-pair? null-list?
+-list=
++list=
+ 
+ +-
Selectors +-
+-
+-car cdr ... cddadr cddddr list-ref
++
Selectors ++
++
++car cdr ... cddadr cddddr list-ref
+ first second third fourth fifth sixth seventh eighth ninth tenth
+-car+cdr
++car+cdr
+ take       drop
+ take-right drop-right
+-take!      drop-right! 
+-split-at   split-at! 
++take!      drop-right!
++split-at   split-at!
+ last last-pair
+ 
+ +-
Miscellaneous: length, append, concatenate, reverse, zip & count +-
+-
+-length length+
+-append  concatenate  reverse
++
Miscellaneous: length, append, concatenate, reverse, zip & count ++
++
++length length+
++append  concatenate  reverse
+ append! concatenate! reverse!
+ append-reverse append-reverse!
+ zip unzip1 unzip2 unzip3 unzip4 unzip5
+ count
+ 
+ +-
Fold, unfold & map +-
+-
+-map for-each
+-fold       unfold       pair-fold       reduce 
+-fold-right unfold-right pair-fold-right reduce-right 
++
Fold, unfold & map ++
++
++map for-each
++fold       unfold       pair-fold       reduce
++fold-right unfold-right pair-fold-right reduce-right
+ append-map append-map!
+ map! pair-for-each filter-map map-in-order
+ 
+ +-
Filtering & partitioning +-
+-
++
Filtering & partitioning ++
++
+ filter  partition  remove
+-filter! partition! remove! 
++filter! partition! remove!
+ 
+ +-
Searching +-
+-
+-member memq memv
+-find find-tail 
++
Searching ++
++
++member memq memv
++find find-tail
+ any every
+ list-index
+ take-while drop-while take-while!
+ span break span! break!
+ 
+ +-
Deleting +-
+-
+-delete  delete-duplicates 
++
Deleting ++
++
++delete  delete-duplicates
+ delete! delete-duplicates!
+ 
+ +-
Association lists +-
+-
+-assoc assq assv
++
Association lists ++
++
++assoc assq assv
+ alist-cons alist-copy
+ alist-delete alist-delete!
+ 
+ +-
Set operations on lists +-
+-
+-lset<= lset= lset-adjoin
++
Set operations on lists ++
++
++lset<= lset= lset-adjoin
+ lset-union			lset-union!
+ lset-intersection		lset-intersection!
+ lset-difference		        lset-difference!
+ lset-xor			lset-xor!
+-lset-diff+intersection	        lset-diff+intersection!
++lset-diff+intersection	        lset-diff+intersection!
+ 
+ +-
Primitive side-effects +-
+-
+-set-car! set-cdr!
++
Primitive side-effects ++
++
++set-car! set-cdr!
+ 
+-
++ +
+ +

+ Four R4RS/R5RS list-processing procedures are extended by this library in + backwards-compatible ways: +-

+- +-
map for-each +- (Extended to take lists of unequal length) +-
member assoc +- (Extended to take an optional comparison procedure.) +-
++

++
++ ++
map for-each ++ (Extended to take lists of unequal length) ++
member assoc ++ (Extended to take an optional comparison procedure.) ++
+
+ +

+ The following R4RS/R5RS list- and pair-processing procedures are also part of + list-lib's exports, as defined by the R5RS: +-

++

++
+
+ cons pair? null?
+-car cdr ... cdddar cddddr 
+-set-car! set-cdr! 
++car cdr ... cdddar cddddr
++set-car! set-cdr!
+ list append reverse
+ length list-ref
+ memq memv assq assv
+ 
+
+- ++ +

+-The remaining two R4RS/R5RS list-processing ++The remaining two R4RS/R5RS list-processing + procedures are not part of + this library: +-

+- +-
list-tail +- (renamed drop) +-
list? +- (see proper-list?, +- circular-list? and ++

++
++ ++
list-tail ++ (renamed drop) ++
list? ++ (see proper-list?, ++ circular-list? and + dotted-list?) +-
++
+
+ + +-

General discussion

++

General discussion

+

+ + A set of general criteria guided the design of this library. + ++

+

+ +-I don't require "destructive" (what I call "linear update") procedures to ++I don't require "destructive" (what I call "linear update") procedures to + alter and recycle cons cells from the argument lists. They are allowed to, but + not required to. (And the reference implementations I have written do + recycle the argument lists.) + ++

+

+ List-filtering procedures such as filter or delete do not disorder + lists. Elements appear in the answer list in the same order as they appear in + the argument list. This constrains implementation, but seems like a desirable + feature, since in many uses of lists, order matters. (In particular, + disordering an alist is definitely a bad idea.) ++

+

+ Contrariwise, although the reference implementations of the list-filtering + procedures share longest common tails between argument and answer lists, + it not is part of the spec. ++

+

+ Because lists are an inherently sequential data structure (unlike, say, + vectors), list-inspection functions such as find, find-tail, for-each, any + and every commit to a left-to-right traversal order of their argument list. ++

+

+ However, constructor functions, such as list-tabulate and the mapping + procedures (append-map, append-map!, map!, pair-for-each, filter-map, + map-in-order), do not specify the dynamic order in which their procedural + argument is applied to its various values. ++

+

+ Predicates return useful true values wherever possible. Thus any must return + the true value produced by its predicate, and every returns the final true + value produced by applying its predicate argument to the last element of its + argument list. ++

+

+ Functionality is provided both in pure and linear-update (potentially + destructive) forms wherever this makes sense. ++

+

+ No special status accorded Scheme's built-in equality functions. + Any functionality provided in terms of eq?, eqv?, equal? is also + available using a client-provided equality function. ++

+

+ Proper design counts for more than backwards compatibility, but I have tried, +-ceteris paribus, ++ceteris paribus, + to be as backwards-compatible as possible with existing + list-processing libraries, in order to facilitate porting old code to run as a + client of the procedures in this library. Name choices and semantics are, for + the most part, in agreement with existing practice in many current Scheme + systems. I have indicated some incompatibilities in the following text. ++

+

+ These procedures are not "sequence generic" -- i.e., procedures that + operate on either vectors and lists. They are list-specific. I prefer to + keep the library simple and focussed. ++

+

+ I have named these procedures without a qualifying initial "list-" lexeme, + which is in keeping with the existing set of list-processing utilities in +@@ -501,9 +546,11 @@ I follow the general Scheme convention (vector-length, string-ref) of + placing the type-name before the action when naming procedures -- so + we have list-copy and pair-for-each rather than the perhaps + more fluid, but less consistent, copy-list or for-each-pair. ++

+

+ I have generally followed a regular and consistent naming scheme, composing + procedure names from a set of basic lexemes. ++

+ + +

"Linear update" procedures

+@@ -520,18 +567,21 @@ of list1 to point to list2, and then + empty list, in which case it would simply return list2). However, append! may + also elect to perform a pure append operation -- this is a legal definition + of append!: +-
++

++
+ (define append! append)
+ 
+

+ This is why we do not call these procedures "destructive" -- because they + aren't required to be destructive. They are potentially destructive. ++

+

+ What this means is that you may only apply linear-update procedures to + values that you know are "dead" -- values that will never be used again + in your program. This must be so, since you can't rely on the value passed + to a linear-update procedure after that procedure has been called. It + might be unchanged; it might be altered. ++

+

+ The "linear" in "linear update" doesn't mean "linear time" or "linear space" + or any sort of multiple-of-n kind of meaning. It's a fancy term that +@@ -542,6 +592,7 @@ bound to no other variable. So when you use a variable in a variable + reference, you "use it up." Knowing that no one else has a pointer to that + value means the a system primitive is free to side-effect its arguments to + produce what is, observationally, a pure-functional result. ++

+

+ In the context of this library, "linear update" means you, the programmer, + know there are no other live references to the value passed to the +@@ -549,11 +600,13 @@ procedure -- after passing the value to one of these procedures, the + value of the old pointer is indeterminate. Basically, you are licensing + the Scheme implementation to alter the data structure if it feels like + it -- you have declared you don't care either way. ++

+

+ You get no help from Scheme in checking that the values you claim are "linear" + really are. So you better get it right. Or play it safe and use the non-! + procedures -- it doesn't do any good to compute quickly if you get the wrong + answer. ++

+

+ Why go to all this trouble to define the notion of "linear update" and use it + in a procedure spec, instead of the more common notion of a "destructive" +@@ -572,16 +625,18 @@ algorithm. Linear-update operations are easily parallelised. Going with a + linear-update spec doesn't close off these valuable alternative implementation + techniques. This list library is intended as a set of low-level, basic + operators, so we don't want to exclude these possible implementations. ++

+

+ The linear-update procedures in this library are +-

++

++
+ take! drop-right! split-at! + append! concatenate! reverse! append-reverse! + append-map! map! +-filter! partition! remove! ++filter! partition! remove! + take-while! span! break! + delete! alist-delete! delete-duplicates! +-lset-adjoin! lset-union! lset-intersection! ++lset-adjoin! lset-union! lset-intersection! + lset-difference! lset-xor! lset-diff+intersection! +
+ +@@ -597,26 +652,33 @@ treat these trees as lists. Further complications ensue from the fact that + Scheme allows side-effects to these tuples, raising the possibility of lists + of unbounded length, and trees of unbounded depth (that is, circular data + structures). +- ++

+

+ However, there is a simple view of the world of Scheme values that considers + every value to be a list of some sort. that is, every value is either ++

+
    +-
  • a "proper list" -- a finite, nil-terminated list, such as:
    +- (a b c)
    +- ()
    +- (32)
    +-
  • a "dotted list" -- a finite, non-nil terminated list, such as:
    +- (a b c . d)
    +- (x . y)
    +- 42
    +- george
    +-
  • or a "circular list" -- an infinite, unterminated list. ++
  • ++ a "proper list" -- a finite, nil-terminated list, such as:
    ++ (a b c)
    ++ ()
    ++ (32)
    ++
  • ++
  • ++ a "dotted list" -- a finite, non-nil terminated list, such as:
    ++ (a b c . d)
    ++ (x . y)
    ++ 42
    ++ george
    ++
  • ++
  • ++ or a "circular list" -- an infinite, unterminated list. ++
  • +
+

+ Note that the zero-length dotted lists are simply all the non-null, non-pair + values. +- ++

+

+ This view is captured by the predicates proper-list?, dotted-list?, and + circular-list?. List-lib users should note that dotted lists are not commonly +@@ -624,7 +686,7 @@ used, and are considered by many Scheme programmers to be an ugly artifact of + Scheme's lack of a true list type. However, dotted lists do play a noticeable + role in the syntax of Scheme, in the "rest" parameters used by n-ary + lambdas: (lambda (x y . rest) ...). +- ++

+

+ Dotted lists are not fully supported by list-lib. Most procedures are + defined only on proper lists -- that is, finite, nil-terminated lists. The +@@ -632,8 +694,9 @@ procedures that will also handle circular or dotted lists are specifically + marked. While this design decision restricts the domain of possible arguments + one can pass to these procedures, it has the benefit of allowing the + procedures to catch the error cases where programmers inadvertently pass +-scalar values to a list procedure by accident, ++scalar values to a list procedure by accident, + e.g., by switching the arguments to a procedure call. ++

+ + +

Errors

+@@ -645,6 +708,7 @@ do that." They are not a guarantee that a conforming implementation will + Regrettably, R5RS Scheme requires no firmer guarantee even for basic operators such + as car and cdr, so there's little point in requiring these procedures to do + more. Here is the relevant section of the R5RS: ++

+
+

+ When speaking of an error situation, this report uses the phrase "an +@@ -654,209 +718,235 @@ more. Here is the relevant section of the ++

+ For example, it is an error for a procedure to be passed an argument + that the procedure is not explicitly specified to handle, even though + such domain errors are seldom mentioned in this report. + Implementations may extend a procedure's domain of definition to + include such arguments. +-

++

+ + + +

Not included in this library

+

+ The following items are not in this library: ++

+
    +
  • Sort routines +-
  • Destructuring/pattern-matching macro +-
  • Tree-processing routines +-
++
  • Destructuring/pattern-matching macro ++
  • Tree-processing routines ++
  • +

    + They should have their own SRFI specs. +-

    ++

    + + + +-

    The procedures

    ++

    The procedures

    +

    + + In a Scheme system that has a module or package system, these procedures + should be contained in a module named "list-lib". +- ++

    ++

    + The templates given below obey the following conventions for procedure formals: ++

    + +- +-
    list +- A proper (finite, nil-terminated) list +-
    clist +- A proper or circular list +-
    flist +- A finite (proper or dotted) list +-
    pair +- A pair +-
    x, y, d, a +- Any value +-
    object, value +- Any value +-
    n, i +- A natural number (an integer >= 0) +-
    proc +- A procedure +-
    pred +- A procedure whose return value is treated as a boolean +-
    = +- A boolean procedure taking two arguments +-
    ++ list ++ A proper (finite, nil-terminated) list ++ clist ++ A proper or circular list ++ flist ++ A finite (proper or dotted) list ++ pair ++ A pair ++ ++ x, y, d, a ++ Any value ++ object, value ++ Any value ++ n, i ++ A natural number (an integer >= 0) ++ proc ++ A procedure ++ pred ++ A procedure whose return value is treated as a boolean ++ = ++ A boolean procedure taking two arguments ++ + +

    + It is an error to pass a circular or dotted list to a procedure not + defined to accept such an argument. +- ++

    + +-

    Constructors

    +-

    ++

    Constructors

    ++ + +
    + + +-
    ++
    + +-cons a d -> pair +-
    ++cons a d -> pair ++ ++
    ++

    + [R5RS] +- The primitive constructor. Returns a newly allocated pair whose car is +- a and whose cdr is d. ++ The primitive constructor. Returns a newly allocated pair whose car is ++ a and whose cdr is d. + The pair is guaranteed to be different (in the sense of eqv?) + from every existing object. +-

    +-(cons 'a '())        => (a)
    +-(cons '(a) '(b c d)) => ((a) b c d)
    +-(cons "a" '(b c))    => ("a" b c)
    +-(cons 'a 3)          => (a . 3)
    +-(cons '(a b) 'c)     => ((a b) . c)
    ++

    ++
    ++(cons 'a '())        => (a)
    ++(cons '(a) '(b c d)) => ((a) b c d)
    ++(cons "a" '(b c))    => ("a" b c)
    ++(cons 'a 3)          => (a . 3)
    ++(cons '(a b) 'c)     => ((a b) . c)
    + 
    +- ++
    + +-
    ++
    + +-list object ... -> list +-
    ++list object ... -> list ++ ++
    ++

    + [R5RS] + Returns a newly allocated list of its arguments. +-

    +-(list 'a (+ 3 4) 'c) =>  (a 7 c)
    +-(list)               =>  ()
    ++

    ++
    ++(list 'a (+ 3 4) 'c) =>  (a 7 c)
    ++(list)               =>  ()
    + 
    +- ++
    + +-
    ++
    + +-xcons d a -> pair +-
    ++xcons d a -> pair ++ ++
    +
    + (lambda (d a) (cons a d))
    + 
    +- Of utility only as a value to be conveniently passed to higher-order ++

    ++ Of utility only as a value to be conveniently passed to higher-order + procedures. +- +-

    ++

    ++
    + (xcons '(b c) 'a) => (a b c)
    + 
    +- ++

    + The name stands for "eXchanged CONS." +- ++

    ++
    + +- +-
    cons* elt1 elt2 ... -> object +-
    +- +- Like list, ++
    cons* elt1 elt2 ... -> object ++
    ++
    ++

    ++ Like list, + but the last argument provides the tail of the constructed list, + returning +-

    ++

    ++
    + (cons elt1 (cons elt2 (cons ... eltn))) +
    +- This function is called list* in Common Lisp and about ++

    ++ This function is called list* in Common Lisp and about + half of the Schemes that provide it, + and cons* in the other half. +-

    ++

    ++
    + (cons* 1 2 3 4) => (1 2 3 . 4)
    + (cons* 1) => 1
    + 
    +- ++
    + +- +-
    make-list n [fill] -> list +-
    +- Returns an n-element list, ++
    make-list n [fill] -> list ++
    ++
    ++

    ++ Returns an n-element list, + whose elements are all the value fill. + If the fill argument is not given, the elements of the list may + be arbitrary values. +-

    ++

    ++
    + (make-list 4 'c) => (c c c c)
    + 
    +- ++
    + +- +-
    list-tabulate n init-proc -> list +-
    ++
    list-tabulate n init-proc -> list ++
    ++
    ++

    + Returns an n-element list. Element i of the list, where 0 <= i < n, + is produced by (init-proc i). No guarantee is made about the dynamic + order in which init-proc is applied to these indices. +- +-

    ++

    ++
    + (list-tabulate 4 values) => (0 1 2 3)
    + 
    +- ++
    + +- +-
    list-copy flist -> flist +-
    ++
    list-copy flist -> flist ++
    ++
    ++

    + Copies the spine of the argument. +- ++

    ++
    + +- +-
    circular-list elt1 elt2 ... -> list +-
    ++
    circular-list elt1 elt2 ... -> list ++
    ++
    ++

    + Constructs a circular list of the elements. +-

    ++

    ++
    + (circular-list 'z 'q) => (z q z q z q ...)
    + 
    +- ++
    + +- +-
    iota count [start step] -> list +-
    ++
    iota count [start step] -> list ++
    ++
    ++

    + Returns a list containing the elements +-

    ++

    ++
    + (start start+step ... start+(count-1)*step)
    + 
    ++

    + The start and step parameters default to 0 and 1, respectively. + This procedure takes its name from the APL primitive. +- +-

    ++

    ++
    + (iota 5) => (0 1 2 3 4)
    + (iota 5 0 -0.1) => (0 -0.1 -0.2 -0.3 -0.4)
    + 
    ++
    +
    + + +@@ -864,240 +954,282 @@ defined to accept such an argument. +

    + Note: the predicates proper-list?, circular-list?, and dotted-list? + partition the entire universe of Scheme values. +- ++

    +
    + +-
    +-proper-list? x -> boolean ++
    ++proper-list? x -> boolean + +-
    ++ ++
    ++

    + Returns true iff x is a proper list -- a finite, nil-terminated list. ++

    +

    +- More carefully: The empty list is a proper list. A pair whose cdr is a ++ More carefully: The empty list is a proper list. A pair whose cdr is a + proper list is also a proper list: ++

    +
    + <proper-list> ::= ()                            (Empty proper list)
    +               |   (cons <x> <proper-list>)      (Proper-list pair)
    + 
    ++

    + Note that this definition rules out circular lists. This + function is required to detect this case and return false. ++

    +

    + Nil-terminated lists are called "proper" lists by R5RS and Common Lisp. + The opposite of proper is improper. ++

    +

    + R5RS binds this function to the variable list?. +-

    ++

    +
    + (not (proper-list? x)) = (or (dotted-list? x) (circular-list? x))
    + 
    +- ++
    + +- +-
    circular-list? x -> boolean +-
    ++
    circular-list? x -> boolean ++
    ++
    ++

    + True if x is a circular list. A circular list is a value such that + for every n >= 0, cdrn(x) is a pair. ++

    +

    + Terminology: The opposite of circular is finite. ++

    +
    + (not (circular-list? x)) = (or (proper-list? x) (dotted-list? x))
    + 
    +- ++
    + +- +-
    dotted-list? x -> boolean +-
    ++
    dotted-list? x -> boolean ++
    ++
    ++

    + True if x is a finite, non-nil-terminated list. That is, there exists +- an n >= 0 such that cdrn(x) is neither a pair nor (). ++ an n >= 0 such that cdrn(x) is neither a pair nor (). + This includes +- non-pair, non-() values (e.g. symbols, numbers), ++ non-pair, non-() values (e.g. symbols, numbers), + which are considered to be dotted lists of length 0. ++

    +
    + (not (dotted-list? x)) = (or (proper-list? x) (circular-list? x))
    + 
    +- ++
    + +- +-
    pair? object -> boolean +-
    ++
    pair? object -> boolean ++
    ++
    ++

    + [R5RS] + Returns #t if object is a pair; otherwise, #f. +-

    +-(pair? '(a . b)) =>  #t
    +-(pair? '(a b c)) =>  #t
    +-(pair? '())      =>  #f
    +-(pair? '#(a b))  =>  #f
    +-(pair? 7)        =>  #f
    +-(pair? 'a)       =>  #f
    ++

    ++
    ++(pair? '(a . b)) =>  #t
    ++(pair? '(a b c)) =>  #t
    ++(pair? '())      =>  #f
    ++(pair? '#(a b))  =>  #f
    ++(pair? 7)        =>  #f
    ++(pair? 'a)       =>  #f
    + 
    +- ++
    + +- +-
    null? object -> boolean +-
    ++
    null? object -> boolean ++
    ++
    ++

    + [R5RS] + Returns #t if object is the empty list; otherwise, #f. +- ++

    ++
    + +- +-
    null-list? list -> boolean +-
    ++
    null-list? list -> boolean ++
    ++
    ++

    + List is a proper or circular list. This procedure returns true if + the argument is the empty list (), and false otherwise. It is an + error to pass this procedure a value which is not a proper or + circular list. +- +- This procedure is recommended as the termination condition for ++

    ++

    ++ This procedure is recommended as the termination condition for + list-processing procedures that are not defined on dotted lists. +- ++

    ++
    + +-
    ++
    + +-not-pair? x -> boolean +-
    +-
    (lambda (x) (not (pair? x)))
    ++not-pair? x -> boolean ++ ++
    ++
    (lambda (x) (not (pair? x)))
    ++

    + Provided as a procedure as it can be useful as the termination condition + for list-processing procedures that wish to handle all finite lists, + both proper and dotted. +- ++

    ++
    + +-
    ++
    + +-list= elt= list1 ... -> boolean +-
    ++list= elt= list1 ... -> boolean ++ ++
    ++

    + Determines list equality, given an element-equality procedure. +- Proper list A equals proper list B ++ Proper list A equals proper list B + if they are of the same length, +- and their corresponding elements are equal, +- as determined by elt=. ++ and their corresponding elements are equal, ++ as determined by elt=. + If the element-comparison procedure's first argument is +- from listi, +- then its second argument is from listi+1, ++ from listi, ++ then its second argument is from listi+1, + i.e. it is always called as + (elt= a b) +- for a an element of list A, ++ for a an element of list A, + and b an element of list B. ++

    +

    +- In the n-ary case, +- every listi is compared to +- listi+1 +- (as opposed, for example, to comparing +- list1 to every listi, +- for i>1). +- If there are no list arguments at all, ++ In the n-ary case, ++ every listi is compared to ++ listi+1 ++ (as opposed, for example, to comparing ++ list1 to every listi, ++ for i>1). ++ If there are no list arguments at all, + list= simply returns true. ++

    +

    + It is an error to apply list= to anything except proper lists. + While + implementations may choose to extend it to circular lists, note that it + cannot reasonably be extended to dotted lists, as it provides no way to + specify an equality procedure for comparing the list terminators. ++

    +

    + Note that the dynamic order in which the elt= procedure is +- applied to pairs of elements is not specified. ++ applied to pairs of elements is not specified. + For example, if list= is applied +- to three lists, A, B, and C, ++ to three lists, A, B, and C, + it may first completely compare A to B, +- then compare B to C, ++ then compare B to C, + or it may compare the first elements of A and B, +- then the first elements of B and C, ++ then the first elements of B and C, + then the second elements of A and B, and so forth. ++

    +

    +- The equality procedure must be consistent with eq?. ++ The equality procedure must be consistent with eq?. + That is, it must be the case that +-

    +- (eq? x y) => (elt= x y). ++

    ++
    ++ (eq? x y) => (elt= x y). +
    +- Note that this implies that two lists which are eq? ++

    ++ Note that this implies that two lists which are eq? + are always list=, as well; implementations may exploit this + fact to "short-cut" the element-by-element comparisons. +-

    +-(list= eq?) => #t       ; Trivial cases
    +-(list= eq? '(a)) => #t
    ++

    ++
    ++(list= eq?) => #t       ; Trivial cases
    ++(list= eq? '(a)) => #t
    + 
    +- ++
    +
    + + + +-

    Selectors

    ++

    Selectors

    +
    + + +- +- +-
    car pair -> value +-
    cdr pair -> value +-
    ++
    car pair -> value ++
    ++
    cdr pair -> value ++
    ++
    ++

    + [R5RS] + These functions return the contents of the car and cdr field of their + argument, respectively. + Note that it is an error to apply them to the empty list. +-

    +-(car '(a b c))     =>  a             (cdr '(a b c))     =>  (b c)  
    +-(car '((a) b c d)) =>  (a)	     (cdr '((a) b c d)) =>  (b c d)
    +-(car '(1 . 2))     =>  1	     (cdr '(1 . 2))     =>  2      
    +-(car '())          =>  *error*	     (cdr '())          =>  *error*
    ++

    ++
    ++(car '(a b c))     =>  a             (cdr '(a b c))     =>  (b c)
    ++(car '((a) b c d)) =>  (a)	     (cdr '((a) b c d)) =>  (b c d)
    ++(car '(1 . 2))     =>  1	     (cdr '(1 . 2))     =>  2
    ++(car '())          =>  *error*	     (cdr '())          =>  *error*
    + 
    +- ++
    + + + +- +- +- +- +-
    caar pair -> value +-
    cadr pair -> value +-
    : +-
    cdddar pair -> value +-
    cddddr pair -> value +-
    ++
    caar pair -> value ++
    ++
    cadr pair -> value ++
    ++
    : ++
    ++
    cddadr pair -> value ++
    ++
    cdddar pair -> value ++
    ++
    cddddr pair -> value ++
    ++
    ++

    + [R5RS] + These procedures are compositions of car and cdr, + where for example caddr could be defined by +-

        
    ++

    ++
    + (define caddr (lambda (x) (car (cdr (cdr x))))).
    + 
    ++

    + Arbitrary compositions, up to four deep, are provided. There are + twenty-eight of these procedures in all. +- ++

    ++
    + +- +-
    list-ref clist i -> value +-
    ++
    list-ref clist i -> value ++
    ++
    ++

    + [R5RS] +- Returns the ith element of clist. +- (This is the same as the car of ++ Returns the ith element of clist. ++ (This is the same as the car of + (drop clist i).) +- It is an error if i >= n, ++ It is an error if i >= n, + where n is the length of clist. +-

        
    +-(list-ref '(a b c d) 2) => c
    +-
    +- ++

    ++
    ++(list-ref '(a b c d) 2) => c
    ++
    ++
    + +-
    ++
    + +-first   pair -> object +-
    ++first   pair -> object ++
    + +-second  pair -> object +-
    ++second  pair -> object ++
    + +-third   pair -> object +-
    ++third   pair -> object ++
    + +-fourth  pair -> object +-
    ++fourth  pair -> object ++
    + +-fifth   pair -> object +-
    ++fifth   pair -> object ++
    + +-sixth   pair -> object +-
    ++sixth   pair -> object ++
    + +-seventh pair -> object +-
    ++seventh pair -> object ++
    + +-eighth  pair -> object +-
    ++eighth  pair -> object ++
    + +-ninth   pair -> object +-
    ++ninth   pair -> object ++
    + +-tenth   pair -> object +-
    +- Synonyms for car, cadr, caddr, ... ++tenth   pair -> object ++
    ++ Synonyms for car, cadr, caddr, ... + +-
    ++
    + (third '(a b c d e)) => c
    + 
    + + +-
    ++
    + +-car+cdr pair -> [x y] +-
    ++car+cdr pair -> [x y] ++
    + The fundamental pair deconstructor: +-
    ++
    + (lambda (p) (values (car p) (cdr p)))
    + 
    + This can, of course, be implemented more efficiently by a compiler. +- ++
    + +-
    ++
    + +-take x i -> list +-
    ++take x i -> list ++
    + +-drop x i -> object +-
    +- take returns the first i elements of list x.
    ++drop x i -> object ++
    ++ take returns the first i elements of list x.
    + drop returns all but the first i elements of list x. +-
    ++
    + (take '(a b c d e)  2) => (a b)
    + (drop '(a b c d e)  2) => (c d e)
    + 
    + x may be any value -- a proper, circular, or dotted list: +-
    ++
    + (take '(1 2 3 . d) 2) => (1 2)
    + (drop '(1 2 3 . d) 2) => (3 . d)
    + (take '(1 2 3 . d) 3) => (1 2 3)
    +@@ -1186,7 +1318,7 @@ partition the entire universe of Scheme values.
    + 
    + For a legal i, take and drop partition the list in a manner which + can be inverted with append: +-
    ++
    + (append (take x i) (drop x i)) = x
    + 
    + drop is exactly equivalent to performing i cdr operations on x; +@@ -1195,114 +1327,138 @@ partition the entire universe of Scheme values. + If the argument is a list of non-zero length, take is guaranteed to + return a freshly-allocated list, even in the case where the entire + list is taken, e.g. (take lis (length lis)). +- ++
    + +-
    ++
    + +-take-right flist i -> object +-
    ++take-right flist i -> object ++
    ++
    + +-drop-right flist i -> list +-
    +- take-right returns the last i elements of flist.
    ++drop-right flist i -> list ++ ++
    ++

    ++ take-right returns the last i elements of flist.
    + drop-right returns all but the last i elements of flist. +-

    ++

    ++
    + (take-right '(a b c d e) 2) => (d e)
    + (drop-right '(a b c d e) 2) => (a b c)
    + 
    ++

    + The returned list may share a common tail with the argument list. ++

    +

    + flist may be any finite list, either proper or dotted: +-

    ++

    ++
    + (take-right '(1 2 3 . d) 2) => (2 3 . d)
    + (drop-right '(1 2 3 . d) 2) => (1)
    + (take-right '(1 2 3 . d) 0) => d
    + (drop-right '(1 2 3 . d) 0) => (1 2 3)
    + 
    +- For a legal i, take-right and drop-right partition the list in a manner ++

    ++ For a legal i, take-right and drop-right partition the list in a manner + which can be inverted with append: +-

    ++

    ++
    + (append (take flist i) (drop flist i)) = flist
    + 
    ++

    + take-right's return value is guaranteed to share a common tail with flist. + + If the argument is a list of non-zero length, drop-right is guaranteed to + return a freshly-allocated list, even in the case where nothing is + dropped, e.g. (drop-right lis 0). +- ++

    ++
    + +-
    ++
    + +-take! x i -> list +-
    ++take! x i -> list ++
    ++
    + +-drop-right! flist i -> list +-
    ++drop-right! flist i -> list ++ ++
    ++

    + take! and drop-right! are "linear-update" variants of take and + drop-right: the procedure is allowed, but not required, to alter the + argument list to produce the result. +-

    ++

    + If x is circular, take! may return a shorter-than-expected list: +-

    ++

    ++
    + (take! (circular-list 1 3 5) 8) => (1 3)
    + (take! (circular-list 1 3 5) 8) => (1 3 5 1 3 5 1 3)
    + 
    +- ++
    + + +-
    ++
    + +-split-at  x i -> [list object] +-
    ++split-at  x i -> [list object] ++
    ++
    + +-split-at! x i -> [list object] +-
    +- split-at splits the list x +- at index i, returning a list of the ++split-at! x i -> [list object] ++ ++
    ++

    ++ split-at splits the list x ++ at index i, returning a list of the + first i elements, and the remaining tail. It is equivalent + to +-

    ++

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

    + split-at! is the linear-update variant. It is allowed, but not + required, to alter the argument list to produce the result. +-

    +-(split-at '(a b c d e f g h) 3) =>
    ++

    ++
    ++(split-at '(a b c d e f g h) 3) =>
    +     (a b c)
    +     (d e f g h)
    + 
    +- ++
    + + +-
    ++
    + +-last pair -> object +-
    ++last pair -> object ++
    ++
    + +-last-pair pair -> pair +-
    +- last returns the last element of the non-empty, ++last-pair pair -> pair ++ ++
    ++

    ++ last returns the last element of the non-empty, + finite list pair. + last-pair returns the last pair in the non-empty, + finite list pair. +- +-

    ++

    ++
    + (last '(a b c)) => c
    + (last-pair '(a b c)) => (c)
    + 
    +- ++
    +
    + + +@@ -1313,174 +1469,208 @@ partition the entire universe of Scheme values. + ==== length+ + ==== length + ============================================================================--> +-
    ++
    + +-length  list -> integer +-
    ++length  list -> integer ++
    ++
    + +-length+ clist -> integer or #f +-
    ++length+ clist -> integer or #f ++ ++
    ++

    + Both length and length+ return the length of the argument. + It is an error to pass a value to length which is not a proper + list (finite and nil-terminated). In particular, this means an + implementation may diverge or signal an error when length is + applied to a circular list. +-

    ++

    ++

    + length+, on the other hand, returns #F when applied to a circular + list. +-

    +- The length of a proper list is a non-negative integer n such that cdr ++

    ++

    ++ The length of a proper list is a non-negative integer n such that cdr + applied n times to the list produces the empty list. +- ++

    ++
    + + +-
    ++
    + +-append  list1 ... -> list +-
    ++append  list1 ... -> list ++
    ++
    + +-append! list1 ... -> list +-
    ++append! list1 ... -> list ++ ++
    ++

    + [R5RS] +- append returns a list consisting of the elements ++ append returns a list consisting of the elements + of list1 + followed by the elements of the other list parameters. +-

    +-(append '(x) '(y))        =>  (x y)
    +-(append '(a) '(b c d))    =>  (a b c d)
    +-(append '(a (b)) '((c)))  =>  (a (b) (c))
    ++

    ++
    ++(append '(x) '(y))        =>  (x y)
    ++(append '(a) '(b c d))    =>  (a b c d)
    ++(append '(a (b)) '((c)))  =>  (a (b) (c))
    + 
    ++

    + The resulting list is always newly allocated, except that it +- shares structure with the final listi argument. +- This last argument may be any value at all; ++ shares structure with the final listi argument. ++ This last argument may be any value at all; + an improper list results if it is not + a proper list. All other arguments must be proper lists. +-

    +-(append '(a b) '(c . d))  =>  (a b c . d)
    +-(append '() 'a)           =>  a
    +-(append '(x y))           =>  (x y)
    +-(append)                  =>  ()
    ++

    ++
    ++(append '(a b) '(c . d))  =>  (a b c . d)
    ++(append '() 'a)           =>  a
    ++(append '(x y))           =>  (x y)
    ++(append)                  =>  ()
    + 
    +- ++

    + append! is the "linear-update" variant of append + -- it is allowed, but not required, to alter cons cells in the argument +- lists to construct the result list. ++ lists to construct the result list. + The last argument is never altered; the result + list shares structure with this parameter. +- ++

    ++
    + +-
    ++
    + +-concatenate  list-of-lists -> value +-
    ++concatenate  list-of-lists -> value ++
    ++
    + +-concatenate! list-of-lists -> value +-
    ++concatenate! list-of-lists -> value ++ ++
    ++

    + These functions append the elements of their argument together. + That is, concatenate returns +-

    ++

    ++
    + (apply append list-of-lists)
    + 
    ++

    + or, equivalently, +-

    ++

    ++
    + (reduce-right append '() list-of-lists)
    + 
    +- ++

    + concatenate! is the linear-update variant, defined in + terms of append! instead of append. +- ++

    +

    + Note that some Scheme implementations do not support passing more than a +- certain number (e.g., 64) of arguments to an n-ary procedure. ++ certain number (e.g., 64) of arguments to an n-ary procedure. + In these implementations, the (apply append ...) idiom +- would fail when applied to long lists, ++ would fail when applied to long lists, + but concatenate would continue to function properly. +- ++

    +

    +- As with append and append!, ++ As with append and append!, + the last element of the input list may be any value at all. +- ++

    ++
    + +-
    ++
    + +-reverse  list -> list +-
    ++reverse  list -> list ++
    ++
    + +-reverse! list -> list +-
    ++reverse! list -> list ++ ++
    ++

    + [R5RS] + + reverse returns a newly allocated list consisting of + the elements of list in reverse order. +-

    +-(reverse '(a b c)) =>  (c b a)
    ++

    ++
    ++(reverse '(a b c)) =>  (c b a)
    + (reverse '(a (b c) d (e (f))))
    +-    =>  ((e (f)) d (b c) a)
    ++    =>  ((e (f)) d (b c) a)
    + 
    ++

    + reverse! is the linear-update variant of reverse. +- It is permitted, but not required, to alter the argument's cons cells ++ It is permitted, but not required, to alter the argument's cons cells + to produce the reversed list. +- ++

    ++
    + + +-
    ++
    + +-append-reverse  rev-head tail -> list +-
    ++append-reverse  rev-head tail -> list ++
    ++
    + +-append-reverse! rev-head tail -> list +-
    ++append-reverse! rev-head tail -> list ++ ++
    ++

    + append-reverse returns + (append (reverse rev-head) tail). + It is provided because it is a common operation -- a common + list-processing style calls for this exact operation to transfer values + accumulated in reverse order onto the front of another list, and because + the implementation is significantly more efficient than the simple +- composition it replaces. (But note that this pattern of iterative +- computation followed by a reverse can frequently be rewritten as a +- recursion, dispensing with the reverse and append-reverse steps, and +- shifting temporary, intermediate storage from the heap to the stack, +- which is typically a win for reasons of cache locality and eager storage ++ composition it replaces. (But note that this pattern of iterative ++ computation followed by a reverse can frequently be rewritten as a ++ recursion, dispensing with the reverse and append-reverse steps, and ++ shifting temporary, intermediate storage from the heap to the stack, ++ which is typically a win for reasons of cache locality and eager storage + reclamation.) ++

    +

    + append-reverse! is just the linear-update variant -- it is allowed, but + not required, to alter rev-head's cons cells to construct the result. +- ++

    ++
    + +- +-
    zip clist1 clist2 ... -> list +-
    ++
    zip clist1 clist2 ... -> list ++
    ++
    +
    (lambda lists (apply map list lists))
    + 
    ++

    + 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) 
    ++

    ++
    ++(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))
    ++

    ++
    ++(zip '(3 1 4 1) (circular-list #f #t))
    ++    => ((3 #f) (1 #t) (4 #f) (1 #t))
    + 
    +- ++
    + +- +-
    unzip1 list -> list +- +-
    unzip2 list -> [list list] +- +-
    unzip3 list -> [list list list] +- +-
    unzip4 list -> [list list list list] +- +-
    unzip5 list -> [list list list list list] +-
    +- unzip1 takes a list of lists, +- where every list must contain at least one element, +- and returns a list containing the initial element of each such list. +- That is, it returns (map car lists). ++
    unzip1 list -> list ++
    ++
    unzip2 list -> [list list] ++
    ++
    unzip3 list -> [list list list] ++
    ++
    unzip4 list -> [list list list list] ++
    ++
    unzip5 list -> [list list list list list] ++
    ++
    ++

    ++ unzip1 takes a list of lists, ++ where every list must contain at least one element, ++ and returns a list containing the initial element of each such list. ++ That is, it returns (map car lists). + unzip2 takes a list of lists, where every list must contain at least + two elements, and returns two values: a list of the first elements, + and a list of the second elements. unzip3 does the same for the first + three elements of the lists, and so forth. +- +-

    ++

    ++
    + (unzip2 '((1 one) (2 two) (3 three))) =>
    +-    (1 2 3) 
    ++    (1 2 3)
    +     (one two three)
    + 
    +- ++
    + +-
    ++
    + +-count pred clist1 clist2 -> integer +-
    ++count pred clist1 clist2 -> integer ++ ++
    ++

    + pred is a procedure taking as many arguments as there +- are lists and returning a single value. It is applied ++ are lists and returning a single value. It is applied + element-wise to the elements of the lists, and a count is + tallied of the number of elements that produce a true value. This count + is returned. count is "iterative" in that it is guaranteed + to apply pred to the list elements in a + left-to-right order. + The counting stops when the shortest list expires. +-

    +-(count even? '(3 1 4 1 5 9 2 5 6)) => 3
    +-(count < '(1 2 4 8) '(2 4 6 8 10 12 14 16)) => 3
    ++

    ++
    ++(count even? '(3 1 4 1 5 9 2 5 6)) => 3
    ++(count < '(1 2 4 8) '(2 4 6 8 10 12 14 16)) => 3
    + 
    ++

    + At least one of the argument lists must be finite: +-

    +-(count < '(3 1 4 1) (circular-list 1 10)) => 2
    ++

    ++
    ++(count < '(3 1 4 1) (circular-list 1 10)) => 2
    + 
    +- ++
    + + + +-

    Fold, unfold & map

    ++

    Fold, unfold & map

    +
    + +-
    ++
    + +-fold kons knil clist1 clist2 ... -> value +-
    +- The fundamental list iterator. ++fold kons knil clist1 clist2 ... -> value ++ ++
    ++

    ++ The fundamental list iterator. ++

    +

    + First, consider the single list-parameter case. If clist1 = (e1 e2 ... en), + then this procedure returns +-

    ++

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

    + That is, it obeys the (tail) recursion +-

    ++

    ++
    + (fold kons knil lis) = (fold kons (kons (car lis) knil) (cdr lis))
    + (fold kons knil '()) = knil
    + 
    +- ++

    + Examples: +-

    ++

    ++
    + (fold + 0 lis)			; Add up the elements of LIS.
    + 
    + (fold cons '() lis)		; Reverse LIS.
    +@@ -1581,297 +1784,357 @@ partition the entire universe of Scheme values.
    +       0
    +       lis)
    + 
    +- ++

    + If n list arguments are provided, then the kons function must take + n+1 parameters: one element from each list, and the "seed" or fold + state, which is initially knil. The fold operation terminates when + the shortest list runs out of values: +-

    ++

    ++
    + (fold cons* '() '(a b c) '(1 2 3 4 5)) => (c 3 b 2 a 1)
    + 
    ++

    + At least one of the list arguments must be finite. +- ++

    ++
    + +-
    ++
    + +-fold-right kons knil clist1 clist2 ... -> value +-
    +- The fundamental list recursion operator. ++fold-right kons knil clist1 clist2 ... -> value ++ ++
    +

    +- First, consider the single list-parameter case. If clist1 = (e1 e2 ... en), ++ The fundamental list recursion operator. ++

    ++

    ++ First, consider the single list-parameter case. If clist1 = (e1 e2 ... en), + then this procedure returns +-

    ++

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

    + That is, it obeys the recursion +-

    ++

    ++
    + (fold-right kons knil lis) = (kons (car lis) (fold-right kons knil (cdr lis)))
    + (fold-right kons knil '()) = knil
    + 
    +- ++

    + Examples: +-

    ++

    ++
    + (fold-right cons '() lis)		; Copy LIS.
    + 
    + ;; Filter the even numbers out of LIS.
    + (fold-right (lambda (x l) (if (even? x) (cons x l) l)) '() lis))
    + 
    +- ++

    + If n list arguments are provided, then the kons function must take + n+1 parameters: one element from each list, and the "seed" or fold + state, which is initially knil. The fold operation terminates when + the shortest list runs out of values: +-

    ++

    ++
    + (fold-right cons* '() '(a b c) '(1 2 3 4 5)) => (a 1 b 2 c 3)
    + 
    ++

    + At least one of the list arguments must be finite. +- ++

    ++
    + +-
    ++
    + +-pair-fold kons knil clist1 clist2 ... -> value +-
    +- Analogous to fold, but kons is applied to successive sublists of the ++pair-fold kons knil clist1 clist2 ... -> value ++ ++
    ++

    ++ Analogous to fold, but kons is applied to successive sublists of the + lists, rather than successive elements -- that is, kons is applied to the + pairs making up the lists, giving this (tail) recursion: +-

    ++

    ++
    + (pair-fold kons knil lis) = (let ((tail (cdr lis)))
    +                               (pair-fold kons (kons lis knil) tail))
    + (pair-fold kons knil '()) = knil
    + 
    ++

    + For finite lists, the kons function may reliably apply + set-cdr! to the pairs it is given + without altering the sequence of execution. ++

    +

    + Example: +-

    ++

    ++
    + ;;; Destructively reverse a list.
    +-(pair-fold (lambda (pair tail) (set-cdr! pair tail) pair) '() lis))
    ++(pair-fold (lambda (pair tail) (set-cdr! pair tail) pair) '() lis)
    + 
    +- ++

    + At least one of the list arguments must be finite. +- +- ++

    ++
    + +-
    ++
    + +-pair-fold-right kons knil clist1 clist2 ... -> value +-
    ++pair-fold-right kons knil clist1 clist2 ... -> value ++ ++
    ++

    + Holds the same relationship with fold-right that pair-fold holds with fold. + Obeys the recursion +-

    +-(pair-fold-right kons knil lis) = 
    ++

    ++
    ++(pair-fold-right kons knil lis) =
    +     (kons lis (pair-fold-right kons knil (cdr lis)))
    + (pair-fold-right kons knil '()) = knil
    + 
    +- ++

    + Example: +-

    ++

    ++
    + (pair-fold-right cons '() '(a b c)) => ((a b c) (b c) (c))
    + 
    +- ++

    + At least one of the list arguments must be finite. +- ++

    ++
    + +-
    ++
    + +-reduce f ridentity list -> value +-
    +- reduce is a variant of fold. ++reduce f ridentity list -> value ++ ++
    +

    +- ridentity should be a "right identity" of the procedure f -- that is, ++ reduce is a variant of fold. ++

    ++

    ++ ridentity should be a "right identity" of the procedure f -- that is, + for any value x acceptable to f, +-

    ++

    ++
    + (f x ridentity) = x
    + 
    +- ++

    + reduce has the following definition: +-

    +-If list = (), return ridentity;
    ++

    ++
    ++If list = (), return ridentity;
    + Otherwise, return (fold f (car list) (cdr list)). +
    +- ...in other words, we compute ++

    ++ ...in other words, we compute + (fold f ridentity list). ++

    +

    + Note that ridentity is used only in the empty-list case. + You typically use reduce when applying f is expensive and you'd + like to avoid the extra application incurred when fold applies + f to the head of list and the identity value, +- redundantly producing the same value passed in to f. +- For example, if f involves searching a file directory or +- performing a database query, this can be significant. ++ redundantly producing the same value passed in to f. ++ For example, if f involves searching a file directory or ++ performing a database query, this can be significant. + In general, however, fold is useful in many contexts where reduce is not + (consider the examples given in the fold definition -- only one of the +- five folds uses a function with a right identity. ++ five folds uses a function with a right identity. + The other four may not be performed with reduce). +- ++

    +

    + Note: MIT Scheme and Haskell flip F's arg order for their reduce and + fold functions. +- +-

    ++

    ++
    + ;; Take the max of a list of non-negative integers.
    + (reduce max 0 nums) ; i.e., (apply max 0 nums)
    + 
    +- ++
    + +-
    ++
    + +-reduce-right f ridentity list -> value +-
    ++reduce-right f ridentity list -> value ++ ++
    ++

    + reduce-right is the fold-right variant of reduce. + It obeys the following definition: +-

    ++

    ++
    + (reduce-right f ridentity '()) = ridentity
    + (reduce-right f ridentity '(e1)) = (f e1 ridentity) = e1
    + (reduce-right f ridentity '(e1 e2 ...)) =
    +     (f e1 (reduce f ridentity (e2 ...)))
    + 
    +- ...in other words, we compute ++

    ++ ...in other words, we compute + (fold-right f ridentity list). +- +-

    ++

    ++
    + ;; Append a bunch of lists together.
    + ;; I.e., (apply append list-of-lists)
    + (reduce-right append '() list-of-lists)
    + 
    +- ++
    + +-
    ++
    + +-unfold p f g seed [tail-gen] -> list +-
    ++unfold p f g seed [tail-gen] -> list ++ ++
    ++

    + unfold is best described by its basic recursion: +-

    +-(unfold p f g seed) = 
    ++

    ++
    ++(unfold p f g seed) =
    +     (if (p seed) (tail-gen seed)
    +         (cons (f seed)
    +               (unfold p f g (g seed))))
    + 
    +
    +-
    p
    Determines when to stop unfolding. +-
    f
    Maps each seed value to the corresponding list element. +-
    g
    Maps each seed value to next seed value. +-
    seed
    The "state" value for the unfold. +-
    tail-gen
    Creates the tail of the list; +- defaults to (lambda (x) '()) ++
    p
    ++
    Determines when to stop unfolding.
    ++
    f
    ++
    Maps each seed value to the corresponding list element.
    ++
    g
    ++
    Maps each seed value to next seed value.
    ++
    seed
    ++
    The "state" value for the unfold.
    ++
    tail-gen
    ++
    Creates the tail of the list; defaults to (lambda (x) '())
    +
    +

    + In other words, we use g to generate a sequence of seed values +-

    ++

    ++
    + seed, g(seed), g2(seed), g3(seed), ... +
    +- These seed values are mapped to list elements by f, +- producing the elements of the result list in a left-to-right order. ++

    ++ These seed values are mapped to list elements by f, ++ producing the elements of the result list in a left-to-right order. + P says when to stop. +- ++

    +

    +- unfold is the fundamental recursive list constructor, +- just as fold-right is ++ unfold is the fundamental recursive list constructor, ++ just as fold-right is + the fundamental recursive list consumer. + While unfold may seem a bit abstract + to novice functional programmers, it can be used in a number of ways: +- +-

    ++

    ++
    + ;; List of squares: 1^2 ... 10^2
    + (unfold (lambda (x) (> x 10))
    +         (lambda (x) (* x x))
    + 	(lambda (x) (+ x 1))
    + 	1)
    +-		
    ++
    + (unfold null-list? car cdr lis) ; Copy a proper list.
    + 
    + ;; Read current input port into a list of values.
    + (unfold eof-object? values (lambda (x) (read)) (read))
    + 
    + ;; Copy a possibly non-proper list:
    +-(unfold not-pair? car cdr lis 
    ++(unfold not-pair? car cdr lis
    +               values)
    + 
    + ;; Append HEAD onto TAIL:
    +-(unfold null-list? car cdr head 
    ++(unfold null-list? car cdr head
    +               (lambda (x) tail))
    + 
    +- +- Interested functional programmers may enjoy noting that ++

    ++ Interested functional programmers may enjoy noting that + fold-right and unfold +- are in some sense inverses. +- That is, given operations knull?, kar, ++ are in some sense inverses. ++ That is, given operations knull?, kar, + kdr, kons, and knil satisfying +-

    ++

    ++
    + (kons (kar x) (kdr x)) = x +- and ++ and + (knull? knil) = #t +
    ++

    + then +-

    ++

    ++
    + (fold-right kons knil (unfold knull? kar kdr x)) = x +
    ++

    + and +-

    ++

    ++
    + (unfold knull? kar kdr (fold-right kons knil x)) = x. +
    +- ++

    + This combinator sometimes is called an "anamorphism;" when an + explicit tail-gen procedure is supplied, it is called an + "apomorphism." +- +- ++

    ++
    + +-
    ++
    + +-unfold-right p f g seed [tail] -> list +-
    ++unfold-right p f g seed [tail] -> list ++ ++
    ++

    + unfold-right constructs a list with the following loop: +-

    ++

    ++
    + (let lp ((seed seed) (lis tail))
    +   (if (p seed) lis
    +       (lp (g seed)
    +           (cons (f seed) lis))))
    + 
    +
    +-
    p
    Determines when to stop unfolding. +-
    f
    Maps each seed value to the corresponding list element. +-
    g
    Maps each seed value to next seed value. +-
    seed
    The "state" value for the unfold. +-
    tail
    list terminator; defaults to '(). ++
    p
    ++
    Determines when to stop unfolding.
    ++
    f
    ++
    Maps each seed value to the corresponding list element.
    ++
    g
    ++
    Maps each seed value to next seed value.
    ++
    seed
    ++
    The "state" value for the unfold.
    ++
    tail
    ++
    list terminator; defaults to '().
    +
    +

    + In other words, we use g to generate a sequence of seed values +-

    ++

    ++
    + seed, g(seed), g2(seed), g3(seed), ... +
    +- These seed values are mapped to list elements by f, +- producing the elements of the result list in a right-to-left order. ++

    ++ These seed values are mapped to list elements by f, ++ producing the elements of the result list in a right-to-left order. + P says when to stop. +- ++

    +

    +- unfold-right is the fundamental iterative list constructor, ++ unfold-right is the fundamental iterative list constructor, + just as fold is the +- fundamental iterative list consumer. ++ fundamental iterative list consumer. + While unfold-right may seem a bit abstract + to novice functional programmers, it can be used in a number of ways: +-

    ++

    ++
    + ;; List of squares: 1^2 ... 10^2
    +-(unfold-right zero? 
    ++(unfold-right zero?
    +               (lambda (x) (* x x))
    +               (lambda (x) (- x 1))
    +               10)
    +-	
    ++
    + ;; Reverse a proper list.
    + (unfold-right null-list? car cdr lis)
    + 
    +@@ -1881,241 +2144,290 @@ Otherwise,    return (fold f (car list) (cdr li
    + ;; (append-reverse rev-head tail)
    + (unfold-right null-list? car cdr rev-head tail)
    + 
    +- +- Interested functional programmers may enjoy noting that ++

    ++ Interested functional programmers may enjoy noting that + fold and unfold-right +- are in some sense inverses. +- That is, given operations knull?, kar, ++ are in some sense inverses. ++ That is, given operations knull?, kar, + kdr, kons, and knil satisfying +-

    ++

    ++
    + (kons (kar x) (kdr x)) = x +- and ++ and + (knull? knil) = #t +
    ++

    + then +-

    ++

    ++
    + (fold kons knil (unfold-right knull? kar kdr x)) = x +
    ++

    + and +-

    ++

    ++
    + (unfold-right knull? kar kdr (fold kons knil x)) = x. +
    +- ++

    + This combinator presumably has some pretentious mathematical name; + interested readers are invited to communicate it to the author. +- ++

    ++
    + +-
    ++
    + +-map proc clist1 clist2 ... -> list +-
    +- [R5RS+] +- +- proc is a procedure taking as many arguments +- as there are list arguments and returning a single value. ++map proc clist1 clist2 ... -> list ++ ++
    ++

    ++ [R5RS+] ++ proc is a procedure taking as many arguments ++ as there are list arguments and returning a single value. + map applies proc element-wise to the elements +- of the lists and returns a list of the results, +- in order. +- The dynamic order in which proc ++ of the lists and returns a list of the results, ++ in order. ++ The dynamic order in which proc + is applied to the elements of the lists is unspecified. +- +-

    +-(map cadr '((a b) (d e) (g h))) =>  (b e h)
    ++

    ++
    ++(map cadr '((a b) (d e) (g h))) =>  (b e h)
    + 
    + (map (lambda (n) (expt n n))
    +      '(1 2 3 4 5))
    +-    =>  (1 4 27 256 3125)
    ++    =>  (1 4 27 256 3125)
    + 
    +-(map + '(1 2 3) '(4 5 6)) =>  (5 7 9)
    ++(map + '(1 2 3) '(4 5 6)) =>  (5 7 9)
    + 
    + (let ((count 0))
    +   (map (lambda (ignored)
    +          (set! count (+ count 1))
    +          count)
    +-       '(a b))) =>  (1 2) or (2 1)
    ++       '(a b))) =>  (1 2) or (2 1)
    + 
    +- +- This procedure is extended from its ++

    ++ This procedure is extended from its + R5RS +- specification to allow the arguments to be of unequal length; +- it terminates when the shortest list runs out. ++ specification to allow the arguments to be of unequal length; ++ it terminates when the shortest list runs out. ++

    +

    + At least one of the argument lists must be finite: +-

    +-(map + '(3 1 4 1) (circular-list 1 0)) => (4 1 5 1)
    ++

    ++
    ++(map + '(3 1 4 1) (circular-list 1 0)) => (4 1 5 1)
    + 
    +- ++
    + +-
    ++
    + +-for-each proc clist1 clist2 ... -> unspecified +-
    ++for-each proc clist1 clist2 ... -> unspecified ++ ++
    ++

    + [R5RS+] +- +- The arguments to for-each are like the arguments to ++

    ++

    ++ The arguments to for-each are like the arguments to + map, but + for-each calls proc for its side effects rather +- than for its values. +- Unlike map, for-each is guaranteed to call ++ than for its values. ++ Unlike map, for-each is guaranteed to call + proc on the elements of the lists in order from the first +- element(s) to the last, ++ element(s) to the last, + and the value returned by for-each is unspecified. +-

    ++

    ++
    + (let ((v (make-vector 5)))
    +   (for-each (lambda (i)
    +               (vector-set! v i (* i i)))
    +             '(0 1 2 3 4))
    +-  v)  =>  #(0 1 4 9 16)
    ++  v)  =>  #(0 1 4 9 16)
    + 
    +- ++

    + This procedure is extended from its + R5RS +- specification to allow the arguments to be of unequal length; +- it terminates when the shortest list runs out. ++ specification to allow the arguments to be of unequal length; ++ it terminates when the shortest list runs out. ++

    +

    + At least one of the argument lists must be finite. +- ++

    ++
    + +-
    ++
    + +-append-map  f clist1 clist2 ... -> value +-
    ++append-map  f clist1 clist2 ... -> value ++
    ++
    + +-append-map! f clist1 clist2 ... -> value +-
    +- Equivalent to +-
    ++append-map! f clist1 clist2 ... -> value ++ ++
    ++

    ++ Equivalent to ++

    ++
    + (apply append (map f clist1 clist2 ...)) +
    ++

    + and +-

    ++

    ++
    + (apply append! (map f clist1 clist2 ...)) +
    +- ++

    + Map f over the elements of the lists, just as in the map function. + However, the results of the applications are appended together to + make the final result. append-map uses append to append the results + together; append-map! uses append!. ++

    +

    + The dynamic order in which the various applications of f are made is + not specified. ++

    +

    + Example: +-

    ++

    ++
    + (append-map! (lambda (x) (list x (- x))) '(1 3 8))
    +     => (1 -1 3 -3 8 -8)
    + 
    +- ++

    + At least one of the list arguments must be finite. +- ++

    ++
    + +-
    ++
    + +-map! f list1 clist2 ... -> list +-
    +- Linear-update variant of map -- map! is allowed, but not required, to ++map! f list1 clist2 ... -> list ++ ++
    ++

    ++ Linear-update variant of map -- map! is allowed, but not required, to + alter the cons cells of list1 to construct the result list. ++

    +

    + The dynamic order in which the various applications of f are made is + not specified. +- ++

    ++

    + In the n-ary case, clist2, clist3, ... must have at least as many + elements as list1. +- ++

    ++
    + +-
    ++
    + +-map-in-order f clist1 clist2 ... -> list +-
    ++map-in-order f clist1 clist2 ... -> list ++ ++
    ++

    + A variant of the map procedure that guarantees to apply f across + the elements of the listi arguments in a left-to-right order. This + is useful for mapping procedures that both have side effects and + return useful values. ++

    +

    + At least one of the list arguments must be finite. +- ++

    ++
    + +-
    ++
    + +-pair-for-each f clist1 clist2 ... -> unspecific +-
    ++pair-for-each f clist1 clist2 ... -> unspecific ++ ++
    ++

    + Like for-each, but f is applied to successive sublists of the argument + lists. That is, f is applied to the cons cells of the lists, rather + than the lists' elements. These applications occur in left-to-right + order. ++

    +

    + The f procedure may reliably apply set-cdr! to the pairs it is given + without altering the sequence of execution. +- +-

    ++

    ++
    + (pair-for-each (lambda (pair) (display pair) (newline)) '(a b c)) ==>
    +     (a b c)
    +     (b c)
    +     (c)
    + 
    +- ++

    + At least one of the list arguments must be finite. +- ++

    ++
    + +-
    ++
    + +-filter-map f clist1 clist2 ... -> list +-
    ++filter-map f clist1 clist2 ... -> list ++ ++
    ++

    + Like map, but only true values are saved. +-

    ++

    ++
    + (filter-map (lambda (x) (and (number? x) (* x x))) '(a 1 b 3 c 7))
    +     => (1 9 49)
    + 
    ++

    + The dynamic order in which the various applications of f are made is + not specified. ++

    +

    + At least one of the list arguments must be finite. ++

    ++
    +
    + + +-

    Filtering & partitioning

    ++

    Filtering & partitioning

    +
    + + +-
    ++
    + +-filter pred list -> list +-
    ++filter pred list -> 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 returned list may share a common tail with the argument list. + The dynamic order in which the various applications of pred are made is + not specified. +- +-

    ++

    ++
    + (filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4)
    + 
    +- ++
    + +-
    ++
    + +-partition pred list -> [list list] +-
    ++partition pred list -> [list list] ++ ++
    ++

    + Partitions the elements of list with predicate pred, and returns two + values: the list of in-elements and the list of out-elements. + The list is not disordered -- elements occur in the result lists +@@ -2123,71 +2435,88 @@ Otherwise, return (fold f (car list) (cdr li + The dynamic order in which the various applications of pred are made is + not specified. One of the returned lists may share a common tail with the + argument list. +- +-

    +-(partition symbol? '(one 2 3 four five 6)) => 
    ++

    ++
    ++(partition symbol? '(one 2 3 four five 6)) =>
    +     (one four five)
    +     (2 3 6)
    + 
    +- ++
    + +-
    ++
    + +-remove pred list -> list +-
    ++remove pred list -> list ++ ++
    ++

    + Returns list without the elements that satisfy predicate pred: +-

    ++

    ++
    + (lambda (pred list) (filter (lambda (x) (not (pred x))) list))
    + 
    ++

    + 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 returned list may share a common tail with the argument list. +- The dynamic order in which the various applications of pred are made is ++ The dynamic order in which the various applications of pred are made is + not specified. +- +-

    ++

    ++
    + (remove even? '(0 7 8 8 43 -4)) => (7 43)
    + 
    +- ++
    + +-
    ++
    + +-filter!    pred list -> list +-
    ++filter!    pred list -> list ++
    ++
    + +-partition! pred list -> [list list] +-
    ++partition! pred list -> [list list] ++
    ++
    + +-remove!    pred list -> list +-
    ++remove!    pred list -> list ++ ++
    ++

    + Linear-update variants of filter, partition and remove. + These procedures are allowed, but not required, to alter the cons cells + in the argument list to construct the result lists. +- ++

    ++
    +
    + + +-

    Searching

    +-

    ++

    Searching

    + ++

    + The following procedures all search lists for a leftmost element satisfying + some criteria. This means they do not always examine the entire list; thus, + there is no efficient way for them to reliably detect and signal an error when + passed a dotted or circular list. Here are the general rules describing how + these procedures work when applied to different kinds of lists: ++

    + +
    +-
    Proper lists: +-
    The standard, canonical behavior happens in this case. +- +-
    Dotted lists: +-
    It is an error to pass these procedures a dotted list ++
    Proper lists: ++
    ++
    ++

    ++ The standard, canonical behavior happens in this case. ++

    ++
    ++
    Dotted lists: ++
    ++
    ++

    ++ It is an error to pass these procedures a dotted list + that does not contain an element satisfying the search + criteria. That is, it is an error if the procedure has + to search all the way to the end of the dotted list. +@@ -2200,23 +2529,31 @@ these procedures work when applied to different kinds of lists: + which is compliant with this SRFI may not rely on any + particular behavior. Future SRFI's may refine SRFI-1 + to define specific behavior in this case. +-

    ++

    ++

    + In brief, SRFI-1 compliant code may not pass a dotted + list argument to these procedures. +- +-

    Circular lists: +-
    It is an error to pass these procedures a circular list ++

    ++
    ++
    Circular lists: ++
    ++
    ++

    ++ It is an error to pass these procedures a circular list + that does not contain an element satisfying the search +- criteria. Note that the procedure is not required to ++ criteria. Note that the procedure is not required to + detect this case; it may simply diverge. It is, however, + acceptable to search a circular list if the search is + successful -- that is, if the list contains an element + satisfying the search criteria. ++

    ++
    +
    +

    + Here are some examples, using the find and any procedures as canonical + representatives: +-

    ++

    ++
    + ;; Proper list -- success
    + (find even? '(1 2 3))	=> 2
    + (any  even? '(1 2 3))	=> #t
    +@@ -2230,7 +2567,7 @@ representatives:
    + (any  even? '(1 3 . x))	=> error
    + 
    + ;; The dotted list contains an element satisfying the search.
    +-;; This case is not specified -- it could be success, an error, 
    ++;; This case is not specified -- it could be success, an error,
    + ;; or some third possibility.
    + (find even? '(1 2 . x))	=> error/undefined
    + (any  even? '(1 2 . x))	=> error/undefined ; success, error or other.
    +@@ -2248,17 +2585,19 @@ representatives:
    + 
    +-
    ++
    + +-find pred clist -> value +-
    ++find pred clist -> value ++ ++
    ++

    + Return the first element of clist that satisfies predicate pred; + false if no element does. +- +-

    ++

    ++
    + (find even? '(3 1 4 1 5 9)) => 4
    + 
    +- ++

    + Note that find has an ambiguity in its lookup semantics -- if find + returns #f, you cannot tell (in general) if it found a #f element + that satisfied pred, or if it did not find any element at all. In +@@ -2267,145 +2606,168 @@ representatives: + guaranteed to have an element satisfying pred. However, in cases + where this ambiguity can arise, you should use find-tail instead of + find -- find-tail has no such ambiguity: +-

    ++

    ++
    + (cond ((find-tail pred lis) => (lambda (pair) ...)) ; Handle (CAR PAIR)
    +       (else ...)) ; Search failed.
    + 
    +- ++
    + +-
    ++
    + +-find-tail pred clist -> pair or false +-
    ++find-tail pred clist -> pair or false ++ ++
    ++

    + Return the first pair of clist whose car satisfies pred. If no pair does, + return false. ++

    +

    + find-tail can be viewed as a general-predicate variant of the member + function. ++

    +

    +- Examples: +-

    ++    Examples:
    ++

    ++
    + (find-tail even? '(3 1 37 -8 -5 0 0)) => (-8 -5 0 0)
    + (find-tail even? '(3 1 37 -5)) => #f
    + 
    + ;; MEMBER X LIS:
    + (find-tail (lambda (elt) (equal? x elt)) lis)
    + 
    +- ++

    + In the circular-list case, this procedure "rotates" the list. +- ++

    +

    +- Find-tail is essentially drop-while, +- where the sense of the predicate is inverted: ++ Find-tail is essentially drop-while, ++ where the sense of the predicate is inverted: + Find-tail searches until it finds an element satisfying +- the predicate; drop-while searches until it finds an ++ the predicate; drop-while searches until it finds an + element that doesn't satisfy the predicate. +- ++

    ++
    + +-
    ++
    + +-take-while  pred clist -> list +-
    ++take-while  pred clist -> list ++
    ++
    + +-take-while! pred clist -> list +-
    +- ++take-while! pred clist -> list ++ ++
    ++

    + Returns the longest initial prefix of clist whose elements all + satisfy the predicate pred. +- ++

    +

    + Take-while! is the linear-update variant. It is allowed, but not + required, to alter the argument list to produce the result. +- +-

    +-(take-while even? '(2 18 3 10 22 9)) => (2 18)
    ++

    ++
    ++(take-while even? '(2 18 3 10 22 9)) => (2 18)
    + 
    +- ++
    + +-
    ++
    + +-drop-while pred clist -> list +-
    ++drop-while pred clist -> list ++ ++
    ++

    + Drops the longest initial prefix of clist whose elements all + satisfy the predicate pred, and returns the rest of the list. +- +-

    +-(drop-while even? '(2 18 3 10 22 9)) => (3 10 22 9)
    ++

    ++
    ++(drop-while even? '(2 18 3 10 22 9)) => (3 10 22 9)
    + 
    ++

    + The circular-list case may be viewed as "rotating" the list. +- ++

    ++
    + + +-
    ++
    + +-span   pred clist -> [list clist] +-
    ++span   pred clist -> [list clist] ++
    ++
    + +-span!  pred list  -> [list list] +-
    ++span!  pred list  -> [list list] ++
    ++
    + +-break  pred clist -> [list clist] +-
    ++break  pred clist -> [list clist] ++
    ++
    + +-break! pred list  -> [list list] +-
    +- ++break! pred list  -> [list list] ++ ++
    ++

    + Span splits the list into the longest initial prefix whose +-elements all satisfy pred, and the remaining tail. +-Break inverts the sense of the predicate: ++elements all satisfy pred, and the remaining tail. ++Break inverts the sense of the predicate: + the tail commences with the first element of the input list + that satisfies the predicate. +- ++

    +

    +-In other words: +-span finds the initial span of elements +-satisfying pred, +-and break breaks the list at the first element satisfying ++In other words: ++span finds the intial span of elements ++satisfying pred, ++and break breaks the list at the first element satisfying + pred. +- ++

    +

    +-Span is equivalent to +-

    +-(values (take-while pred clist) 
    ++Span is equivalent to
    ++

    ++
    ++(values (take-while pred clist)
    +         (drop-while pred clist))
    + 
    +- +

    +-Span! and break! are the linear-update variants. +-They are allowed, but not required, ++Span! and break! are the linear-update variants. ++They are allowed, but not required, + to alter the argument list to produce the result. +- +-

    +-(span even? '(2 18 3 10 22 9)) =>
    ++

    ++
    ++(span even? '(2 18 3 10 22 9)) =>
    +   (2 18)
    +   (3 10 22 9)
    + 
    +-(break even? '(3 1 4 1 5 9)) =>
    ++(break even? '(3 1 4 1 5 9)) =>
    +   (3 1)
    +   (4 1 5 9)
    + 
    +- ++
    + + +-
    ++
    + +-any pred clist1 clist2 ... -> value +-
    ++any pred clist1 clist2 ... -> value ++ ++
    ++

    + Applies the predicate across the lists, returning true if the predicate + returns true on any application. ++

    +

    + If there are n list arguments clist1 ... clistn, then pred must be a +- procedure taking n arguments and returning a boolean result. ++ procedure taking n arguments ++ and returning a single value, interpreted as a boolean (that is, ++ #f means false, and any other value means true). ++

    +

    + any applies pred to the first elements of the clisti parameters. + If this application returns a true value, any immediately returns +@@ -2413,37 +2775,45 @@ to alter the argument list to produce the result. + elements of the clisti parameters, then the third, and so forth. + The iteration stops when a true value is produced or one of the lists runs + out of values; in +- the latter case, any returns #f. ++ the latter case, any returns #f. + The application of pred to the last element of the + lists is a tail call. ++

    +

    + Note the difference between find and any -- find returns the element + that satisfied the predicate; any returns the true value that the + predicate produced. ++

    +

    + Like every, any's name does not end with a question mark -- this is to + indicate that it does not return a simple boolean (#t or #f), but a + general value. +- +-

    ++

    ++
    + (any integer? '(a 3 b 2.7))   => #t
    + (any integer? '(a 3.1 b 2.7)) => #f
    + (any < '(3 1 4 1 5)
    +        '(2 7 1 8 2)) => #t
    + 
    +- ++
    + +-
    ++
    + +-every pred clist1 clist2 ... -> value +-
    ++every pred clist1 clist2 ... -> value ++ ++
    ++

    + Applies the predicate across the lists, returning true if the predicate + returns true on every application. ++

    +

    + If there are n list arguments clist1 ... clistn, then pred must be a +- procedure taking n arguments and returning a boolean result. ++ procedure taking n arguments ++ and returning a single value, interpreted as a boolean (that is, ++ #f means false, and any other value means true). ++

    +

    + every applies pred to the first elements of the clisti parameters. + If this application returns false, every immediately returns false. +@@ -2451,27 +2821,36 @@ to alter the argument list to produce the result. + clisti parameters, then the third, and so forth. The iteration stops + when a false value is produced or one of the lists runs out of values. + In the latter case, every returns +- the true value produced by its final application of pred. +- The application of pred to the last element of the lists ++ the true value produced by its final application of pred. ++ The application of pred to the last element of the lists + is a tail call. ++

    +

    + If one of the clisti has no elements, every simply returns #t. ++

    +

    + Like any, every's name does not end with a question mark -- this is to + indicate that it does not return a simple boolean (#t or #f), but a + general value. +- ++

    ++
    + +-
    ++
    + +-list-index pred clist1 clist2 ... -> integer or false +-
    ++list-index pred clist1 clist2 ... -> integer or false ++ ++
    ++

    + Return the index of the leftmost element that satisfies pred. ++

    +

    + If there are n list arguments clist1 ... clistn, then pred must be a +- function taking n arguments and returning a boolean result. ++ function taking n arguments ++ and returning a single value, interpreted as a boolean (that is, ++ #f means false, and any other value means true). ++

    +

    + list-index applies pred to the first elements of the clisti parameters. + If this application returns true, list-index immediately returns zero. +@@ -2479,139 +2858,154 @@ to alter the argument list to produce the result. + clisti parameters, then the third, and so forth. When it finds a tuple of + list elements that cause pred to return true, it stops and returns the + zero-based index of that position in the lists. ++

    +

    + The iteration stops when one of the lists runs out of values; in this + case, list-index returns #f. +- +-

    ++

    ++
    + (list-index even? '(3 1 4 1 5 9)) => 2
    + (list-index < '(3 1 4 1 5 9 2 5 6) '(2 7 1 8 2)) => 1
    + (list-index = '(3 1 4 1 5 9 2 5 6) '(2 7 1 8 2)) => #f
    + 
    +- ++
    + +-
    ++
    + +-member x list [=] -> list +-
    ++member x list [=] -> list ++
    ++
    + +-memq x list -> list +-
    ++memq x list -> list ++
    ++
    + +-memv x list -> list +-
    +- [R5RS+] +- ++memv x list -> list ++ ++
    ++

    ++ [R5RS+] + These procedures return the first sublist of list whose car is +- x, where the sublists of list are the +- non-empty lists returned by ++ x, where the sublists of list are the ++ non-empty lists returned by + (drop list i) +- for i less than the length of list. ++ for i less than the length of list. + If x does +- not occur in list, then #f is returned. ++ not occur in list, then #f is returned. + memq uses eq? to compare x +- with the elements of list, ++ with the elements of list, + while memv uses eqv?, and + member uses equal?. +- +-

    +-    (memq 'a '(a b c))          =>  (a b c)
    +-    (memq 'b '(a b c))          =>  (b c)
    +-    (memq 'a '(b c d))          =>  #f
    +-    (memq (list 'a) '(b (a) c)) =>  #f
    ++

    ++
    ++    (memq 'a '(a b c))          =>  (a b c)
    ++    (memq 'b '(a b c))          =>  (b c)
    ++    (memq 'a '(b c d))          =>  #f
    ++    (memq (list 'a) '(b (a) c)) =>  #f
    +     (member (list 'a)
    +-            '(b (a) c))         =>  ((a) c)
    +-    (memq 101 '(100 101 102))   =>  *unspecified*
    +-    (memv 101 '(100 101 102))   =>  (101 102)
    ++            '(b (a) c))         =>  ((a) c)
    ++    (memq 101 '(100 101 102))   =>  *unspecified*
    ++    (memv 101 '(100 101 102))   =>  (101 102)
    + 
    +- +- member is extended from its ++

    ++ member is extended from its + R5RS + definition to allow the client to pass in +- an optional equality procedure = used to compare keys. ++ an optional equality procedure = used to compare keys. + ++

    +

    + The comparison procedure is used to compare the elements ei of list + to the key x in this way: +-

    ++

    ++
    + (= x ei) ; list is (E1 ... En) +
    ++

    + That is, the first argument is always x, and the second argument is + one of the list elements. Thus one can reliably find the first element + of list that is greater than five with + (member 5 list <) +- ++

    +

    + Note that fully general list searching may be performed with + the find-tail and find procedures, e.g. +-

    ++

    ++
    + (find-tail even? list) ; Find the first elt with an even key.
    + 
    +- ++
    + + + +-

    Deletion

    +-

    ++

    Deletion

    + +
    + +-
    ++
    + +-delete  x list [=] -> list +-
    ++delete  x list [=] -> list ++
    ++
    + +-delete! x list [=] -> list +-
    ++delete! x list [=] -> list ++ ++
    ++

    + delete uses the comparison procedure =, which defaults to equal?, to find + all elements of list that are equal to x, and deletes them from list. The + dynamic order in which the various applications of = are made is not + specified. +- ++

    +

    + 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 result may share a common tail with the argument list. +- ++

    +

    + Note that fully general element deletion can be performed with the remove + and remove! procedures, e.g.: +-

    ++

    ++
    + ;; Delete all the even elements from LIS:
    + (remove even? lis)
    + 
    +- ++

    + The comparison procedure is used in this way: + (= x ei). +- That is, x is always the first argument, ++ That is, x is always the first argument, + and a list element is always the + second argument. The comparison procedure will be used to compare each + element of list exactly once; the order in which it is applied to the + various ei is not specified. Thus, one can reliably remove all the + numbers greater than five from a list with + (delete 5 list <) +- ++

    +

    + delete! is the linear-update variant of delete. + It is allowed, but not required, to alter the cons cells in +- its argument list to construct the result. +- ++ its argument list to construct the result. ++

    ++
    + +-
    ++
    + +-delete-duplicates  list [=] -> list +-
    ++delete-duplicates  list [=] -> list ++
    ++
    + +-delete-duplicates! list [=] -> list +-
    ++delete-duplicates! list [=] -> list ++ ++
    ++

    + delete-duplicates removes duplicate elements from the + list argument. + If there are multiple equal elements in the argument list, the result list +@@ -2619,19 +3013,22 @@ to alter the argument list to produce the result. + The order of these surviving elements is the same as in the original + list -- delete-duplicates does not disorder the list (hence it is useful + for "cleaning up" association lists). ++

    +

    + The = parameter is used to compare the elements of the list; it defaults +- to equal?. If x comes before y in list, then the comparison is performed ++ to equal?. If x comes before y in list, then the comparison is performed + (= x y). +- The comparison procedure will be used to compare each pair of elements in +- list no more than once; ++ The comparison procedure will be used to compare each pair of elements in ++ list no more than once; + the order in which it is applied to the various pairs is not specified. ++

    +

    + Implementations of delete-duplicates + are allowed to share common tails + between argument and result lists -- for example, if the list argument + contains only unique elements, it may simply return exactly + this list. ++

    +

    + Be aware that, in general, delete-duplicates + runs in time O(n2) for n-element lists. +@@ -2639,12 +3036,13 @@ to alter the argument list to produce the result. + the list to bring equal elements together, then using a linear-time + algorithm to remove equal elements. Alternatively, one can use algorithms + based on element-marking, with linear-time results. +- ++

    +

    + delete-duplicates! is the linear-update variant of delete-duplicates; it + is allowed, but not required, to alter the cons cells in its argument + list to construct the result. +-

    ++

    ++
    + (delete-duplicates '(a b a c a b c z)) => (a b c z)
    + 
    + ;; Clean up an alist:
    +@@ -2652,124 +3050,143 @@ to alter the argument list to produce the result.
    +                    (lambda (x y) (eq? (car x) (car y))))
    +     => ((a . 3) (b . 7) (c . 1))
    + 
    ++
    +
    + + +-

    Association lists

    ++

    Association lists

    +

    + An "association list" (or "alist") is a list of pairs. The car of each pair + contains a key value, and the cdr contains the associated data value. They can + be used to construct simple look-up tables in Scheme. Note that association + lists are probably inappropriate for performance-critical use on large data; + in these cases, hash tables or some other alternative should be employed. +- ++

    +
    + +-
    ++
    + +-assoc key alist [=] -> pair or #f +-
    ++assoc key alist [=] -> pair or #f ++
    ++
    + +-assq key alist -> pair or #f +-
    ++assq key alist -> pair or #f ++
    ++
    + +-assv key alist -> pair or #f +-
    +- +- [R5RS+] +- alist must be an association list -- a list of pairs. ++assv key alist -> pair or #f ++ ++
    ++

    ++ [R5RS+] ++ alist must be an association list -- a list of pairs. + These procedures +- find the first pair in alist whose car field is key, +- and returns that pair. +- If no pair in alist has key as its car, +- then #f is returned. +- assq uses eq? to compare key +- with the car fields of the pairs in alist, +- while assv uses eqv? ++ find the first pair in alist whose car field is key, ++ and returns that pair. ++ If no pair in alist has key as its car, ++ then #f is returned. ++ assq uses eq? to compare key ++ with the car fields of the pairs in alist, ++ while assv uses eqv? + and assoc uses equal?. +-

    ++

    ++
    + (define e '((a 1) (b 2) (c 3)))
    +-(assq 'a e)                            =>  (a 1)
    +-(assq 'b e)                            =>  (b 2)
    +-(assq 'd e)                            =>  #f
    +-(assq (list 'a) '(((a)) ((b)) ((c))))  =>  #f
    +-(assoc (list 'a) '(((a)) ((b)) ((c)))) =>  ((a))
    +-(assq 5 '((2 3) (5 7) (11 13)))	   =>  *unspecified*
    +-(assv 5 '((2 3) (5 7) (11 13)))	   =>  (5 7)
    ++(assq 'a e)                            =>  (a 1)
    ++(assq 'b e)                            =>  (b 2)
    ++(assq 'd e)                            =>  #f
    ++(assq (list 'a) '(((a)) ((b)) ((c))))  =>  #f
    ++(assoc (list 'a) '(((a)) ((b)) ((c)))) =>  ((a))
    ++(assq 5 '((2 3) (5 7) (11 13)))	   =>  *unspecified*
    ++(assv 5 '((2 3) (5 7) (11 13)))	   =>  (5 7)
    + 
    +- +- assoc is extended from its +- R5RS ++

    ++ assoc is extended from its ++ R5RS + definition to allow the client to pass in + an optional equality procedure = used to compare keys. +- ++

    +

    + The comparison procedure is used to compare the elements ei of list + to the key parameter in this way: +-

    ++

    ++
    + (= key (car ei)) ; list is (E1 ... En) +
    +- That is, the first argument is always key, +- and the second argument is one of the list elements. ++

    ++ That is, the first argument is always key, ++ and the second argument is one of the list elements. + Thus one can reliably find the first entry + of alist whose key is greater than five with + (assoc 5 alist <) +- ++

    +

    + Note that fully general alist searching may be performed with + the find-tail and find procedures, e.g. +-

    ++

    ++
    + ;; Look up the first association in alist with an even key:
    + (find (lambda (a) (even? (car a))) alist)
    + 
    +- ++
    + + +-
    ++
    + +-alist-cons key datum alist -> alist +-
    ++alist-cons key datum alist -> alist ++ ++
    +
    + (lambda (key datum alist) (cons (cons key datum) alist))
    + 
    ++

    + Cons a new alist entry mapping key -> datum onto alist. +- ++

    ++
    + +-
    ++
    + +-alist-copy alist -> alist +-
    ++alist-copy alist -> alist ++ ++
    ++

    + Make a fresh copy of alist. This means copying each pair that + forms an association as well as the spine of the list, i.e. ++

    +
    + (lambda (a) (map (lambda (elt) (cons (car elt) (cdr elt))) a))
    + 
    +- ++
    + +-
    ++
    + +-alist-delete  key alist [=] -> alist +-
    ++alist-delete  key alist [=] -> alist ++
    ++
    + +-alist-delete! key alist [=] -> alist +-
    +- alist-delete deletes all associations from alist with the given key, +- using key-comparison procedure =, which defaults to equal?. +- The dynamic order in which the various applications of = are made is not +- specified. ++alist-delete! key alist [=] -> alist ++ ++
    ++

    ++ alist-delete deletes all associations from alist with the given key, ++ using key-comparison procedure =, which defaults to equal?. ++ The dynamic order in which the various applications of = are made is not ++ specified. ++

    +

    + Return values may share common tails with the alist argument. + The alist is not disordered -- elements that appear in the result alist + occur in the same order as they occur in the argument alist. ++

    +

    + The comparison procedure is used to compare the element keys ki of alist's + entries to the key parameter in this way: +@@ -2777,366 +3194,427 @@ in these cases, hash tables or some other alternative should be employed. + Thus, one can reliably remove all entries of alist whose key is greater + than five with + (alist-delete 5 alist <) ++

    +

    + alist-delete! is the linear-update variant of alist-delete. + It is allowed, but not required, + to alter cons cells from the alist parameter to construct the result. +- ++

    ++
    +
    + +- + +-

    Set operations on lists

    ++

    Set operations on lists

    +

    + These procedures implement operations on sets represented as lists of elements. +-They all take an = argument used to compare elements of lists. +-This equality procedure is required to be consistent with eq?. ++They all take an = argument used to compare elements of lists. ++This equality procedure is required to be consistent with eq?. + That is, it must be the case that +-

    +- (eq? x y) => (= x y). ++

    ++
    ++ (eq? x y) => (= x y). +
    ++

    + Note that this implies, in turn, that two lists that are eq? are + also set-equal by any legal comparison procedure. This allows for + constant-time determination of set operations on eq? lists. +- ++

    +

    +-Be aware that these procedures typically run in time +-O(n * m) +-for n- and m-element list arguments. ++Be aware that these procedures typically run in time ++O(n * m) ++for n- and m-element list arguments. + Performance-critical applications + operating upon large sets will probably wish to use other data + structures and algorithms. +- ++

    +
    + +-
    +- +-lset<= = list1 ... -> boolean +-
    ++
    ++ ++lset<= = list1 ... -> boolean ++
    ++
    ++

    + Returns true iff every listi is a subset of listi+1, using = for +- the element-equality procedure. ++ the element-equality procedure. + List A is a subset of list B if every +- element in A is equal to some element of B. +- When performing an element comparison, ++ element in A is equal to some element of B. ++ When performing an element comparison, + the = procedure's first argument is an element + of A; its second, an element of B. +-

    ++

    ++
    + (lset<= eq? '(a) '(a b a) '(a b c c)) => #t
    + 
    +-(lset<= eq?) => #t             ; Trivial cases
    +-(lset<= eq? '(a)) => #t
    ++(lset<= eq?) => #t             ; Trivial cases
    ++(lset<= eq? '(a)) => #t
    + 
    +- ++
    + +-
    ++
    + +-lset= = list1 list2 ... -> boolean +-
    ++lset= = list1 list2 ... -> boolean ++ ++
    ++

    + Returns true iff every listi is set-equal to listi+1, using = for + the element-equality procedure. "Set-equal" simply means that + listi is a subset of listi+1, and listi+1 is a subset of listi. + The = procedure's first argument is an element of listi; its second is an element of + listi+1. +-

    ++

    ++
    + (lset= eq? '(b e a) '(a e b) '(e e b a)) => #t
    + 
    +-(lset= eq?) => #t               ; Trivial cases
    +-(lset= eq? '(a)) => #t
    ++(lset= eq?) => #t               ; Trivial cases
    ++(lset= eq? '(a)) => #t
    + 
    + ++

    ++Note added on 2020-06-02: ++The reference (sample) implementation ++had a bug that reversed the arguments to =. The ++implementation has been corrected to match the text above. ++

    ++
    + +-
    ++
    + +-lset-adjoin = list elt1 ... -> list +-
    +- Adds the elti elements not already in the list parameter to the ++lset-adjoin = list elt1 ... -> list ++ ++
    ++

    ++ Adds the elti elements not already in the list parameter to the + result list. The result shares a common tail with the list parameter. + The new elements are added to the front of the list, but no guarantees + are made about their order. The = parameter is an equality procedure +- used to determine if an elti is already a member of list. Its first ++ used to determine if an elti is already a member of list. Its first + argument is an element of list; its second is one of the elti. ++

    +

    + The list parameter is always a suffix of the result -- even if the list + parameter contains repeated elements, these are not reduced. +-

    ++

    ++
    + (lset-adjoin eq? '(a b c d c e) 'a 'e 'i 'o 'u) => (u o i a b c d c e)
    + 
    +- ++
    + +-
    ++
    + +-lset-union = list1 ... -> list +-
    ++lset-union = list1 ... -> list ++ ++
    ++

    + Returns the union of the lists, using = for the element-equality + procedure. ++

    +

    + The union of lists A and B is constructed as follows: ++

    +
      +-
    • If A is the empty list, ++
    • If A is the empty list, + the answer is B (or a copy of B). +-
    • Otherwise, the result is initialised to be list A ++
    • Otherwise, the result is initialised to be list A + (or a copy of A). +-
    • Proceed through the elements of list B ++
    • Proceed through the elements of list B + in a left-to-right order. +- If b is such an element of B, +- compare every element r of the current result list +- to b: +- (= r b). +- If all comparisons fail, ++ If b is such an element of B, ++ compare every element r of the current result list ++ to b: ++ (= r b). ++ If all comparisons fail, + b is consed onto the front of the result. +-
    ++ ++

    + However, there is no guarantee that = will be applied to every pair +- of arguments from A and B. +- In particular, if A is eq? to B, ++ of arguments from A and B. ++ In particular, if A is eq? to B, + the operation may immediately terminate. +- ++

    +

    + In the n-ary case, the two-argument list-union operation is simply + folded across the argument lists. +- +-

    +-(lset-union eq? '(a b c d e) '(a e i o u)) => 
    ++

    ++
    ++(lset-union eq? '(a b c d e) '(a e i o u)) =>
    +     (u o i a b c d e)
    + 
    + ;; Repeated elements in LIST1 are preserved.
    +-(lset-union eq? '(a a c) '(x a x)) => (x a a c)
    ++(lset-union eq? '(a a c) '(x a x)) => (x a a c)
    + 
    + ;; Trivial cases
    +-(lset-union eq?) => ()
    +-(lset-union eq? '(a b c)) => (a b c)
    ++(lset-union eq?) => ()
    ++(lset-union eq? '(a b c)) => (a b c)
    + 
    +- ++
    + +-
    ++
    + +-lset-intersection = list1 list2 ... -> list +-
    +- Returns the intersection of the lists, ++lset-intersection = list1 list2 ... -> list ++ ++
    ++

    ++ Returns the intersection of the lists, + using = for the element-equality procedure. ++

    +

    + The intersection of lists A and B +- is comprised of every element of A that is = +- to some element of B: +- (= a b), ++ is comprised of every element of A that is = ++ to some element of B: ++ (= a b), + for a in A, and b in B. +- Note this implies that an element which appears in B ++ Note this implies that an element which appears in B + and multiple times in list A + will also appear multiple times in the result. ++

    +

    + The order in which elements appear in the result is the same as +- they appear in list1 -- +- that is, lset-intersection essentially filters +- list1, +- without disarranging element order. ++ they appear in list1 -- ++ that is, lset-intersection essentially filters ++ list1, ++ without disarranging element order. + The result may + share a common tail with list1. ++

    +

    + In the n-ary case, the two-argument list-intersection operation is simply + folded across the argument lists. However, the dynamic order in which the +- applications of = are made is not specified. ++ applications of = are made is not specified. + The procedure may check an +- element of list1 for membership ++ element of list1 for membership + in every other list before proceeding to +- consider the next element of list1, ++ consider the next element of list1, + or it may completely intersect list1 +- and list2 +- before proceeding to list3, ++ and list2 ++ before proceeding to list3, + or it may go about its work in some third order. +- +-

    ++

    ++
    + (lset-intersection eq? '(a b c d e) '(a e i o u)) => (a e)
    + 
    + ;; Repeated elements in LIST1 are preserved.
    +-(lset-intersection eq? '(a x y a) '(x a x z)) => '(a x a)
    ++(lset-intersection eq? '(a x y a) '(x a x z)) => '(a x a)
    + 
    +-(lset-intersection eq? '(a b c)) => (a b c)     ; Trivial case
    ++(lset-intersection eq? '(a b c)) => (a b c)     ; Trivial case
    + 
    +- ++
    + +-
    ++
    + +-lset-difference = list1 list2 ... -> list +-
    ++lset-difference = list1 list2 ... -> list ++ ++
    ++

    + Returns the difference of the lists, using = for the element-equality + procedure -- all the elements of list1 that are not + = to any element from one of the +- other listi parameters. ++ other listi parameters. ++

    +

    +- The = procedure's first argument is +- always an element of list1; ++ The = procedure's first argument is ++ always an element of list1; + its second is an element of one of the other listi. +- Elements that are repeated multiple times in the +- list1 parameter +- will occur multiple times in the result. ++ Elements that are repeated multiple times in the ++ list1 parameter ++ will occur multiple times in the result. + + The order in which elements appear in the result is the same as +- they appear in list1 -- ++ they appear in list1 -- + that is, lset-difference essentially +- filters list1, without disarranging element order. +- The result may share a common tail with list1. ++ filters list1, without disarranging element order. ++ The result may share a common tail with list1. + + The dynamic order in which the applications of = are made is not +- specified. ++ specified. + The procedure may check an element of list1 + for membership in every other list before proceeding to consider the + next element of list1, +- or it may completely compute the difference of ++ or it may completely compute the difference of + list1 and list2 before +- proceeding to list3, ++ proceeding to list3, + or it may go about its work in some third order. +- +-

    ++

    ++
    + (lset-difference eq? '(a b c d e) '(a e i o u)) => (b c d)
    + 
    +-(lset-difference eq? '(a b c)) => (a b c) ; Trivial case
    ++(lset-difference eq? '(a b c)) => (a b c) ; Trivial case
    + 
    +- ++
    + +-
    ++
    + +-lset-xor = list1 ... -> list +-
    +- Returns the exclusive-or of the sets, +- using = for the element-equality procedure. ++lset-xor = list1 ... -> list ++ ++
    ++

    ++ Returns the exclusive-or of the sets, ++ using = for the element-equality procedure. + If there are exactly two lists, this is all the elements + that appear in exactly one of the two lists. The operation is associative, + and thus extends to the n-ary case -- the elements that appear in an + odd number of the lists. The result may share a common tail with any of + the listi parameters. ++

    +

    +- More precisely, for two lists A and B, ++ More precisely, for two lists A and B, + A xor B is a list of ++

    +
      +
    • every element a of A + such that there is no element b of B + such that (= a b), and +-
    • every element b of B ++
    • every element b of B + such that there is no element a of A + such that (= b a). +-
    ++ ++

    + However, an implementation is allowed to assume that = is + symmetric -- that is, that +-

    +- (= a b) => ++

    ++
    ++ (= a b) => + (= b a). +
    +- This means, for example, that if a comparison ++

    ++ This means, for example, that if a comparison + (= a b) produces +- true for some a in A ++ true for some a in A + and b in B, + both a and b may be removed from + inclusion in the result. ++

    +

    + In the n-ary case, the binary-xor operation is simply folded across + the lists. +- +-

    ++

    ++
    + (lset-xor eq? '(a b c d e) '(a e i o u)) => (d c b i o u)
    + 
    + ;; Trivial cases.
    +-(lset-xor eq?) => ()
    +-(lset-xor eq? '(a b c d e)) => (a b c d e)
    ++(lset-xor eq?) => ()
    ++(lset-xor eq? '(a b c d e)) => (a b c d e)
    + 
    +- ++
    + + +-
    ++
    + +-lset-diff+intersection = list1 list2 ... -> [list list] +-
    ++lset-diff+intersection = list1 list2 ... -> [list list] ++ ++
    ++

    + Returns two values -- the difference and the intersection of the lists. +- Is equivalent to +-

    ++    Is equivalent to
    ++

    ++
    + (values (lset-difference = list1 list2 ...)
    +         (lset-intersection = list1
    +                              (lset-union = list2 ...)))
    + 
    ++

    + but can be implemented more efficiently. ++

    +

    + The = procedure's first argument is an element of list1; its second + is an element of one of the other listi. ++

    +

    +- Either of the answer lists may share a ++ Either of the answer lists may share a + common tail with list1. + This operation essentially partitions list1. +- ++

    ++
    + +-
    ++
    + +-lset-union!             = list1 ... -> list +-
    ++lset-union!             = list1 ... -> list ++
    ++
    + +-lset-intersection!      = list1 list2 ... -> list +-
    ++lset-intersection!      = list1 list2 ... -> list ++
    ++
    + +-lset-difference!        = list1 list2 ... -> list +-
    ++lset-difference!        = list1 list2 ... -> list ++
    ++
    + +-lset-xor!               = list1 ... -> list +-
    ++lset-xor!               = list1 ... -> list ++
    ++
    + +-lset-diff+intersection! = list1 list2 ... -> [list list] +-
    ++lset-diff+intersection! = list1 list2 ... -> [list list] ++ ++
    ++

    + These are linear-update variants. They are allowed, but not required, + to use the cons cells in their first list parameter to construct their +- answer. lset-union! is permitted to recycle cons cells from any ++ answer. lset-union! is permitted to recycle cons cells from any + of its list arguments. ++

    ++
    +
    + + +-

    Primitive side-effects

    ++

    Primitive side-effects

    +

    +-These two procedures are the primitive, +-R5RS ++These two procedures are the primitive, ++R5RS + side-effect operations on pairs. +- ++

    +
    + +-
    ++
    + +-set-car! pair object -> unspecified +-
    ++set-car! pair object -> unspecified ++
    ++
    + +-set-cdr! pair object -> unspecified +-
    ++set-cdr! pair object -> unspecified ++ ++
    ++

    + [R5RS] + These procedures store object in the car and cdr field + of pair, respectively. + The value returned is unspecified. +-

    ++

    ++
    + (define (f) (list 'not-a-constant-list))
    + (define (g) '(constant-list))
    +-(set-car! (f) 3) =>  *unspecified*
    +-(set-car! (g) 3) =>  *error*
    ++(set-car! (f) 3) =>  *unspecified*
    ++(set-car! (g) 3) =>  *error*
    + 
    ++
    +
    + + +-

    Acknowledgements

    ++

    Acknowledgements

    +

    + The design of this library benefited greatly from the feedback provided during + the SRFI discussion phase. Among those contributing thoughtful commentary and +@@ -3149,77 +3627,80 @@ Kelsey, Donovan Kolbly, Shriram Krishnamurthi, Dave Mason, Jussi Piitulainen, + David Pokorny, Duncan Smith, Mike Sperber, Maciej Stachowiak, Harvey J. Stein, + John David Stone, and Joerg F. Wittenberger. I am grateful to them for their + assistance. ++

    +

    + I am also grateful the authors, implementors and documentors of all the systems + mentioned in the rationale. Aubrey Jaffer and Kent Pitman should be noted +-for their work in producing Web-accessible versions of the R5RS and ++for their work in producing Web-accessible versions of the R5RS and + Common Lisp spec, which was a tremendous aid. ++

    +

    + This is not to imply that these individuals necessarily endorse the final +-results, of course. +- ++results, of course. ++

    + + +-

    References & links

    +-

    ++

    + +
    +-
    This document, in HTML: +-
    +- http://srfi.schemers.org/srfi-1/srfi-1.html ++
    This document, in HTML: ++
    ++ https://srfi.schemers.org/srfi-1/srfi-1.html + +-
    Source code for the reference implementation: +-
    +- http://srfi.schemers.org/srfi-1/srfi-1-reference.scm ++
    Source code for the reference implementation: ++
    ++ https://srfi.schemers.org/srfi-1/srfi-1-reference.scm + +-
    Archive of SRFI-1 discussion-list email: +-
    +- http://srfi.schemers.org/srfi-1/mail-archive/maillist.html ++
    Archive of SRFI-1 discussion-list email: ++
    ++ https://srfi-email.schemers.org/srfi-1 ++ ++
    SRFI web site: ++
    ++ https://srfi.schemers.org/ ++
    + +-
    SRFI web site: +-
    +- http://srfi.schemers.org/ +- + +-

    + +

    +-
    [CommonLisp]
    +-
    Common Lisp: the Language
    +-Guy L. Steele Jr. (editor).
    +-Digital Press, Maynard, Mass., second edition 1990.
    +-Available at +-http://www.elwood.com/alu/table/references.htm#cltl2. ++
    [CommonLisp]
    ++
    ++

    ++Common Lisp: the Language
    ++Guy L. Steele Jr. (editor).
    ++Digital Press, Maynard, Mass., second edition 1990.
    ++(Wikipedia entry) ++

    +

    +- + The Common Lisp "HyperSpec," produced by Kent Pitman, is essentially + the ANSI spec for Common Lisp: +- +-http://www.harlequin.com/education/books/HyperSpec/. +- +-

    [R5RS]
    +-
    Revised5 report on the algorithmic language Scheme.
    +- R. Kelsey, W. Clinger, J. Rees (editors).
    +- Higher-Order and Symbolic Computation, Vol. 11, No. 1, September, 1998.
    +- and ACM SIGPLAN Notices, Vol. 33, No. 9, October, 1998.
    ++http://www.lispworks.com/documentation/HyperSpec/Front/index.htm ++

    ++
    ++
    [R5RS]
    ++
    Revised5 report on the algorithmic language Scheme.
    ++ R. Kelsey, W. Clinger, J. Rees (editors).
    ++ Higher-Order and Symbolic Computation, Vol. 11, No. 1, September, 1998.
    ++ and ACM SIGPLAN Notices, Vol. 33, No. 9, October, 1998.
    + Available at + http://www.schemers.org/Documents/Standards/. +- ++
    +
    + + + ++ + +-

    Copyright

    ++ +

    +- + Certain portions of this document -- the specific, marked segments of text + describing the R5RS procedures -- were adapted with permission from the R5RS + report. ++

    +

    +- +-All other text is copyright (C) Olin Shivers (1998, 1999). +-All Rights Reserved. ++All other text is copyright (C) Olin Shivers (1998, 1999). ++All Rights Reserved. ++

    +

    + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -3242,5 +3723,7 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

    ++
    ++
    Editor: Michael Sperber
    + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-11.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-11.html +index 987edd5..f100a02 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-11.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-11.html +@@ -1,55 +1,74 @@ +- +- ++ ++ + ++ ++ + SRFI 11: Syntax for receiving multiple values ++ ++ ++ + + + + +-

    Title

    ++

    SRFI 11: Syntax for receiving multiple values

    + +-SRFI 11: Syntax for receiving multiple values ++

    by Lars T Hansen

    ++

    This copy of the SRFI 11 specification document ++is distributed as part of the Racket package ++srfi-doc.

    The canonical source of this document is ++https://srfi.schemers.org/srfi-11/srfi-11.html.

    + +-

    Author

    ++

    Status

    + +-Lars T Hansen ++

    This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-11@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

    ++
      ++
    • Received: 1999-09-10 ++
    • Draft: 1999-09-14--1999-11-12 ++
    • Revised: 1999-11-01 ++
    • Revised: 2000-03-15 ++
    • Final: 2000-03-15 ++
    + +-

    Status

    +-This SRFI is currently in ``final'' status. To see an explanation of each status +-that a SRFI can hold, see here. +-You can access the discussion via the archive of +-the mailing list. +-

      +-
    • Received: 1999/09/10 +-
    • Draft: 1999/09/14-1999/11/12 +-
    • Revised: 1999/11/01 +-
    • Revised: 2000/03/15 +-
    • Final: 2000/03/15 +-
    +- +-

    Abstract

    ++

    Abstract

    + + The SRFI introduces syntactic forms LET-VALUES and LET*-VALUES that bind the values of + expressions that return multiple values. + +-

    Issues

    ++

    Issues

    + + None. + +-

    Rationale

    ++

    Rationale

    + + LET-VALUES and LET*-VALUES reduce the clutter of the CALL-WITH-VALUES notation for + receiving multiple values. + + +-

    Specification

    ++

    Specification

    + +
    +-
    ++
    + (LET-VALUES ((<formals> <expression>) ...) <body>) +-
    Syntax ++
    Syntax ++
    +
    +-

    Each <formals> should be a formal arguments list as for a LAMBDA ++

    Each <formals> should be a formal arguments list as for a LAMBDA + expression, cf section 4.1.4 of the R5RS.

    + +

    The <expression>s are evaluated in the current environment, the +@@ -64,7 +83,6 @@ receiving multiple values. + error for an <expression> to return a number of values that does + not match its corresponding <formals>.

    + +-

    +

    +              (let-values (((a b . c) (values 1 2 3 4)))
    +                (list a b c))            --> (1 2 (3 4))
    +@@ -74,13 +92,13 @@ receiving multiple values.
    +                             ((x y) (values a b)))
    +                  (list a b x y)))       --> (x y a b)
    + 
    +-

    +- +-
    ++
    ++
    + (LET*-VALUES ((<formals> <expression>) ...) <body>) +-
    Syntax ++
    Syntax ++
    +
    +-

    Each <formals> should be a formal arguments list as for a LAMBDA ++

    Each <formals> should be a formal arguments list as for a LAMBDA + expression, cf section 4.1.4 of the R5RS.

    + +

    LET*-VALUES is similar to LET-VALUES, but the bindings are performed +@@ -89,26 +107,25 @@ receiving multiple values. + expression to the right of the binding. Thus the second binding is done in + an environment in which the first binding is visible, and so on.

    + +-

    +

    +              (let ((a 'a) (b 'b) (x 'x) (y 'y))
    +                (let*-values (((a b) (values x y))
    +                              ((x y) (values a b)))
    +                  (list a b x y)))       --> (x y x y)
    + 
    +-

    ++
    + + +-

    Implementation

    + ++

    Implementation

    ++

    + The following implementation is written in R5RS Scheme. It is not + compatible with the IEEE Scheme standard because the IEEE standard does + not contain the high-level macro system. +- ++

    +

    The implementation assumes that some top-level names defined by the + R5RS are bound to their original values. +- +-

    ++

    +
    + ;; This code is in the public domain.
    + 
    +@@ -148,9 +165,8 @@ R5RS are bound to their original values.
    +        (let*-values (?binding1 ...) ?body0 ?body1 ...)))))
    + 
    + +-

    Copyright

    ++

    Copyright

    +

    Copyright (C) Lars T Hansen (1999). All Rights Reserved.

    +- +

    + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -173,12 +189,11 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

    +- +-
    +-
    Editor: Mike Sperber
    ++
    ++
    Editor: Mike Sperber
    + + +-Last modified: Tue Sep 28 10:59:57 MST 2004 ++Last modified: Sun Jan 28 13:40:20 MET 2007 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-13.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-13.html +index 2f744dc..b519905 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-13.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-13.html +@@ -1,22 +1,39 @@ +- ++ ++ ++ ++ ++ + +- + +- +- +- +- ++ + SRFI 13: String Libraries +- ++ ++ ++ + + + +- + + + + + +-

    Title

    ++

    SRFI 13: String Libraries

    + +-
    SRFI 13: String Libraries
    ++

    by Olin Shivers

    ++

    This copy of the SRFI 13 specification document ++is distributed as part of the Racket package ++srfi-doc.

    The canonical source of this document is ++https://srfi.schemers.org/srfi-13/srfi-13.html.

    + +- +-

    Author

    +- +-Olin Shivers +- +-

    Status

    +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

      +-
    • Received: 1999/10/17 +-
    • Draft: 1999/10/18-1999/12/16 +-
    • Revised: 1999/10/31 +-
    • Revised: 1999/11/13 +-
    • Revised: 1999/11/22 +-
    • Revised: 2000/04/30 +-
    • Revised: 2000/06/09 +-
    • Revised: 2000/12/23 +-
    +- +-

    Table of contents

    ++

    Status

    ++ ++

    This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-13@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

    ++
      ++
    • Received: 1999-10-17 ++
    • Draft: 1999-10-18--1999-12-16 ++
    • Revised: 1999-10-31 ++
    • Revised: 1999-11-13 ++
    • Revised: 1999-11-22 ++
    • Revised: 2000-04-30 ++
    • Revised: 2000-06-09 ++
    • Revised: 2000-12-23 ++
    ++ ++

    Table of contents

    + + +- ++ ++
  • Procedure specification + ++ ++
  • Low-level procedures + +- ++
  • Knuth-Morris-Pratt searching ++
  • ++ + +-
  • Reference implementation +-
  • Acknowledgements +-
  • References & Links +-
  • Copyright +- ++
  • Reference implementation ++
  • Acknowledgements ++
  • References & Links ++
  • Copyright ++
  • + + +-

    Abstract

    ++

    Abstract

    +

    + + R5RS + Scheme has an impoverished set of string-processing utilities, which is a +-problem for authors of portable code. This SRFI proposes a coherent and comprehensive set of ++problem for authors of portable code. ++This SRFI proposes ++a coherent and comprehensive set of + string-processing procedures; it is accompanied by a reference implementation + of the spec. The reference implementation is ++

    +
      +
    • portable +-
    • efficient +-
    • open source +-
    ++
  • efficient ++
  • open source ++
  • +

    + The routines in this SRFI are backwards-compatible with the string-processing + routines of + R5RS. +- ++

    + +-

    Procedure Index

    ++

    Procedure Index

    +

    + Here is a list of the procedures provided by the string-lib + and string-lib-internals packages. + R5RS + procedures are shown in +-bold; ++bold; + extended R5RS + +- procedures, in bold italic. +-

    ++ procedures, in bold italic. ++

    ++
    +
    +-
    Predicates +-
    +-
    +-string? string-null? 
    ++
    Predicates ++
    ++
    ++string? string-null? 
    + string-every string-any
    + 
    + +-
    Constructors +-
    +-
    +-make-string string string-tabulate
    ++
    Constructors ++
    ++
    ++make-string string string-tabulate
    + 
    + +-
    List & string conversion +-
    +-
    +-string->list list->string
    +-reverse-list->string string-join
    ++
    List & string conversion ++
    ++
    ++string->list list->string
    ++reverse-list->string string-join
    + 
    + +-
    Selection +-
    +-
    +-string-length
    ++
    Selection ++
    ++
    ++string-length
    + string-ref
    +-string-copy
    +-substring/shared
    ++string-copy
    ++substring/shared
    + string-copy! 
    + string-take string-take-right
    + string-drop string-drop-right
    +@@ -288,24 +310,24 @@ extended R5RSstring-trim string-trim-right string-trim-both 
    + 
    + +-
    Modification +-
    +-
    +-string-set! string-fill!
    ++
    Modification ++
    ++
    ++string-set! string-fill!
    + 
    + +-
    Comparison +-
    +-
    ++
    Comparison ++
    ++
    + string-compare string-compare-ci
    +-string<>     string=    string<    string>    string<=    string>=
    +-string-ci<>  string-ci= string-ci< string-ci> string-ci<= string-ci>=
    ++string<>     string=    string<    string>    string<=    string>=
    ++string-ci<>  string-ci= string-ci< string-ci> string-ci<= string-ci>=
    + string-hash  string-hash-ci
    + 
    + +-
    Prefixes & suffixes +-
    +-
    ++
    Prefixes & suffixes ++
    ++
    + string-prefix-length    string-suffix-length
    + string-prefix-length-ci string-suffix-length-ci
    + 
    +@@ -313,65 +335,65 @@ extended R5RSstring-prefix-ci? string-suffix-ci? 
    + 
    + +-
    Searching +-
    +-
    ++
    Searching ++
    ++
    + string-index string-index-right
    + string-skip  string-skip-right 
    + string-count 
    + string-contains string-contains-ci
    + 
    + +-
    Alphabetic case mapping +-
    +-
    ++
    Alphabetic case mapping ++
    ++
    + string-titlecase  string-upcase  string-downcase
    + string-titlecase! string-upcase! string-downcase!
    + 
    + +-
    Reverse & append +-
    +-
    ++
    Reverse & append ++
    ++
    + string-reverse string-reverse!
    +-string-append
    ++string-append
    + string-concatenate
    +-string-concatenate/shared string-append/shared
    +-string-concatenate-reverse string-concatenate-reverse/shared
    ++string-concatenate/shared string-append/shared
    ++string-concatenate-reverse string-concatenate-reverse/shared
    + 
    + +-
    Fold, unfold & map +-
    +-
    ++
    Fold, unfold & map ++
    ++
    + string-map      string-map!
    + string-fold     string-fold-right
    + string-unfold   string-unfold-right
    + string-for-each string-for-each-index
    + 
    + +-
    Replicate & rotate +-
    +-
    ++
    Replicate & rotate ++
    ++
    + xsubstring string-xcopy!
    + 
    + +-
    Miscellaneous: insertion, parsing +-
    +-
    ++
    Miscellaneous: insertion, parsing ++
    ++
    + string-replace string-tokenize
    + 
    + +-
    Filtering & deleting +-
    +-
    ++
    Filtering & deleting ++
    ++
    + string-filter string-delete 
    + 
    + +-
    Low-level procedures +-
    +-
    +-string-parse-start+end
    +-string-parse-final-start+end
    +-let-string-start+end
    ++
    Low-level procedures ++
    ++
    ++string-parse-start+end
    ++string-parse-final-start+end
    ++let-string-start+end
    + 
    + check-substring-spec
    + substring-spec-ok?
    +@@ -379,35 +401,34 @@ extended R5RSmake-kmp-restart-vector kmp-step string-kmp-partial-search
    + 
    + +-
    ++ +
    + + +-

    Rationale

    ++

    Rationale

    +

    +- + This SRFI defines two libraries that provide a rich set of operations for + manipulating strings. These are frequently useful for scripting and other + text-manipulation applications. The library's design was influenced by the + string libraries found in MIT Scheme, Gambit, RScheme, MzScheme, slib, Common + Lisp, Bigloo, guile, Chez, APL, Java, and the SML standard basis. ++

    +

    +- + All procedures involving character comparison are available in + both case-sensitive and case-insensitive forms. ++

    +

    +- + All functionality is available in substring and full-string forms. +- ++

    + +-

    Strings are code-point sequences

    ++

    Strings are code-point sequences

    +

    + This SRFI considers strings simply to be a sequence of "code points" or + character encodings. Operations such as comparison or reversal are always done + code point by code point. See the comments below on super-ASCII character + types for implications that follow. ++

    +

    +- + It's entirely possible that a legal string might not be a sensible "text" + sequence. For example, consider a string comprised entirely of zero-width + Unicode accent characters with no preceding base character to modify -- +@@ -415,11 +436,10 @@ this is a legal string, albeit one that does not make a great deal of sense + when interpreted as a sequence of natural-language text. The routines in + this SRFI do not handle these "text" concerns; they restrict themselves + to the underlying view of strings as merely a sequence of "code points." +- ++

    + +-

    String operations are locale- and context-independent

    ++

    String operations are locale- and context-independent

    +

    +- + This SRFI defines string operations that are locale- and context-independent. + While it is certainly important to have a locale-sensitive comparison or + collation procedure when processing text, it is also important to have a suite +@@ -427,14 +447,13 @@ of operations that are reliably invariant for basic string processing --- + otherwise, a change of locale could cause data structures such as hash tables, + b-trees, symbol tables, directories of filenames, etc. + to become corrupted. +- ++

    +

    + Locale- and context-sensitive text operations, such as collation, are + explicitly deferred to a subsequent, companion "text" SRFI. +- ++

    + +-

    Internationalisation & super-ASCII character types

    +- ++

    Internationalisation & super-ASCII character types

    +

    + The major issue confronting this SRFI is the existence of super-ASCII + character encodings, such as eight-bit Latin-1 or 16- and 32-bit Unicode. It +@@ -443,13 +462,13 @@ implementations based on at least these three standard encodings. + Unfortunately, this places strong limitations on the API design. Here are + some relevant issues. Be warned that life in a super-ASCII world is + significantly more complex; there are no easy answers for many of these issues. +- ++

    + +-

    Case mapping and case-folding

    ++

    Case mapping and case-folding

    + +

    + Upper- and lower-casing characters is complex in super-ASCII encodings. +- ++

    +
      +
    • Some characters case-map to more than one character. For example, + the Latin-1 German eszet character upper-cases to "SS." +@@ -458,20 +477,22 @@ Upper- and lower-casing characters is complex in super-ASCII encodings. + R5RS function char-upcase is not well-defined, + since it is defined to produce a (single) character result. + +-
    • It means that an in-place string-upcase! procedure cannot be reliably ++
    • It means that an in-place string-upcase! procedure cannot be reliably + defined, since the original string may not be long enough to contain + the result -- an N-character string might upcase to a 2N-character result. + +-
    • It means that case-insensitive string-matching or searching is quite ++
    • It means that case-insensitive string-matching or searching is quite + tricky. For example, an n-character string s might match a 2N-character + string s'. +-
    ++ + ++ +
  • Some characters case-map in different ways depending upon their surrounding + context. For example, the Unicode Greek capital sigma character downcases + differently depending upon whether or not it is the final character in a + word. Again, this spells trouble for the simple R5RS char-downcase function. + ++
  • +
  • Unicode defines three cases: lowercase, uppercase and titlecase. The + distinction between uppercase and titlecase arises in the presence of + Unicode's compound characters. For example, Unicode has a single character +@@ -479,18 +500,22 @@ Upper- and lower-casing characters is complex in super-ASCII encodings. + the compound character "DZ", while titlecasing (or, as Americans say, + capitalizing) it produces compound character "Dz". + ++
  • +
  • Turkish actually has different case-mappings from other languages. ++
  • + + +

    +-The Unicode Consortium's web site +-

    ++ The Unicode Consortium's web site ++

    ++ +-

    ++

    + has detailed discussions of the issues. See in particular technical report + 21 on case mappings +-

    ++

    ++ + +@@ -498,24 +523,26 @@ has detailed discussions of the issues. See in particular technical report + SRFI 13 makes no attempt to deal with these issues; it uses a simple 1-1 + locale- and context-independent case-mapping, specifically Unicode's 1-1 + case-mappings given in +-
    ++

    ++ +-

    ++

    + The format of this file is explained in +-

    ++

    ++ +-

    ++

    + Note that this means that German eszet upper-cases to itself, not "SS". + +-

    ++

    + Case-mapping and case-folding operations in SRFI 13 are locale-independent so + that shifting locales won't wreck hash tables, b-trees, symbol tables, etc. +- ++

    + + +-

    String equality & string normalisation

    ++

    String equality & string normalisation

    + +

    + Comparing strings for equality is complicated because in some cases Unicode +@@ -526,31 +553,32 @@ an acute accent. There is a single Unicode character for this. However, + Unicode also allows one to represent this with a two-character sequence: the + "e" character followed by a zero-width acute-accent character. As another + example, Unicode provides some Asian characters in "narrow" and "full" widths. +- ++

    +

    + There are multiple ways we might want to compare strings for equality. In + (roughly) decreasing order of precision, +- ++

    +
      +
    • we might want a precise comparison of the actual encoding, so that + <e-acute> would not compare equal to <e, acute>. +- +-
    • We might want a "normalised" comparison, where these two sequences ++
    • ++
    • We might want a "normalised" comparison, where these two sequences + would compare equal. +- ++
    • +
    • We might want an even more-permissive normalisation, where visually-distinct + properties of "the same" character would be ignored. For example, we might + want narrow/full-width versions of the same Asian character to compare equal. +- ++
    • +
    • We might want comparisons that are insensitive to accents and diacritical + marks. +- ++
    • +
    • We might want comparisons that are case-insensitive. +- ++
    • +
    • We might want comparisons that are insensitive to several of the above + properties. +- ++
    • +
    • We might want ways to "normalise" strings into various canonical forms. ++
    • +
    + +

    +@@ -559,24 +587,26 @@ simply based upon comparing the encoding values used for the characters. + Accent-insensitive and other types of comparison are not provided; only + a simple form of case-insensitive comparison is provided, which uses the + 1-1 case mappings specified by Unicode in +-

    ++

    ++ +-

    ++

    + These are adequate for "program" or "systems" use of strings (e.g., to + manipulate program identifiers and operating-system filenames). +- ++

    + +-

    String inequality

    ++

    String inequality

    + +

    + Above and beyond the issues arising in string-equality, when we attempt + to order strings there are even further considerations. +- ++

    +
      +
    • French orders accents with right-to-left significance -- the reverse of + the significance of the characters. + ++
    • +
    • Case-insensitive ordering is not well defined by simple "code-point" + considerations, even for simple ASCII: there are punctuation characters + between the ASCII's upper-case range of letters and its lower-case range +@@ -584,8 +614,10 @@ to order strings there are even further considerations. + Does left-bracket compare less-than or greater-than "a" in a + case-insensitive comparison? + ++
    • +
    • The German eszet character should sort as if it were the pair of + letters "ss". ++
    • +
    + +

    +@@ -596,9 +628,9 @@ can be overlaid by additional domain- or language-specific rules. Again, + this SRFI does not address these issues. SRFI 13 string ordering is strictly + based upon a character-by-character comparison of the values used for + representing the string. +- ++

    + +-

    Naming conventions

    ++

    Naming conventions

    + +

    + This library contains a large number of procedures, but they follow +@@ -608,22 +640,25 @@ in a regular way that exposes the structure and relationships between the + procedures. This should help the programmer to recall or reconstitute the name + of the particular procedure that he needs when writing his own code. In + particular +- ++

    +
      +
    • Procedures whose names end in "-ci" are case-insensitive variants. + ++
    • +
    • Procedures whose names end in "!" are side-effecting variants. + What values these procedures return is usually not specified. + ++
    • +
    • The order of common parameters is consistent across the + different procedures. + ++
    • +
    • Left/right/both directionality: + Procedures that have left/right directional variants + use the following convention: +-
      +- +- ++
      ++
      Direction
      ++ + + + +@@ -635,10 +670,11 @@ particular + This is a general convention that was established in SRFI 1. + The value of a convention is proportional to the extent of its + use. ++ + + + +-

      Shared storage

      ++

      Shared storage

      + +

      + Some Scheme implementations, e.g. guile and T, provide ways to construct +@@ -651,12 +687,12 @@ property of these substrings -- the application assumes that if the underlying + storage is mutated, then all strings sharing that storage will show the + change. However, shared-text substrings are not a common feature; most Scheme + implementations do not provide them. +- ++

      +

      + SRFI 13 takes a middle ground with respect to shared-text substrings. In + particular, a Scheme implementation does not need to have shared-text + substrings in order to implement this SRFI. +- ++

      +

      + There is an additional form of storage sharing enabled by some SRFI 13 + procedures, even without the benefit of shared-text substrings. In +@@ -665,40 +701,44 @@ of the strings that was passed in as a parameter. For example, when + constructing a substring with the substring/shared procedure, if the + requested substring is the entire string, the procedure is permitted + simply to return the original value. That is, +-

      ++

      ++
      + (eq? s (substring/shared s 0 (string-length s))) => true or false
      + 
      +-

      ++

      + whereas the R5RS + substring function is required to allocate a fresh copy +-

      ++

      ++
      + (eq? s (substring s 0 (string-length s))) => false.
      + 
      +

      + In keeping with SRFI 13's general approach to sharing, compliant + implementations are allowed, but not required, to provide this kind of + sharing. Hence, procedures may not rely upon sharing in these cases. +-

      ++

      ++

      + Most procedures that permit results to share storage with inputs have + equivalent procedures that require allocating fresh storage for results. + If an application wishes to be sure a new, fresh string is allocated, then + these "pure" procedures should be used. +-

      +-
      Direction  Suffix
      left-to-rightnone
      +- ++

      ++
      ++
      Fresh copy guaranteed
      ++ + + + + + + +- ++ + +- ++ + + + ++ + + + +@@ -719,16 +759,16 @@ without this consideration -- if we had cheap shared-text substrings, all the + start/end index parameters would vanish. However, since SRFI 13 does not + require implementations to provide shared-text substrings, the extended + API is provided. +- ++

      + +-

      R4RS/R5RS procedures

      ++

      R4RS/R5RS procedures

      + +

      + The R4RS and R5RS reports define 22 string procedures. The string-lib + package includes 8 of these exactly as defined, 3 in an extended, + backwards-compatible way, and drops the remaining 11 (whose functionality + is available via other bindings). +- ++

      +

      + The 8 procedures provided exactly as documented in the reports are + string?, +@@ -739,7 +779,7 @@ The 8 procedures provided exactly as documented in the reports are + string-set!, + string-append, and + list->string. +- ++

      +

      + The eleven functions not included are + string=?, string-ci=?, +@@ -749,37 +789,44 @@ The eleven functions not included are + string>=?, string-ci>=?, and + substring. + The string-lib package provides alternate bindings and extended functionality. +- ++

      +

      + Additionally, the three extended procedures are +-

      ++

      ++
      + string-fill! s char [start end] -> unspecified
      + string->list s [start end] -> char-list
      + string-copy  s [start end] -> string
      + 
      +-

      ++

      + They are uniformly extended to take optional start/end parameters specifying + substring ranges. +- ++

      + +-

      Extra-SRFI recommendations

      ++

      Extra-SRFI recommendations

      + +

      + This SRFI recommends the following +- ++

      +
        +-
      • A SRFI be defined for shared-text substrings, allowing programs to ++
      • ++

        ++ A SRFI be defined for shared-text substrings, allowing programs to + be written that actually rely on the shared-storage properties of these data + structures. +- +-

      • A SRFI be defined for manipulating Unicode text -- various normalisation ++

        ++
      • ++
      • ++

        ++ A SRFI be defined for manipulating Unicode text -- various normalisation + operations, collation, searching, etc. Collation operations might be + parameterised by a "collation" structure representing collation rules + for a particular locale or language. Alternatively, a data structure + specifying collation rules could be activated with dynamic scope by + special procedures, possibly overridden by allowing collation rules + to be optional arguments to procedures that need to order strings, e.g. +-

        ++    

        ++
        + (with-locale* denmark-locale
        +   (lambda () 
        +     (f x)
        +@@ -792,28 +839,32 @@ This SRFI recommends the following
        + 
        + (set-locale! denmark-locale)
        + 
        +- +-
      • A SRFI be defined for manipulating characters that is portable across ++
      • ++
      • ++

        ++ A SRFI be defined for manipulating characters that is portable across + at least ASCII, Latin-1 and Unicode. +- +-

          ++

          ++
            +
          • For backwards-compatibility, char-upcase and char-downcase should + be defined to use the 1-1 locale- and context-insensitive case + mappings given by Unicode's UnicodeData.txt table. +- ++
          • +
          • numeric codes for standard functions that map between characters and + integers should be required to use the Unicode/Latin-1/ASCII mapping. This + allows programmers to write portable code. +- ++
          • +
          • char-titlecase be added to char-upcase and char-downcase. +- ++
          • +
          • char-titlecase? be added to char-upcase? and char-downcase?. +- ++
          • +
          • Title/up/down-case functions be added to the character-processing suite + which allow 1->n case maps by returning immutable, + possibly-multi-character strings instead of single characters. These case + mappings need not be locale- or context-sensitive. +-
          ++ ++
        ++
      • +
      + +

      +@@ -821,75 +872,83 @@ This SRFI recommends the following + requiring a Unicode/Latin-1/ASCII interface to integer/char mapping + functions does not imply anything about the actual underlying encodings of + characters. +- ++

      + + +-

      Procedure Specification

      ++

      Procedure Specification

      + +

      + In the following procedure specifications: ++

      +
        +
      • An s parameter is a string. +- ++
      • +
      • A char parameter is a character. +- +-
      • Start and end parameters are half-open string indices specifying ++
      • ++
      • Start and end parameters are half-open string indices specifying + a substring within a string parameter; when optional, they default + to 0 and the length of the string, respectively. When specified, it + must be the case that 0 <= start <= end + <= (string-length s), for + the corresponding parameter s. They typically restrict a procedure's + action to the indicated substring. +- +-
      • A pred parameter is a unary character predicate procedure, returning ++
      • ++
      • A pred parameter is a unary character predicate procedure, returning + a true/false value when applied to a character. +- ++
      • +
      • A char/char-set/pred parameter is a value used to select/search + for a character in a string. If it is a character, it is used in + an equality test; if it is a character set, it is used as a + membership test; if it is a procedure, it is applied to the + characters as a test predicate. +- ++
      • +
      • An i parameter is an exact non-negative integer specifying an index + into a string. +- ++
      • +
      • Len and nchars parameters are exact non-negative integers specifying a + length of a string or some number of characters. +- ++
      • +
      • An obj parameter may be any value at all. ++
      • +
      +-

      ++

      + Passing values to procedures with these parameters that do not satisfy these + types is an error. +- ++

      +

      + Parameters given in square brackets are optional. Unless otherwise noted in the + text describing the procedure, any prefix of these optional parameters may + be supplied, from zero arguments to the full list. When a procedure returns + multiple values, this is shown by listing the return values in square + brackets, as well. So, for example, the procedure with signature +-

      +-halts? f [x init-store] -> [boolean integer]
      ++

      ++
      ++halts? f [x init-store] -> [boolean integer]
      + 
      ++

      + would take one (f), two (f, x) + or three (f, x, init-store) input parameters, + and return two values, a boolean and an integer. +- ++

      +

      + A parameter followed by "..." means zero-or-more elements. + So the procedure with the signature +-

      +-sum-squares x ...  -> number
      ++

      ++
      ++sum-squares x ...  -> number
      + 
      ++

      + takes zero or more arguments (x ...), + while the procedure with signature +-

      +-spell-check doc dict1 dict2 ... -> string-list
      ++

      ++
      ++spell-check doc dict1 dict2 ... -> string-list
      + 
      ++

      + takes two required parameters + (doc and dict1) + and zero or more optional parameters (dict2 ...). +- ++

      +

      + If a procedure is said to return "unspecified," this means that nothing at + all is said about what the procedure returns. Such a procedure is not even +@@ -901,176 +960,207 @@ Note that in + R5RS, + this restricts such a procedure to returning a single value; + non-R5RS systems may not even provide this restriction. +- ++

      + +-

      Main procedures

      ++

      Main procedures

      + +

      + In a Scheme system that has a module or package system, these procedures + should be contained in a module named "string-lib". +- ++

      + +-

      Predicates

      ++

      Predicates

      + +
      + +-
      ++
      + +-string? obj -> boolean +-
      ++string? obj -> boolean ++ ++
      ++

      + [R5RS] + Returns #t if obj is a string, otherwise returns #f. +- ++

      ++
      + +-
      ++
      + +-string-null? s -> boolean +-
      ++string-null? s -> boolean ++ ++
      + Is s the empty string? +
      + + +-
      ++
      + + +-string-every char/char-set/pred s [start end] -> value +-
      string-any char/char-set/pred s [start end] -> value +-
      ++string-every char/char-set/pred s [start end] -> value ++ ++
      string-any char/char-set/pred s [start end] -> value ++
      ++
      ++

      + Checks to see if the given criteria is true of every / any character in s, + proceeding from left (index start) to right (index end). +- ++

      +

      + If char/char-set/pred is a character, it is tested for equality with + the elements of s. +- ++

      +

      + If char/char-set/pred is a character set, the elements of s are tested + for membership in the set. +- ++

      +

      + If char/char-set/pred is a predicate procedure, it is applied to the + elements of s. The predicate is "witness-generating:" +- ++

      +
        +
      • If string-any returns true, the returned true value is the one produced + by the application of the predicate. +- ++
      • +
      • If string-every returns true, the returned true value is the one +- produced by the final application of the predicate to s[end]. ++ produced by the final application of the predicate to s[end-1]. + If string-every is applied to an empty sequence of characters, + it simply returns #t. ++
      • +
      ++

      + If string-every or string-any apply the predicate to the final element + of the selected sequence (i.e., s[end-1]), that final application is a + tail call. +- ++

      +

      + The names of these procedures do not end with a question mark -- this is to + indicate that, in the predicate case, they do not return a simple boolean + (#t or #f), but a general value. ++

      ++
      +
      + + + +-

      Constructors

      ++

      Constructors

      + +
      + +-
      ++
      + +-make-string len [char] -> string +-
      ++make-string len [char] -> string ++ ++
      ++

      + [R5RS] + make-string returns a newly allocated string of length len. If + char is given, then all elements of the string are initialized + to char, otherwise the contents of the string are unspecified. +- ++

      ++
      + +-
      ++
      + +-string char1 ... -> string +-
      ++string char1 ... -> string ++ ++
      ++

      + [R5RS] + Returns a newly allocated string composed of the argument characters. +- ++

      ++
      + +-
      ++
      + +-string-tabulate proc len -> string +-
      +- Proc is an integer->char procedure. Construct a string of size len ++string-tabulate proc len -> string ++ ++
      ++

      ++ Proc is an integer->char procedure. Construct a string of size len + by applying proc to each index to produce the corresponding string + element. The order in which proc is applied to the indices is not + specified. +- ++

      ++
      +
      + + +-

      List & string conversion

      ++

      List & string conversion

      + +
      + + +-
      ++
      + + +-string->list s [start end] -> char-list +-
      list->string char-list -> string +-
      ++string->list s [start end] -> char-list ++ ++
      list->string char-list -> string ++
      ++
      ++

      + [R5RS+] +- string->list returns a newly allocated list of the characters +- that make up the given string. list->string returns a newly ++ string->list returns a newly allocated list of the characters ++ that make up the given string. list->string returns a newly + allocated string formed from the characters in the list char-list, +- which must be a list of characters. string->list and list->string ++ which must be a list of characters. string->list and list->string + are inverses so far as equal? is concerned. +- +-

      +- string->list is extended from the R5RS definition to take optional ++

      ++

      ++ string->list is extended from the R5RS definition to take optional + start/end arguments. +- ++

      ++
      + +-
      ++
      + +-reverse-list->string char-list -> string +-
      +- An efficient implementation of (compose list->string reverse): +-
      +-(reverse-list->string '(#\a #\B #\c)) -> "cBa"
      ++reverse-list->string char-list -> string
      ++
      ++
      ++

      ++ An efficient implementation of (compose list->string reverse): ++

      ++
      ++(reverse-list->string '(#\a #\B #\c)) -> "cBa"
      + 
      ++

      + This is a common idiom in the epilog of string-processing loops + that accumulate an answer in a reverse-order list. (See also + string-concatenate-reverse for the "chunked" variant.) +- ++

      ++
      + +-
      ++
      + +-string-join string-list [delimiter grammar] -> string +-
      ++string-join string-list [delimiter grammar] -> string ++ ++
      ++

      + This procedure is a simple unparser --- it pastes strings together using + the delimiter string. +- +-

      ++

      ++

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

      +
        +
      • 'infix means an infix or separator grammar: + insert the delimiter +@@ -1079,20 +1169,25 @@ Returns #t if obj is a string, otherwise returns # + grammar is ambiguous. Is it an empty list, or a list of one element, + the empty string? + +-
      • 'strict-infix means the same as 'infix, ++
      • ++
      • 'strict-infix means the same as 'infix, + but will raise an error if given an empty list. + ++
      • +
      • 'suffix means a suffix or terminator grammar: + insert the delimiter + after every list element. This grammar has no ambiguities. + ++
      • +
      • 'prefix means a prefix grammar: insert the delimiter + before every list element. This grammar has no ambiguities. ++
      • +
      +- ++

      + The delimiter is the string used to delimit elements; it defaults to + a single space " ". +-

      ++

      ++
      + (string-join '("foo" "bar" "baz") ":")         => "foo:bar:baz"
      + (string-join '("foo" "bar" "baz") ":" 'suffix) => "foo:bar:baz:"
      + 
      +@@ -1104,103 +1199,124 @@ Returns #t if obj is a string, otherwise returns #
      + (string-join '()   ":" 'suffix) => ""
      + (string-join '("") ":" 'suffix) => ":"
      + 
      ++
      +
      + + + +-

      Selection

      ++

      Selection

      + +
      + +-
      ++
      + +-string-length s -> integer +-
      ++string-length s -> integer ++ ++
      ++

      + [R5RS] + Returns the number of characters in the string s. +- ++

      ++
      + +-
      ++
      + +-string-ref s i -> char +-
      ++string-ref s i -> char ++ ++
      ++

      + [R5RS] + Returns character s[i] using zero-origin indexing. + I must be a valid index of s. +- ++

      ++
      + +-
      ++
      + + +-string-copy s [start end] -> string +-
      substring/shared s start [end] -> string +-
      ++string-copy s [start end] -> string ++ ++
      substring/shared s start [end] -> string ++
      ++
      ++

      + [R5RS+] + substring/shared returns a string whose contents are the characters of s + beginning with index start (inclusive) and ending with index end + (exclusive). It differs from the R5RS substring in two ways: ++

      +
        +
      • The end parameter is optional, not required. ++
      • +
      • substring/shared may return a value that shares memory with s or + is eq? to s. ++
      • +
      +- +-

      ++

      + string-copy is extended from its R5RS definition by the addition of + its optional start/end parameters. In contrast to substring/shared, + it is guaranteed to produce a freshly-allocated string. +- +-

      ++

      ++

      + Use string-copy when you want to indicate explicitly in your code that you + wish to allocate new storage; use substring/shared when you don't care if + you get a fresh copy or share storage with the original string. +-

      ++

      ++
      + (string-copy "Beta substitution") => "Beta substitution"
      + (string-copy "Beta substitution" 1 10) 
      +     => "eta subst"
      + (string-copy "Beta substitution" 5) => "substitution"
      + 
      +- ++
      + +-
      ++
      + +-string-copy! target tstart s [start end] -> unspecified +-
      ++string-copy! target tstart s [start end] -> unspecified ++ ++
      ++

      + Copy the sequence of characters from index range [start,end) in + string s to string target, beginning at index tstart. The characters + are copied left-to-right or right-to-left as needed -- the copy is + guaranteed to work, even if target and s are the same string. +- ++

      +

      + It is an error if the copy operation runs off the end of the target + string, e.g. +-

      ++    

      ++
      + (string-copy! (string-copy "Microsoft") 0
      +               "Regional Microsoft Operating Companies") => error
      + 
      +- ++
      + + +-
      ++
      + + + + +-string-take s nchars -> string +-
      string-drop s nchars -> string +-
      string-take-right s nchars -> string +-
      string-drop-right s nchars -> string +-
      ++string-take s nchars -> string ++ ++
      string-drop s nchars -> string ++
      ++
      string-take-right s nchars -> string ++
      ++
      string-drop-right s nchars -> string ++
      ++
      ++

      + string-take returns the first nchars of s; + string-drop returns all but the first nchars of s. + string-take-right returns the last nchars of s; +@@ -1208,133 +1324,157 @@ Returns #t if obj is a string, otherwise returns # + If these procedures produce the entire string, they may return either + s or a copy of s; in some implementations, proper substrings may share + memory with s. +-

      ++

      ++
      + (string-take "Pete Szilagyi" 6) => "Pete S"
      + (string-drop "Pete Szilagyi" 6) => "zilagyi"
      + 
      + (string-take-right "Beta rules" 5) => "rules"
      + (string-drop-right "Beta rules" 5) => "Beta "
      + 
      +- ++

      + It is an error to take or drop more characters than are in the string: +-

      ++

      ++
      + (string-take "foo" 37) => error
      + 
      +- ++
      + +-
      ++
      + + +-string-pad s len [char start end] -> string +-
      string-pad-right s len [char start end] -> string +-
      ++string-pad s len [char start end] -> string ++ ++
      string-pad-right s len [char start end] -> string ++
      ++
      ++

      + Build a string of length len comprised of s padded on the left (right) + by as many occurrences of the character char as needed. If s has more + than len chars, it is truncated on the left (right) to length len. Char + defaults to #\space. +- +-

      ++

      ++

      + If len <= end-start, the returned value is allowed to share storage + with s, or be exactly s (if len = end-start). +-

      ++

      ++
      + (string-pad     "325" 5) => "  325"
      + (string-pad   "71325" 5) => "71325"
      + (string-pad "8871325" 5) => "71325"
      + 
      +- ++
      + +-
      ++
      + + + +-string-trim       s [char/char-set/pred start end] -> string +-
      string-trim-right s [char/char-set/pred start end] -> string +-
      string-trim-both  s [char/char-set/pred start end] -> string +-
      ++string-trim       s [char/char-set/pred start end] -> string ++ ++
      string-trim-right s [char/char-set/pred start end] -> string ++
      ++
      string-trim-both  s [char/char-set/pred start end] -> string ++
      ++
      ++

      + Trim s by skipping over all characters on the left / on the right / + on both sides that satisfy the second parameter char/char-set/pred: +-

        ++

        ++
          +
        • if it is a character char, characters equal to char are trimmed; ++
        • +
        • if it is a char set cs, characters contained in cs are trimmed; ++
        • +
        • if it is a predicate pred, it is a test predicate that is applied + to the characters in s; a character causing it to return true + is skipped. +-
        ++ ++
      ++

      + Char/char-set/pred defaults to the character set char-set:whitespace + defined in SRFI 14. +- +-

      ++

      ++

      + If no trimming occurs, these functions may return either s or a copy of s; + in some implementations, proper substrings may share memory with s. +- +-

      ++

      ++
      + (string-trim-both "  The outlook wasn't brilliant,  \n\r")
      +     => "The outlook wasn't brilliant,"
      + 
      ++
      +
      + + + +-

      Modification

      ++

      Modification

      + +
      + + +-
      ++
      + +-string-set! s i char -> unspecified +-
      ++string-set! s i char -> unspecified ++ ++
      ++

      + [R5RS] + I must be a valid index of s. string-set! stores char in + element i of s. Constant string literals appearing in code are + immutable; it is an error to use them in a string-set!. +- +-

      ++

      ++
      + (define (f) (make-string 3 #\*))
      + (define (g) "***")
      + (string-set! (f) 0 #\?)                ==>  unspecified
      + (string-set! (g) 0 #\?)                ==>  error
      +-(string-set! (symbol->string 'immutable)
      ++(string-set! (symbol->string 'immutable)
      +              3
      +              #\?)                      ==>  error
      + 
      +- ++
      + +-
      ++
      + +-string-fill! s char [start end] -> unspecified +-
      ++string-fill! s char [start end] -> unspecified ++ ++
      ++

      + [R5RS+] + Stores char in every element of s. +- +-

      ++

      ++

      + string-fill is extended from the R5RS definition to take optional + start/end arguments. +- ++

      ++
      +
      + + +-

      Comparison

      ++

      Comparison

      + +
      + + +-
      ++
      + + +-string-compare    s1 s2 proc< proc= proc> [start1 end1 start2 end2] -> values +-
      string-compare-ci s1 s2 proc< proc= proc> [start1 end1 start2 end2] -> values +-
      ++string-compare    s1 s2 proc< proc= proc> [start1 end1 start2 end2] -> values ++ ++
      string-compare-ci s1 s2 proc< proc= proc> [start1 end1 start2 end2] -> values ++
      ++
      ++

      + Apply proc<, proc=, or proc> + to the mismatch index, depending + upon whether s1 is less than, equal to, or greater than s2. +@@ -1342,156 +1482,182 @@ The "mismatch index" is the largest index i such that for + every 0 <= j < i, + s1[j] = s2[j] + -- that is, i is the first position that doesn't match. +- ++

      +

      + string-compare-ci is the case-insensitive variant. Case-insensitive + comparison is done by case-folding characters with the operation +-

      ++

      ++
      + (char-downcase (char-upcase c))
      + 
      ++

      + where the two case-mapping operations are assumed to be 1-1, locale- and + context-insensitive, and compatible with the 1-1 case mappings specified + by Unicode's UnicodeData.txt table: +-

      ++

      ++ +- +

      + The optional start/end indices restrict the comparison to the indicated + substrings of s1 and s2. The mismatch index is always an index into s1; + in the case of proc=, it is always end1; + we observe the protocol + in this redundant case for uniformity. +- +-

      ++

      ++
      + (string-compare "The cat in the hat" "abcdefgh" 
      +                 values values values
      +                 4 6         ; Select "ca" 
      +                 2 4)        ; & "cd"
      +     => 5    ; Index of S1's "a"
      + 
      +- ++

      + Comparison is simply done on individual code-points of the string. + True text collation is not handled by this SRFI. +- ++

      ++
      + +-
      ++
      + +- +- +- +- +- +-string=  s1 s2 [start1 end1 start2 end2] -> boolean +-
      string<> s1 s2 [start1 end1 start2 end2] -> boolean +-
      string<  s1 s2 [start1 end1 start2 end2] -> boolean +-
      string>  s1 s2 [start1 end1 start2 end2] -> boolean +-
      string<= s1 s2 [start1 end1 start2 end2] -> boolean +-
      string>= s1 s2 [start1 end1 start2 end2] -> boolean +-
      ++ ++ ++ ++ ++ ++string=  s1 s2 [start1 end1 start2 end2] -> boolean ++ ++
      string<> s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string<  s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string>  s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string<= s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string>= s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      ++

      + These procedures are the lexicographic extensions to strings of the + corresponding orderings on characters. For example, string< is the + lexicographic ordering on strings induced by the ordering char<? on + characters. If two strings differ in length but are the same up to + the length of the shorter string, the shorter string is considered to + be lexicographically less than the longer string. +- +-

      ++

      ++

      + The optional start/end indices restrict the comparison to the indicated + substrings of s1 and s2. +- +-

      ++

      ++

      + Comparison is simply done on individual code-points of the string. + True text collation is not handled by this SRFI. +- ++

      ++
      + +-
      ++
      + +- +- +- +- +- +-string-ci=  s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-ci<> s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-ci<  s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-ci>  s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-ci<= s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-ci>= s1 s2 [start1 end1 start2 end2] -> boolean +-
      ++ ++ ++ ++ ++ ++string-ci=  s1 s2 [start1 end1 start2 end2] -> boolean ++ ++
      string-ci<> s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string-ci<  s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string-ci>  s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string-ci<= s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string-ci>= s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      ++

      + Case-insensitive variants. +- +-

      ++

      ++

      + Case-insensitive comparison is done by case-folding characters with + the operation +-

      ++

      ++
      + (char-downcase (char-upcase c))
      + 
      ++

      + where the two case-mapping operations are assumed to be 1-1, locale- and + context-insensitive, and compatible with the 1-1 case mappings specified + by Unicode's UnicodeData.txt table: +-

      + +-
      ++
      + + +-string-hash    s [bound start end] -> integer +-
      string-hash-ci s [bound start end] -> integer +-
      ++string-hash    s [bound start end] -> integer ++ ++
      string-hash-ci s [bound start end] -> integer ++
      ++
      ++

      + Compute a hash value for the string s. + Bound is a non-negative + exact integer specifying the range of the hash function. A positive + value restricts the return value to the range [0,bound). +- ++

      +

      + If bound is either zero or not given, the implementation may use + an implementation-specific default value, chosen to be as large as + is efficiently practical. For instance, the default range might be chosen + for a given implementation to map all strings into the range of + integers that can be represented with a single machine word. +- ++

      +

      + The optional start/end indices restrict the hash operation to the + indicated substring of s. +- ++

      +

      + string-hash-ci is the case-insensitive variant. Case-insensitive + comparison is done by case-folding characters with the operation +-

      ++

      ++
      + (char-downcase (char-upcase c))
      + 
      ++

      + where the two case-mapping operations are assumed to be 1-1, locale- and + context-insensitive, and compatible with the 1-1 case mappings specified + by Unicode's UnicodeData.txt table: +-

      ++

      ++ +- +

      + Invariants: +-

      +-(<= 0 (string-hash s b) (- b 1)) ; When B > 0.
      ++

      ++
      ++(<= 0 (string-hash s b) (- b 1)) ; When B > 0.
      + (string=    s1 s2)  =>  (= (string-hash s1 b)    (string-hash s2 b))
      + (string-ci= s1 s2)  =>  (= (string-hash-ci s1 b) (string-hash-ci s2 b))
      + 
      +- +

      + A legal but nonetheless discouraged implementation: +-

      ++

      ++
      + (define (string-hash    s . other-args) 1)
      + (define (string-hash-ci s . other-args) 1)
      + 
      +- +

      + Rationale: allowing the user to specify an explicit bound simplifies user + code by removing the mod operation that typically accompanies every hash +@@ -1502,231 +1668,274 @@ A legal but nonetheless discouraged implementation: + intermediate values never overflow into bignum integers, allowing the + implementor to provide a fixnum-specific "fast path" for computing the + common cases very rapidly. +- +- ++

      ++
      +
      + + +-

      Prefixes & suffixes

      ++

      Prefixes & suffixes

      + +
      + +-
      ++
      + + + + +-string-prefix-length    s1 s2 [start1 end1 start2 end2] -> integer +-
      string-suffix-length    s1 s2 [start1 end1 start2 end2] -> integer +-
      string-prefix-length-ci s1 s2 [start1 end1 start2 end2] -> integer +-
      string-suffix-length-ci s1 s2 [start1 end1 start2 end2] -> integer +-
      ++string-prefix-length    s1 s2 [start1 end1 start2 end2] -> integer ++ ++
      string-suffix-length    s1 s2 [start1 end1 start2 end2] -> integer ++
      ++
      string-prefix-length-ci s1 s2 [start1 end1 start2 end2] -> integer ++
      ++
      string-suffix-length-ci s1 s2 [start1 end1 start2 end2] -> integer ++
      ++
      ++

      + Return the length of the longest common prefix/suffix of the two strings. + For prefixes, this is equivalent to the "mismatch index" for the strings + (modulo the starti index offsets). +- ++

      +

      + The optional start/end indices restrict the comparison to the indicated + substrings of s1 and s2. +- ++

      +

      + string-prefix-length-ci and string-suffix-length-ci are the + case-insensitive variants. Case-insensitive comparison is done by + case-folding characters with the operation +-

      ++

      ++
      + (char-downcase (char-upcase c))
      + 
      ++

      + where the two case-mapping operations are assumed to be 1-1, locale- and + context-insensitive, and compatible with the 1-1 case mappings specified + by Unicode's UnicodeData.txt table: +-

      ++

      ++ ++

      + Comparison is simply done on individual code-points of the string. +- ++

      ++
      + +-
      ++
      + + + + +-string-prefix?    s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-suffix?    s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-prefix-ci? s1 s2 [start1 end1 start2 end2] -> boolean +-
      string-suffix-ci? s1 s2 [start1 end1 start2 end2] -> boolean +-
      ++string-prefix?    s1 s2 [start1 end1 start2 end2] -> boolean ++ ++
      string-suffix?    s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string-prefix-ci? s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      string-suffix-ci? s1 s2 [start1 end1 start2 end2] -> boolean ++
      ++
      ++

      + Is s1 a prefix/suffix of s2? +- ++

      +

      + The optional start/end indices restrict the comparison to the indicated + substrings of s1 and s2. +- ++

      +

      + string-prefix-ci? and string-suffix-ci? are the case-insensitive variants. + Case-insensitive comparison is done by case-folding characters with the + operation +-

      ++

      ++
      + (char-downcase (char-upcase c))
      + 
      ++

      + where the two case-mapping operations are assumed to be 1-1, locale- and + context-insensitive, and compatible with the 1-1 case mappings specified + by Unicode's UnicodeData.txt table: +-

      ++

      ++ +- +

      + Comparison is simply done on individual code-points of the string. +- ++

      ++
      +
      + + +-

      Searching

      ++

      Searching

      + +
      + + +-
      ++
      + + + + +-string-index s char/char-set/pred [start end] -> integer or #f +-
      string-index-right s char/char-set/pred [start end] -> integer or #f +-
      string-skip s char/char-set/pred [start end] -> integer or #f +-
      string-skip-right s char/char-set/pred [start end] -> integer or #f +-
      ++string-index s char/char-set/pred [start end] -> integer or #f ++ ++
      string-index-right s char/char-set/pred [start end] -> integer or #f ++
      ++
      string-skip s char/char-set/pred [start end] -> integer or #f ++
      ++
      string-skip-right s char/char-set/pred [start end] -> integer or #f ++
      ++
      ++

      + string-index (string-index-right) searches through the string from the + left (right), returning the index of the first occurrence of a character + which ++

      +
        +
      • equals char/char-set/pred (if it is a character); ++
      • +
      • is in char/char-set/pred (if it is a character set); ++
      • +
      • satisfies the predicate char/char-set/pred (if it is a procedure). ++
      • +
      ++

      + If no match is found, the functions return false. +- ++

      +

      + The start and end parameters specify the beginning and end indices of + the search; the search includes the start index, but not the end index. + Be careful of "fencepost" considerations: when searching right-to-left, + the first index considered is +-

      ++

      ++
      + end-1 +
      ++

      + whereas when searching left-to-right, the first index considered is +-

      ++

      ++
      + start +
      ++

      + That is, the start/end indices describe a same half-open interval + [start,end) in these procedures that they do + in all the other SRFI 13 procedures. +- ++

      +

      + The skip functions are similar, but use the complement of the criteria: + they search for the first char that doesn't satisfy the test. E.g., + to skip over initial whitespace, say +-

      ++

      ++
      + (cond ((string-skip s char-set:whitespace) =>
      +        (lambda (i) ...)) ; s[i] is not whitespace.
      +       ...)
      + 
      +- ++
      + +-
      ++
      + +-string-count s char/char-set/pred [start end] -> integer +-
      ++string-count s char/char-set/pred [start end] -> integer ++ ++
      ++

      + Return a count of the number of characters in s that satisfy the + char/char-set/pred argument. If this argument is a procedure, + it is applied to the character as a predicate; if it is a character set, + the character is tested for membership; if it is a character, it is + used in an equality test. +- ++

      ++
      + +-
      ++
      + + +-string-contains    s1 s2 [start1 end1 start2 end2] -> integer or false +-
      string-contains-ci s1 s2 [start1 end1 start2 end2] -> integer or false +-
      ++string-contains    s1 s2 [start1 end1 start2 end2] -> integer or false ++ ++
      string-contains-ci s1 s2 [start1 end1 start2 end2] -> integer or false ++
      ++
      ++

      + Does string s1 contain string s2? +- ++

      +

      + Return the index in s1 where s2 occurs as a substring, or false. + The optional start/end indices restrict the operation to the + indicated substrings. +- ++

      +

      + The returned index is in the range [start1,end1). + A successful match must lie entirely in the + [start1,end1) range of s1. +- +-

      +-

      ++

      ++
      + (string-contains "eek -- what a geek." "ee"
      +                  12 18) ; Searches "a geek"
      +     => 15
      + 
      +- +

      + string-contains-ci is the case-insensitive variant. Case-insensitive + comparison is done by case-folding characters with the operation +-

      ++

      ++
      + (char-downcase (char-upcase c))
      + 
      ++

      + where the two case-mapping operations are assumed to be 1-1, locale- and + context-insensitive, and compatible with the 1-1 case mappings specified + by Unicode's UnicodeData.txt table: +-

      ++

      ++ +- +

      + Comparison is simply done on individual code-points of the string. +- ++

      +

      + The names of these procedures do not end with a question mark -- this is to + indicate that they do not return a simple boolean (#t or #f). Rather, + they return either false (#f) or an exact non-negative integer. +- ++

      ++
      +
      + ++ + +-

      Alphabetic case mapping

      ++

      Alphabetic case mapping

      + +
      + + +-
      ++
      + + +-string-titlecase  s [start end] -> string +-
      string-titlecase! s [start end] -> unspecified +-
      ++string-titlecase  s [start end] -> string ++ ++
      string-titlecase! s [start end] -> unspecified ++
      ++
      ++

      + For every character c in the selected range of s, + if c is preceded by a cased character, it is downcased; + otherwise it is titlecased. +- ++

      +

      + string-titlecase returns the result string and does not alter its s + parameter. string-titlecase! is the in-place side-effecting variant. +- +-

      +-

      ++

      ++
      + (string-titlecase "--capitalize tHIS sentence.") =>
      +   "--Capitalize This Sentence."
      + 
      +@@ -1736,70 +1945,80 @@ parameter. string-titlecase! is the in-place side-effecting variant
      + (string-titlecase "3com makes routers.") =>
      +   "3Com Makes Routers."
      + 
      +- +

      + Note that if a start index is specified, then the character + preceding s[start] has no effect on the titlecase decision for + character s[start]: +-

      ++

      ++
      + (string-titlecase "greasy fried chicken" 2) => "Easy Fried Chicken"
      + 
      +- +

      + Titlecase and cased information must be compatible with the Unicode + specification. +- ++

      ++
      + +-
      ++
      + + + + +-string-upcase  s [start end] -> string +-
      string-upcase! s [start end] -> unspecified +-
      string-downcase  s [start end] -> string +-
      string-downcase! s [start end] -> unspecified +-
      ++string-upcase  s [start end] -> string ++ ++
      string-upcase! s [start end] -> unspecified ++
      ++
      string-downcase  s [start end] -> string ++
      ++
      string-downcase! s [start end] -> unspecified ++
      ++
      ++

      + Raise or lower the case of the alphabetic characters in the string. +- +-

      ++

      ++

      + string-upcase and string-downcase return the result string and do not + alter their s parameter. string-upcase! and string-downcase! are the +- in-place side-effecting variants. +- +-

      ++ in-place side-effecting variants. ++

      ++

      + These procedures use the locale- and context-insensitive 1-1 case mappings + defined by Unicode's UnicodeData.txt table: +-

      +
      + ++ + +-

      Reverse & append

      ++

      Reverse & append

      + +
      + + +-
      ++
      + + +-string-reverse  s [start end] -> string +-
      string-reverse! s [start end] -> unspecified +-
      ++string-reverse  s [start end] -> string ++ ++
      string-reverse! s [start end] -> unspecified ++
      ++
      ++

      + Reverse the string. +- ++

      +

      + string-reverse returns the result string + and does not alter its s parameter. + string-reverse! is the in-place side-effecting variant. +- +-

      ++

      ++
      + (string-reverse "Able was I ere I saw elba.") 
      +     => ".able was I ere I saw elbA"
      + 
      +@@ -1810,49 +2029,58 @@ and does not alter its s parameter.
      +     (string-reverse! s i)
      +     (string-reverse! s)))
      + 
      +- +

      + Unicode note: Reversing a string simply reverses the sequence of + code-points it contains. So a zero-width accent character a + coming after a base character b in string s + would come out before b in the reversed result. +- ++

      ++
      + +-
      ++
      + +-string-append s1 ... -> string +-
      ++string-append s1 ... -> string ++ ++
      ++

      + [R5RS] + Returns a newly allocated string whose characters form the + concatenation of the given strings. +- ++

      ++
      + +-
      ++
      + +-string-concatenate string-list -> string +-
      ++string-concatenate string-list -> string ++ ++
      ++

      + Append the elements of string-list together into a single string. + Guaranteed to return a freshly allocated string. +- +-

      ++

      ++

      + Note that the (apply string-append string-list) + idiom is + not robust for long lists of strings, as some Scheme implementations + limit the number of arguments that may be passed to an n-ary procedure. +- ++

      ++
      + +-
      ++
      + + +-string-concatenate/shared string-list -> string +-
      string-append/shared s1 ... -> string +-
      ++string-concatenate/shared string-list -> string ++ ++
      string-append/shared s1 ... -> string ++
      ++
      ++

      + These two procedures are variants of string-concatenate + and string-append + that are permitted to return results that share storage with their +@@ -1860,122 +2088,146 @@ would come out before b in the reversed result. + In particular, if string-append/shared is applied to just + one argument, it may return exactly that argument, + whereas string-append is required to allocate a fresh string. +- ++

      ++
      + +-
      ++
      + + +-string-concatenate-reverse string-list [final-string end] -> string +-
      string-concatenate-reverse/shared string-list [final-string end] -> string +-
      ++string-concatenate-reverse string-list [final-string end] -> string ++ ++
      string-concatenate-reverse/shared string-list [final-string end] -> string ++
      ++
      ++

      + With no optional arguments, these functions are equivalent to +-

      ++

      ++
      + (string-concatenate (reverse string-list))
      + 
      ++

      + and +-

      ++

      ++
      + (string-concatenate/shared (reverse string-list))
      + 
      ++

      + respectively. +- ++

      +

      + If the optional argument final-string is specified, it is consed + onto the beginning of string-list + before performing the list-reverse and string-concatenate operations. +- +

      ++

      + If the optional argument end is given, + only the first end characters + of final-string are added to the string list, thus producing +-

      ++

      ++
      + (string-concatenate 
      +   (reverse (cons (substring/shared final-string 0 end)
      +                  string-list)))
      + 
      ++

      + E.g. +-

      ++

      ++
      + (string-concatenate-reverse '(" must be" "Hello, I") " going.XXXX" 7)
      +   => "Hello, I must be going."
      + 
      +- +

      + This procedure is useful in the construction of procedures that + accumulate character data into lists of string buffers, and wish to + convert the accumulated data into a single string when done. +- ++

      +

      + Unicode note: Reversing a string simply reverses the sequence of + code-points it contains. + So a zero-width accent character ac coming after + a base character bc in string s would come out + before bc in the reversed result. +- ++

      ++
      +
      + ++ + +-

      Fold, unfold & map

      ++

      Fold, unfold & map

      + +
      + + +-
      ++
      + + +-string-map  proc s [start end] -> string +-
      string-map! proc s [start end] -> unspecified +-
      +- Proc is a char->char procedure; it is mapped over s. +- +-

      ++string-map  proc s [start end] -> string ++ ++

      string-map! proc s [start end] -> unspecified ++
      ++
      ++

      ++ Proc is a char->char procedure; it is mapped over s. ++

      ++

      + string-map returns the result string and does not alter its s parameter. + string-map! is the in-place side-effecting variant. +- +-

      ++

      ++

      + Note: The order in which proc is applied to the elements of + s is not specified. +- ++

      ++
      + +-
      ++
      + + +-string-fold kons knil s [start end] -> value +-
      string-fold-right kons knil s [start end] -> value +-
      ++string-fold kons knil s [start end] -> value ++ ++
      string-fold-right kons knil s [start end] -> value ++
      ++
      ++

      + These are the fundamental iterators for strings. +- ++

      +

      + The left-fold operator maps the kons procedure across the + string from left to right +-

      ++

      ++
      + (... (kons s[2] (kons s[1] (kons s[0] knil))))
      + 
      ++

      + In other words, string-fold obeys the (tail) recursion +-

      ++

      ++
      + (string-fold kons knil s start end) =
      +     (string-fold kons (kons s[start] knil) start+1 end)
      + 
      +- +

      + The right-fold operator maps the kons procedure across the + string from right to left +-

      ++

      ++
      + (kons s[0] (... (kons s[end-3] (kons s[end-2] (kons s[end-1] knil)))))
      + 
      ++

      + obeying the (tail) recursion +-

      ++

      ++
      + (string-fold-right kons knil s start end) =
      +     (string-fold-right kons (kons s[end-1] knil) start end-1)
      + 
      +- +

      + Examples: +-

      ++

      ++
      + ;;; Convert a string to a list of chars.
      + (string-fold-right cons '() s)
      + 
      +@@ -2001,39 +2253,46 @@ Examples:
      +                0 s)
      +   ans)
      + 
      +- +

      + The right-fold combinator is sometimes called a "catamorphism." +- ++

      ++
      + +-
      ++
      + +-string-unfold p f g seed [base make-final] -> string +-
      ++string-unfold p f g seed [base make-final] -> string ++ ++
      ++

      + This is a fundamental constructor for strings. ++

      +
        +
      • G is used to generate a series of "seed" values from the initial seed: +-
        ++
        + seed, (g seed), (g2 seed), (g3 seed), ... +
        ++
      • +
      • P tells us when to stop -- when it returns true when applied to one + of these seed values. ++
      • +
      • F maps each seed value to the corresponding character + in the result string. These chars are assembled into the + string in a left-to-right order. ++
      • +
      • Base is the optional initial/leftmost portion of the constructed string; + it defaults to the empty string "". ++
      • +
      • Make-final is applied to the terminal seed value (on which p returns + true) to produce the final/rightmost portion of the constructed string. + It defaults to (lambda (x) ""). ++
      • +
      +- +

      + More precisely, the following (simple, inefficient) definitions hold: +- +-

      ++

      ++
      + ;;; Iterative
      + (define (string-unfold p f g seed base make-final)
      +   (let lp ((seed seed) (ans base))
      +@@ -2053,18 +2312,20 @@ More precisely, the following (simple, inefficient) definitions hold:
      + string-unfold is a fairly powerful string constructor -- you can use it to
      + convert a list to a string, read a port into a string, reverse a string,
      + copy a string, and so forth. Examples:
      +-
      +-(port->string p) = (string-unfold eof-object? values
      ++

      ++
      ++(port->string p) = (string-unfold eof-object? values
      +                                   (lambda (x) (read-char p))
      +                                   (read-char p))
      + 
      +-(list->string lis) = (string-unfold null? car cdr lis)
      ++(list->string lis) = (string-unfold null? car cdr lis)
      + 
      + (string-tabulate f size) = (string-unfold (lambda (i) (= i size)) f add1 0)
      + 
      +

      + To map f over a list lis, producing a string: +-

      ++

      ++
      + (string-unfold null? (compose f car) cdr lis)
      + 
      +

      +@@ -2072,56 +2333,70 @@ Interested functional programmers may enjoy noting that + string-fold-right + and string-unfold are in some sense inverses. That is, given operations + knull?, kar, kdr, kons, and knil satisfying +-

      ++

      ++
      + (kons (kar x) (kdr x)) = x  and (knull? knil) = #t
      + 
      ++

      + then +-

      ++

      ++
      + (string-fold-right kons knil (string-unfold knull? kar kdr x)) = x
      + 
      ++

      + and +-

      ++

      ++
      + (string-unfold knull? kar kdr (string-fold-right kons knil s)) = s.
      + 
      +- ++

      + The final string constructed does not share storage with either base + or the value produced by make-final. +- ++

      +

      + This combinator sometimes is called an "anamorphism." +- ++

      +

      + Note: implementations should take care that runtime stack limits do not + cause overflow when constructing large (e.g., megabyte) strings with + string-unfold. +- ++

      ++
      + + +-
      ++
      + +-string-unfold-right p f g seed [base make-final] -> string +-
      +- This is a fundamental constructor for strings. ++string-unfold-right p f g seed [base make-final] -> string ++ ++
      ++

      ++ This is a fundamental constructor for strings. ++

      +
        +
      • G is used to generate a series of "seed" values from the initial seed: + seed, (g seed), (g2 seed), (g3 seed), ... ++
      • +
      • P tells us when to stop -- when it returns true when applied to one + of these seed values. ++
      • +
      • F maps each seed value to the corresponding character + in the result string. These chars are assembled into the + string in a right-to-left order. ++
      • +
      • Base is the optional initial/rightmost portion of the constructed string; + it defaults to the empty string "". ++
      • +
      • Make-final is applied to the terminal seed value (on which P returns + true) to produce the final/leftmost portion of the constructed string. + It defaults to (lambda (x) ""). ++
      • +
      +- +-

      ++

      + More precisely, the following (simple, inefficient) definitions hold: +-

      ++

      ++
      + ;;; Iterative
      + (define (string-unfold-right p f g seed base make-final)
      +   (let lp ((seed seed) (ans base))
      +@@ -2137,56 +2412,70 @@ cause overflow when constructing large (e.g., megabyte) strings with
      +                                       (string (f seed)))))
      +                  base))
      + 
      ++

      + Interested functional programmers may enjoy noting that + string-fold + and string-unfold-right are in some sense inverses. + That is, given operations knull?, kar, kdr, kons, and knil satisfying +-

      ++

      ++
      + (kons (kar x) (kdr x)) = x and (knull? knil) = #t +
      ++

      + then +-

      ++

      ++
      + (string-fold kons knil (string-unfold-right knull? kar kdr x)) = x
      + 
      ++

      + and +-

      ++

      ++
      + (string-unfold-right knull? kar kdr (string-fold kons knil s)) = s.
      + 
      +- ++

      + The final string constructed does not share storage with either base + or the value produced by make-final. +- +-

      ++

      ++

      + Note: implementations should take care that runtime stack limits do not + cause overflow when constructing large (e.g., megabyte) strings with + string-unfold-right. +- ++

      ++
      + + +-
      ++
      + +-string-for-each proc s [start end] -> unspecified +-
      ++string-for-each proc s [start end] -> unspecified ++ ++
      ++

      + Apply proc to each character in s. + string-for-each is required to iterate from start to end + in increasing order. +- ++

      ++
      + +-
      ++
      + +-string-for-each-index proc s [start end] -> unspecified +-
      ++string-for-each-index proc s [start end] -> unspecified ++ ++
      ++

      + Apply proc to each index of s, in order. The optional start/end + pairs restrict the endpoints of the loop. This is simply a + method of looping over a string that is guaranteed to be safe + and correct. +- ++

      ++

      + Example: +-

      ++

      ++
      + (let* ((len (string-length s))
      +        (ans (make-string len)))
      +   (string-for-each-index
      +@@ -2194,109 +2483,127 @@ Example:
      +       s)
      +   ans)
      + 
      +- ++
      +
      + ++ + +-

      Replicate & rotate

      ++

      Replicate & rotate

      + +
      + + +-
      ++
      + +-xsubstring s from [to start end] -> string +-
      ++xsubstring s from [to start end] -> string ++ ++
      ++

      + This is the "extended substring" procedure that implements replicated + copying of a substring of some string. +- +-

      ++

      ++

      + S is a string; start and end are optional arguments that demarcate + a substring of s, defaulting to 0 and the length of s (i.e., the whole + string). Replicate this substring up and down index space, in both the + positive and negative directions. For example, if s = "abcdefg", start=3, + and end=6, then we have the conceptual bidirectionally-infinite string +-

      ++

      ++
      +
      Fresh copy guaranteedSharing permitted
      string-copysubstring/shared
      string-copystring-take string-take-right
      string-copystring-drop string-drop-right
      string-drop string-drop-right
      string-concatenatestring-concatenate/shared
      string-concatenate/shared
      string-appendstring-append/shared
      string-concatenate-reverse +- string-concatenate-reverse/shared
      string-concatenate-reverse/shared
      string-pad string-pad-right
      +- +- +- +- ++ ++ ++ ++ +
      ... d e f d e f d e f d e f d e f d e f d ... +-
      ... -9 -8 -7 -6 -5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5 +6 +7 +8 +9 ... +-
      ... d e f d e f d e f d e f d e f d e f d ... ++
      ... -9 -8 -7 -6 -5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5 +6 +7 +8 +9 ... ++
      +
      +- ++

      + xsubstring returns the substring of this string beginning at index from, + and ending at to + (which defaults to from+(end-start)). +- +-

      ++

      ++

      + You can use xsubstring to perform a variety of tasks: ++

      +
        +
      • To rotate a string left: (xsubstring "abcdef" 2) => "cdefab" ++
      • +
      • To rotate a string right: (xsubstring "abcdef" -2) => "efabcd" ++
      • +
      • To replicate a string: (xsubstring "abc" 0 7) => "abcabca" ++
      • +
      +- +-

      +- Note that ++

      ++ Note that ++

      +
        +
      • The from/to indices give a half-open range -- the characters from + index from up to, but not including, index to. ++
      • +
      • The from/to indices are not in terms of the index space for string s. + They are in terms of the replicated index space of the substring + defined by s, start, and end. ++
      • +
      +- +-

      ++

      + It is an error if start=end -- although this is allowed by special + dispensation when from=to. +- ++

      ++ + +-
      ++
      + +-string-xcopy! target tstart s sfrom [sto start end] -> unspecified +-
      ++string-xcopy! target tstart s sfrom [sto start end] -> unspecified ++ ++
      ++

      + Exactly the same as xsubstring, but the extracted text is written + into the string target starting at index tstart. + This operation is not defined if (eq? target s) + or these two arguments + share storage -- you cannot copy a string on top of itself. +- ++

      ++
      + + ++ + +-

      Miscellaneous: insertion, parsing

      ++

      Miscellaneous: insertion, parsing

      + +
      + + +-
      ++
      + +-string-replace s1 s2 start1 end1 [start2 end2] -> string +-
      ++string-replace s1 s2 start1 end1 [start2 end2] -> string ++ ++
      ++

      + Returns +-

      ++

      ++
      + (string-append (substring/shared s1 0 start1)
      +                (substring/shared s2 start2 end2)
      +                (substring/shared s1 end1 (string-length s1)))
      + 
      +- ++

      + That is, the segment of characters in s1 from start1 to end1 + is replaced by the segment of characters in s2 from start2 to end2. + If start1=end1, this simply splices the s2 characters into s1 at the + specified index. +- +-

      ++

      ++

      + Examples: +-

      ++

      ++
      + (string-replace "The TCL programmer endured daily ridicule."
      +                 "another miserable perl drone" 4 7 8 22 ) =>
      +     "The miserable perl programmer endured daily ridicule."
      +@@ -2309,74 +2616,82 @@ Example:
      + (string-insert "It's easy to code it up in Scheme." 5 "really ") =>
      +     "It's really easy to code it up in Scheme."
      + 
      +- ++
      + +-
      ++
      + +-string-tokenize s [token-set start end] -> list +-
      ++string-tokenize s [token-set start end] -> list ++ ++
      ++

      + Split the string s into a list of substrings, where each substring is + a maximal non-empty contiguous sequence of characters from the character set + token-set. ++

      +
        +
      • token-set defaults to char-set:graphic + (see SRFI 14 + for more on character sets and char-set:graphic). +-
      • If start or end indices are provided, they restrict ++
      • ++
      • If start or end indices are provided, they restrict + string-tokenize to operating on the indicated substring of s. ++
      • +
      +- +-

      ++

      + This function provides a minimal parsing facility for simple applications. + More sophisticated parsers that handle quoting and backslash effects can + easily be constructed using regular-expression systems; be careful not + to use string-tokenize in contexts where more serious parsing is needed. +- +-

      ++

      ++
      + (string-tokenize "Help make programs run, run, RUN!") =>
      +   ("Help" "make" "programs" "run," "run," "RUN!")
      + 
      +- ++
      +
      + + +-

      Filtering & deleting

      ++

      Filtering & deleting

      + +
      + + +-
      ++
      + + +-string-filter char/char-set/pred s [start end] -> string +-
      string-delete char/char-set/pred s [start end] -> string +-
      ++string-filter char/char-set/pred s [start end] -> string ++ ++
      string-delete char/char-set/pred s [start end] -> string ++
      ++
      ++

      + Filter the string s, retaining only those characters that + satisfy / do not satisfy the char/char-set/pred argument. If + this argument is a procedure, it is applied to the character + as a predicate; if it is a char-set, the character is tested + for membership; if it is a character, it is used in an equality test. +- +-

      ++

      ++

      + If the string is unaltered by the filtering operation, these + functions may return either s or a copy of s. +- +- ++

      ++
      +
      + ++ + +-

      Low-level procedures

      ++

      Low-level procedures

      +

      + The following procedures are useful for writing other string-processing + functions. In a Scheme system that has a module or package system, these + procedures should be contained in a module named "string-lib-internals". +- ++

      + +-

      Start/end optional-argument parsing & checking utilities

      ++

      Start/end optional-argument parsing & checking utilities

      + + +
      +@@ -2384,99 +2699,118 @@ procedures should be contained in a module named "string-lib-internals". + +-
      ++
      + + +-string-parse-start+end proc s args -> [rest start end] +-
      string-parse-final-start+end proc s args -> [start end] +-
      ++string-parse-start+end proc s args -> [rest start end] ++ ++
      string-parse-final-start+end proc s args -> [start end] ++
      ++
      ++

      + string-parse-start+end may be used to parse a pair of optional start/end + arguments from an argument list, defaulting them to 0 and the length of + some string s, respectively. Let the length of string s be slen. +-

        ++

        ++
          +
        • If args = (), the function returns + (values '() 0 slen) ++
        • +
        • If args = (i), i is checked to ensure it is an exact integer, and + that 0 <= i <= slen. + Returns (values (cdr args) i slen). ++
        • +
        • If args = (i j ...), + i and j are checked to ensure they are exact + integers, and that 0 <= i <= j <= + slen. + Returns (values (cddr args) i j). +-
        +- +-

        ++ ++

      ++

      + If any of the checks fail, an error condition is raised, and proc is used + as part of the error condition -- it should be the client procedure whose + argument list string-parse-start+end is parsing. +- +-

      ++

      ++

      + string-parse-final-start+end is exactly the same, except that the args list + passed to it is required to be of length two or less; if it is longer, + an error condition is raised. It may be used when the optional start/end + parameters are final arguments to the procedure. +- +-

      ++

      ++

      + Note that in all cases, these functions ensure that s is a string + (by necessity, since all cases apply string-length to s either to + default end or to bounds-check it). +- +-

      ++

      ++ ++
      + +-let-string-start+end (start end [rest]) proc-exp s-exp args-exp body ... -> value(s) +-
      +- ++let-string-start+end (start end [rest]) proc-exp s-exp args-exp body ... -> value(s) ++ ++
      ++

      + [Syntax] ++

      ++

      + Syntactic sugar for an application of string-parse-start+end or + string-parse-final-start+end. +- +-

      ++

      ++

      + If a rest variable is given, the form is equivalent to +-

      ++

      ++
      + (call-with-values
      +     (lambda () (string-parse-start+end proc-exp s-exp args-exp))
      +   (lambda (rest start end) body ...))
      + 
      +- +-

      ++

      + If no rest variable is given, the form is equivalent to +-

      ++

      ++
      + (call-with-values
      +     (lambda () (string-parse-final-start+end proc-exp s-exp args-exp))
      +   (lambda (start end) body ...))
      + 
      +- ++
      + +-
      ++
      + + +-check-substring-spec proc s start end -> unspecified +-
      substring-spec-ok? s start end -> boolean +-
      ++check-substring-spec proc s start end -> unspecified ++ ++
      substring-spec-ok? s start end -> boolean ++
      ++
      ++

      + Check values s, start and end to ensure they specify a valid substring. + This means that s is a string, start and end are exact integers, and + 0 <= start <= end <= + (string-length s) +- +-

      ++

      ++

      + If the values are not proper ++

      +
        +
      • check-substring-spec raises an error condition. proc is used + as part of the error condition, and should be the procedure whose + parameters we are checking. ++
      • +
      • substring-spec-ok? returns false. ++
      • +
      ++

      + Otherwise, substring-spec-ok? returns true, and check-substring-spec + simply returns (what it returns is not specified). +- ++

      ++
      +
      + + + +-

      Knuth-Morris-Pratt searching

      ++

      Knuth-Morris-Pratt searching

      +

      + The Knuth-Morris-Pratt string-search algorithm is a method of rapidly scanning + a sequence of text for the occurrence of some fixed string. It has the +@@ -2487,7 +2821,7 @@ the initialisation and searching phases of the algorithm for general use. They + also support searching through sequences of text that arrive in buffered + chunks, in that intermediate search state can be carried across applications + of the search loop from the end of one buffer application to the next. +- ++

      +

      + A second critical property of KMP search is that it requires the allocation of + auxiliary memory proportional to the length of the pattern, but constant +@@ -2495,22 +2829,24 @@ in the size of the character type. Alternate searching algorithms frequently + require the construction of a table with an entry for every possible + character -- which can be prohibitively expensive in a 16- or 32-bit character + representation. +- ++

      +
      + +-
      ++
      + +-make-kmp-restart-vector s [c= start end] -> integer-vector +-
      ++make-kmp-restart-vector s [c= start end] -> integer-vector ++ ++
      ++

      + Build a Knuth-Morris-Pratt "restart vector," which is useful for quickly + searching character sequences for the occurrence of string s (or the + substring of s demarcated by the optional start/end parameters, if + provided). C= is a character-equality function used to construct the + restart vector. It defaults to char=?; use char-ci=? instead for + case-folded string search. +- ++

      +

      + The definition of the restart vector rv for string s is: + If we have matched chars 0..i-1 of s against some search string ss, and +@@ -2519,13 +2855,13 @@ match ss[k]. + If rv[i] = -1, + then punt ss[k] completely, and move on to + ss[k+1] and s[0]. +- ++

      +

      + In other words, if you have matched the first i chars of s, but + the i+1'th char doesn't match, + rv[i] tells you what the next-longest + prefix of s is that you have matched. +- ++

      +

      + The following string-search function shows how a restart vector is used to + search. Note the attractive feature of the search process: it is "on +@@ -2534,8 +2870,8 @@ data. It simply consumes characters one-at-a-time until declaring a complete + match or reaching the end of the sequence. Thus, it can be easily adapted to + search other character sequences (such as ports) that do not provide random + access to their contents. +- +-

      ++

      ++
      + (define (find-substring pattern source start end)
      +   (let ((plen (string-length pattern))
      +         (rv (make-kmp-restart-vector pattern)))
      +@@ -2558,7 +2894,6 @@ access to their contents.
      +                          (lp (+ si 1)  0   (- sj 1)  plen)  ; Punt.
      +                          (lp si        pi  sj        (- plen pi))))))))))
      + 
      +- +

      + The optional start/end parameters restrict the restart vector to the + indicated substring of pat; rv is end - start elements long. If start > 0, +@@ -2568,23 +2903,26 @@ pattern element pat[i + start]. + Elements of rv are themselves indices + that range just over [0, end-start), + not [start, end). +- ++

      +

      + Rationale: the actual value of rv is "position independent" -- it + does not depend on where in the pat string the pattern occurs, but + only on the actual characters comprising the pattern. +- ++

      ++
      + +-
      ++
      + +-kmp-step pat rv c i c= p-start -> integer +-
      ++kmp-step pat rv c i c= p-start -> integer ++ ++
      ++

      + This function encapsulates the work performed by one step of the + KMP string search; it can be used to scan strings, input ports, + or other on-line character sources for fixed strings. +- ++

      +

      + Pat is the non-empty string specifying the text for which we are searching. + Rv is the Knuth-Morris-Pratt restart vector for the pattern, +@@ -2593,7 +2931,7 @@ The pattern begins at pat[p-start], and is + (string-length rv) characters long. + C= is the character-equality function used to construct the + restart vector, typically char=? or char-ci=?. +- ++

      +

      + Suppose the pattern is N characters in length: + pat[p-start, p-start + n). +@@ -2604,19 +2942,20 @@ We have already matched i characters: + returns the new i value -- that is, how much of the pattern we have + matched, including character c. + When i reaches n, the entire pattern has been matched. +- ++

      +

      + Thus a typical search loop looks like this: +-

      ++

      ++
      + (let lp ((i 0))
      +   (or (= i n)                           ; Win -- #t
      +       (and (not (end-of-stream))        ; Lose -- #f
      +            (lp (kmp-step pat rv (get-next-character) i char=? 0)))))
      + 
      +- +

      + Example: +-

      ++

      ++
      + ;; Read chars from IPORT until we find string PAT or hit EOF.
      + (define (port-skip pat iport)
      +   (let* ((rv (make-kmp-restart-vector pat))
      +@@ -2628,10 +2967,10 @@ Example:
      +                 (lp (kmp-step pat rv c i char=? 0) ; Continue
      +                     (+ nchars 1))))))))
      + 
      +- +

      + This procedure could be defined as follows: +-

      ++

      ++
      + (define (kmp-step pat rv c i c= p-start)
      +   (let lp ((i i))
      +     (if (c= c (string-ref pat (+ i p-start)))     ; Match =>
      +@@ -2640,27 +2979,29 @@ This procedure could be defined as follows:
      +           (if (= i -1) 0                          ; Can't back up more.
      +               (lp i)))))))                        ; Keep going.
      + 
      +- +

      + Rationale: this procedure takes no optional arguments because it + is intended as an inner-loop primitive and we do not want any + run-time penalty for optional-argument parsing and defaulting, + nor do we wish barriers to procedure integration/inlining. +- ++

      ++
      + +-
      ++
      + +-string-kmp-partial-search pat rv s i [c= p-start s-start s-end] -> integer +-
      ++string-kmp-partial-search pat rv s i [c= p-start s-start s-end] -> integer ++ ++
      ++

      + Applies kmp-step across s; + optional s-start/s-end bounds parameters + restrict search to a substring of s. + The pattern is (vector-length rv) characters long; + optional p-start index indicates non-zero start of pattern + in pat. +- ++

      +

      + Suppose plen = (vector-length rv) + is the length of the pattern. +@@ -2668,38 +3009,41 @@ is the length of the pattern. + (that is, 0 <= i < plen) + indicating how much of the pattern has already been matched. + (This means the pattern must be non-empty -- plen > 0.) +- ++

      +
        +
      • On success, returns -j, + where j is the index in s bounding + the end of the pattern -- e.g., a value that could be used as + the end parameter in a call to substring/shared. +- +-
      • On continue, returns the current search state i' ++
      • ++
      • On continue, returns the current search state i' + (an index into rv) + when the search reached the end of the string. This is a non-negative + integer. ++
      • +
      +- ++

      + Hence: ++

      +
        +
      • A negative return value indicates success, and says + where in the string the match occured. +- ++
      • +
      • A non-negative return value provides the i to use for + continued search in a following string. ++
      • +
      +- +

      + This utility is designed to allow searching for occurrences of a fixed + string that might extend across multiple buffers of text. This is + why, for example, we do not provide the index of the start of the + match on success -- it may have occurred in a previous buffer. +- ++

      +

      + To search a character sequence that arrives in "chunks," write a + loop of this form: +-

      ++

      ++
      + (let lp ((i 0))
      +   (and (not (end-of-data?))             ; Lose -- return #f.
      +        (let* ((buf (get-next-chunk))    ; Get or fill up the buffer.
      +@@ -2707,9 +3051,11 @@ loop of this form:
      +          (if (< i 0) (- i)              ; Win -- return end index.
      +              (lp i)))))                 ; Keep looking.
      + 
      ++

      + Modulo start/end optional-argument parsing, this procedure could + be defined as follows: +-

      ++

      ++
      + (define (string-kmp-partial-search pat rv s i c= p-start s-start s-end)
      +   (let ((patlen (vector-length rv)))
      +     (let lp ((si s-start)       ; An index into S.
      +@@ -2720,39 +3066,41 @@ be defined as follows:
      +                       (kmp-step pat rv (string-ref s si)
      +                                 vi c= p-start)))))))
      + 
      ++
      +
      + + +-

      Reference implementation

      ++

      Reference implementation

      + +

      + This SRFI comes with a reference implementation. It can be found at: +-

      +- http://srfi.schemers.org/srfi-13/srfi-13.scm ++

      ++ +-

      ++

      + I have placed this source on the Net with an unencumbered, "open" copyright. + The prefix/suffix and comparison routines in this code had (extremely distant) + origins in MIT Scheme's string lib, and were substantially reworked by myself. + Being derived from that code, they are covered by the MIT Scheme copyright, + which is a generic BSD-style open-source copyright. See the source file for + details. +- ++

      +

      + The KMP string-search code was influenced by implementations written by + Stephen Bevan, Brian Denheyer and Will Fitzgerald. However, this version was + written from scratch by myself. +- ++

      +

      + The remainder of the code was written by myself for scsh or for this SRFI; I + have placed this code under the scsh copyright, which is also a generic + BSD-style open-source copyright. +- ++

      +

      + The code is written for portability and should be straightforward to port to + any Scheme. The source comments contains detailed notes describing the non-R5RS + dependencies. +- ++

      +

      + The library is written for clarity and well-commented; the current source is + approximately 1000 lines of source code and 1000 lines of comments and white +@@ -2760,15 +3108,15 @@ space. It is also written for efficiency. Fast paths are provided for common + cases. This is not to say that the implementation can't be tuned up for a + specific Scheme implementation. There are notes in the comments addressing + ways implementors can tune the reference implementation for performance. +- ++

      +

      + In short, I've written the reference implementation to make it as painless + as possible for an implementor -- or a regular programmer -- to adopt this + library and get good results with it. +- ++

      + + +-

      Acknowledgements

      ++

      Acknowledgements

      + +

      + The design of this library benefited greatly from the feedback provided during +@@ -2782,137 +3130,175 @@ Kiselyov, Bengt Kleberg, Donovan Kolbly, Bruce Korb, Shriram Krishnamurthi, + Bruce Lewis, Tom Lord, Brad Lucier, Dave Mason, David Rush, Klaus Schilling, + Jonathan Sobel, Mike Sperber, Mikael Staldal, Vladimir Tsyshevsky, Donald + Welsh, and Mike Wilson. I am grateful to them for their assistance. +- ++

      +

      + I am also grateful the authors, implementors and documentors of all the systems + mentioned in the introduction. Aubrey Jaffer and Kent Pitman should be noted + for their work in producing Web-accessible versions of the R5RS and Common + Lisp spec, which was a tremendous aid. +- ++

      +

      + This is not to imply that these individuals necessarily endorse the final + results, of course. +- ++

      +

      + During this document's long development period, great patience was exhibited + by Mike Sperber, who is the editor for the SRFI, and by Hillary Sullivan, + who is not. +- ++

      + +-

      References & links

      ++ + +
      + +-
      [Case-map] ++
      [Case-map] ++
      +
      +- Case mappings.
      +- Unicode Technical Report 21.
      ++

      ++ Case mappings.
      ++ Unicode Technical Report 21.
      + http://www.unicode.org/unicode/reports/tr21/ +- +-

      [CommonLisp]
      +-
      Common Lisp: the Language.
      +-Guy L. Steele Jr. (editor).
      +-Digital Press, Maynard, Mass., second edition 1990.
      ++

      ++
      ++
      [CommonLisp] ++
      ++
      ++

      ++Common Lisp: the Language.
      ++Guy L. Steele Jr. (editor).
      ++Digital Press, Maynard, Mass., second edition 1990.
      + Available at + http://www.elwood.com/alu/table/references.htm#cltl2. ++

      +

      +- + The Common Lisp "HyperSpec," produced by Kent Pitman, is essentially + the ANSI spec for Common Lisp: +- +-http://www.harlequin.com/education/books/HyperSpec/. +- +-

      [Java] ++ ++http://www.lispworks.com/documentation/HyperSpec/Front/index.htm. ++

      ++ ++
      [Java] ++
      +
      +- The following URLs provide documentation on relevant Java classes.
      ++

      ++ The following URLs provide documentation on relevant Java classes.
      + + http://java.sun.com/products/jdk/1.2/docs/api/java/lang/Character.html +-
      ++
      + http://java.sun.com/products/jdk/1.2/docs/api/java/lang/String.html +-
      ++
      + http://java.sun.com/products/jdk/1.2/docs/api/java/lang/StringBuffer.html +-
      ++
      + http://java.sun.com/products/jdk/1.2/docs/api/java/text/Collator.html +-
      ++
      + http://java.sun.com/products/jdk/1.2/docs/api/java/text/package-summary.html +- +-

      [MIT-Scheme] ++

      ++ ++
      [MIT-Scheme] ++
      +
      ++

      + http://www.swiss.ai.mit.edu/projects/scheme/ +- +-

      [R5RS]
      +-
      Revised5 report on the algorithmic language Scheme.
      +- R. Kelsey, W. Clinger, J. Rees (editors).
      +- Higher-Order and Symbolic Computation, Vol. 11, No. 1, September, 1998.
      +- and ACM SIGPLAN Notices, Vol. 33, No. 9, October, 1998.
      ++

      ++
      ++
      [R5RS] ++
      ++
      ++

      ++ Revised5 report on the algorithmic language Scheme.
      ++ R. Kelsey, W. Clinger, J. Rees (editors).
      ++ Higher-Order and Symbolic Computation, Vol. 11, No. 1, September, 1998.
      ++ and ACM SIGPLAN Notices, Vol. 33, No. 9, October, 1998.
      + Available at + http://www.schemers.org/Documents/Standards/. +- +-

      [SRFI]
      ++

      ++ ++
      [SRFI] ++
      +
      +- The SRFI web site.
      +- http://srfi.schemers.org/ +- +-
      [SRFI-13]
      ++

      ++ The SRFI web site.
      ++ http://srfi.schemers.org/ ++

      ++ ++
      [SRFI-13] ++
      +
      +- SRFI-13: String libraries.
      +- http://srfi.schemers.org/srfi-13/ +- ++

      ++ SRFI-13: String libraries.
      ++ http://srfi.schemers.org/srfi-13/ ++

      +
      +
      + This document, in HTML: +-
      +- http://srfi.schemers.org/srfi-13/srfi-13.html ++ ++
      ++ https://srfi.schemers.org/srfi-13/srfi-13.html + ++
      +
      + This document, in plain text format: +-
      +- http://srfi.schemers.org/srfi-13/srfi-13.txt ++ ++
      ++ https://srfi.schemers.org/srfi-13/srfi-13.txt + ++
      +
      Source code for the reference implementation: ++
      +
      +- +- http://srfi.schemers.org/srfi-13/srfi-13.scm ++ ++ https://srfi.schemers.org/srfi-13/srfi-13.scm + ++
      +
      Scheme 48 module specification, with typings: ++
      +
      +- +- http://srfi.schemers.org/srfi-13/srfi-13-s48-module.scm ++ ++ https://srfi.schemers.org/srfi-13/srfi-13-s48-module.scm ++
      +
      +
      + +-
      [SRFI-14] ++
      [SRFI-14] ++
      +
      +- SRFI-14: Character-set library.
      +- http://srfi.schemers.org/srfi-14/
      ++

      ++ SRFI-14: Character-set library.
      ++ http://srfi.schemers.org/srfi-14/
      + The SRFI 14 char-set library defines a character-set data type, + which is used by some procedures in this library. +- +-

      [Unicode] ++

      ++ ++
      [Unicode] ++
      +
      + http://www.unicode.org/ +- +-
      [UnicodeData] ++ ++
      [UnicodeData] ++
      +
      +- The Unicode character database.
      ++

      ++ The Unicode character database.
      + ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt +-
      ++
      + ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.html +- ++

      ++
      +
      + ++ + +-

      Copyright

      ++ + +

      + Certain portions of this document -- the specific, marked segments of text + describing the R5RS procedures -- were adapted with permission from the R5RS + report. +- ++

      +

      + All other text is copyright (C) Olin Shivers (1998, 1999, 2000). + All Rights Reserved. +- ++

      +

      + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -2935,11 +3321,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

      +- ++
      ++
      Editor: Michael Sperber
      + +- +- +- ++ +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-14.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-14.html +index 4167ab3..f42fc23 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-14.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-14.html +@@ -1,5 +1,23 @@ +- ++ ++ ++ ++ ++ + +- + +- +- +- +- ++ + SRFI 14: Character-set Library +- ++ ++ ++ + + +- +- + +- + +- + +-

      Title

      ++

      SRFI 14: Character-set Library

      + +-
      SRFI 14: Character-set Library
      ++

      by Olin Shivers

      ++

      This copy of the SRFI 14 specification document ++is distributed as part of the Racket package ++srfi-doc.

      The canonical source of this document is ++https://srfi.schemers.org/srfi-14/srfi-14.html.

      + +- +-

      Author

      +- +-Olin Shivers +- +-

      Status

      +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

        +-
      • Received: 1999/10/17 +-
      • Draft: 1999/10/30-1999/12/30 +-
      • Revised: 2000/04/30 +-
      • Revised: 2000/04/30 +-
      • Revised: 2000/06/09 +-
      • Revised: 2000/12/23 +-
      ++

      Status

      ++ ++

      This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-14@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

      ++
        ++
      • Received: 1999-10-17
      • ++
      • Draft: 1999-10-30--1999-12-30
      • ++
      • Revised: 2000-04-30
      • ++
      • Revised: 2000-04-30
      • ++
      • Revised: 2000-06-09
      • ++
      • Revised: 2000-12-23
      • ++
      • Post-finalization notes: ++
          ++
        • ++ 2019-12-09 (In a ++ separate document, ++ added notes by John Cowan on relevant changes to Unicode ++ since publication of this SRFI. The author of SRFI 14, Olin Shivers, ++ has not yet expressed an opinion on the notes.) ++
        • ++
        ++
      • ++
      ++ + + +-

      Table of contents

      ++

      Table of contents

      + + +-
        +-
      • Abstract +-
      • Variable index +-
      • Rationale +- +- +-
      • Specification +- +- +-
      • Unicode, Latin-1 and ASCII definitions of the standard character sets +-
      • Reference implementation +-
      • Acknowledgements +-
      • References & Links +-
      • Copyright ++ + + +-

        Abstract

        ++

        Abstract

        +

        +- + The ability to efficiently represent and manipulate sets of characters is an + unglamorous but very useful capability for text-processing code -- one that + tends to pop up in the definitions of other libraries. Hence it is useful to + specify a general substrate for this functionality early. This SRFI defines a + general library that provides this functionality. +- ++

        ++

        + It is accompanied by a reference implementation for the spec. The reference + implementation is fairly efficient, straightforwardly portable, and has a + "free software" copyright. The implementation is tuned for "small" 7 or 8 +@@ -216,90 +263,97 @@ bit character types, such as ASCII or Latin-1; the data structures and + algorithms would have to be altered for larger 16 or 32 bit character types + such as Unicode -- however, the specs have been carefully designed with these + larger character types in mind. +- ++

        ++

        + Several forthcoming SRFIs can be defined in terms of this one: ++

        +
          +-
        • string library +-
        • delimited input procedures (e.g., read-line) +-
        • regular expressions ++
        • string library
        • ++
        • delimited input procedures (e.g., read-line)
        • ++
        • regular expressions
        • +
        + +- + +-

        Variable Index

        ++

        Variable Index

        +

        + Here is the complete set of bindings -- procedural and otherwise -- + exported by this library. In a Scheme system that has a module or package + system, these procedures should be contained in a module named "char-set-lib". +- +-

        ++

        ++
        +
        +-
        Predicates & comparison +-
        +-
        +-char-set? char-set= char-set<= char-set-hash
        ++
        Predicates & comparison ++
        ++
        ++
        ++char-set? char-set= char-set<= char-set-hash
        + 
        +- +-
        Iterating over character sets +-
        +-
        ++
        ++
        Iterating over character sets ++
        ++
        ++
        + char-set-cursor char-set-ref char-set-cursor-next end-of-char-set? 
        + char-set-fold char-set-unfold char-set-unfold!
        + char-set-for-each char-set-map
        + 
        +- +-
        Creating character sets +-
        +-
        ++
        ++
        Creating character sets ++
        ++
        ++
        + char-set-copy char-set
        + 
        +-list->char-set  string->char-set
        +-list->char-set! string->char-set!
        ++list->char-set  string->char-set
        ++list->char-set! string->char-set!
        +     
        +-char-set-filter  ucs-range->char-set 
        +-char-set-filter! ucs-range->char-set!
        ++char-set-filter  ucs-range->char-set 
        ++char-set-filter! ucs-range->char-set!
        + 
        +-->char-set
        ++->char-set
        + 
        +- +-
        Querying character sets +-
        +-
        +-char-set->list char-set->string
        ++
        ++
        Querying character sets ++
        ++
        ++
        ++char-set->list char-set->string
        + char-set-size char-set-count char-set-contains?
        + char-set-every char-set-any
        + 
        +- +-
        Character-set algebra +-
        +-
        ++
        ++
        Character-set algebra ++
        ++
        ++
        + char-set-adjoin  char-set-delete
        + char-set-adjoin! char-set-delete!
        + 
        + char-set-complement  char-set-union  char-set-intersection
        + char-set-complement! char-set-union! char-set-intersection!
        + 
        +-char-set-difference  char-set-xor  char-set-diff+intersection
        +-char-set-difference! char-set-xor! char-set-diff+intersection!
        ++char-set-difference  char-set-xor  char-set-diff+intersection
        ++char-set-difference! char-set-xor! char-set-diff+intersection!
        + 
        +- +-
        Standard character sets +-
        +-
        +-char-set:lower-case  char-set:upper-case  char-set:title-case
        +-char-set:letter      char-set:digit       char-set:letter+digit
        +-char-set:graphic     char-set:printing    char-set:whitespace
        +-char-set:iso-control char-set:punctuation char-set:symbol
        +-char-set:hex-digit   char-set:blank       char-set:ascii
        +-char-set:empty       char-set:full
        ++
        ++
        Standard character sets ++
        ++
        ++
        ++char-set:lower-case  char-set:upper-case  char-set:title-case
        ++char-set:letter      char-set:digit       char-set:letter+digit
        ++char-set:graphic     char-set:printing    char-set:whitespace
        ++char-set:iso-control char-set:punctuation char-set:symbol
        ++char-set:hex-digit   char-set:blank       char-set:ascii
        ++char-set:empty       char-set:full
        + 
        + ++
        +
        +
        + + +-

        Rationale

        ++

        Rationale

        + +

        + The ability to efficiently manipulate sets of characters is quite +@@ -307,16 +361,16 @@ useful for text-processing code. Encapsulating this functionality in + a general, efficiently implemented library can assist all such code. + This library defines a new data structure to represent these sets, called + a "char-set." The char-set type is distinct from all other types. +- ++

        +

        + This library is designed to be portable across implementations that use + different character types and representations, especially ASCII, Latin-1 + and Unicode. Some effort has been made to preserve compatibility with Java + in the Unicode case (see the definition of char-set:whitespace for the + single real deviation). +- ++

        + +-

        Linear-update operations

        ++

        Linear-update operations

        + +

        + The procedures of this SRFI, by default, are "pure functional" -- they do not +@@ -327,39 +381,43 @@ to construct their result. An implementation may legally implement these + procedures as pure, side-effect-free functions, or it may implement them using + side effects, depending upon the details of what is the most efficient or + simple to implement in terms of the underlying representation. +- ++

        +

        + The linear-update routines all have names ending with "!". +- ++

        +

        + Clients of these procedures may not rely upon these procedures working by + side effect. For example, this is not guaranteed to work: +-

        ++

        ++
        + (let* ((cs1 (char-set #\a #\b #\c))      ; cs1 = {a,b,c}.
        +        (cs2 (char-set-adjoin! cs1 #\d))) ; Add d to {a,b,c}.
        +   cs1) ; Could be either {a,b,c} or {a,b,c,d}.
        + 
        +-

        ++

        + However, this is well-defined: +-

        ++

        ++
        + (let ((cs (char-set #\a #\b #\c)))
        +   (char-set-adjoin! cs #\d)) ; Add d to {a,b,c}.
        + 
        +- +

        + So clients of these procedures write in a functional style, but must + additionally be sure that, when the procedure is called, there are no other + live pointers to the potentially-modified character set (hence the term + "linear update"). +- ++

        +

        + There are two benefits to this convention: ++

        +
          +
        • Implementations are free to provide the most efficient possible + implementation, either functional or side-effecting. ++
        • +
        • Programmers may nonetheless continue to assume that character sets + are purely functional data structures: they may be reliably shared + without needing to be copied, uniquified, and so forth. ++
        • +
        + +

        +@@ -369,136 +427,151 @@ be represented in an ASCII Scheme with 4 32-bit words. Pure set-algebra + operations on such a representation are very fast and efficient. Programmers + who code using linear-update operations are guaranteed the system will + provide the best implementation across multiple platforms. +- ++

        +

        + In practice, these procedures are most useful for efficiently constructing + character sets in a side-effecting manner, in some limited local context, + before passing the character set outside the local construction scope to be + used in a functional manner. +- ++

        +

        + Scheme provides no assistance in checking the linearity of the potentially + side-effected parameters passed to these functions --- there's no linear + type checker or run-time mechanism for detecting violations. (But + sophisticated programming environments, such as DrScheme, might help.) +- ++

        + +-

        Extra-SRFI recommendations

        ++

        Extra-SRFI recommendations

        +

        + Users are cautioned that the R5RS predicates +-

        +-char-alphabetic?
        +-char-numeric?
        +-char-whitespace?
        +-char-upper-case?
        +-char-lower-case?
        ++

        ++
        ++char-alphabetic?
        ++char-numeric?
        ++char-whitespace?
        ++char-upper-case?
        ++char-lower-case?
        +
        +
        +-

        ++

        + may or may not be in agreement with the SRFI 14 base character sets +-

        ++

        ++
        + +-char-set:letter
        +-char-set:digit
        +-char-set:whitespace
        +-char-set:upper-case
        +-char-set:lower-case
        ++char-set:letter
        ++char-set:digit
        ++char-set:whitespace
        ++char-set:upper-case
        ++char-set:lower-case
        +
        +
        +-

        ++

        + Implementors are strongly encouraged to bring these predicates into + agreement with the base character sets of this SRFI; not to do so risks + major confusion. +- ++

        + + +-

        Specification

        ++

        Specification

        +

        + In the following procedure specifications: ++

        +
          +
        • A cs parameter is a character set. +- ++
        • +
        • An s parameter is a string. +- ++
        • +
        • A char parameter is a character. +- ++
        • +
        • A char-list parameter is a list of characters. +- +-
        • A pred parameter is a unary character predicate procedure, returning ++
        • ++
        • A pred parameter is a unary character predicate procedure, returning + a true/false value when applied to a character. +- ++
        • +
        • An obj parameter may be any value at all. ++
        • +
        + +

        + Passing values to procedures with these parameters that do not satisfy these + types is an error. +- ++

        +

        + Unless otherwise noted in the specification of a procedure, procedures + always return character sets that are distinct (from the point of view + of the linear-update operations) from the parameter character sets. For + example, char-set-adjoin is guaranteed to provide a fresh character set, + even if it is not given any character parameters. +- ++

        +

        + Parameters given in square brackets are optional. Unless otherwise noted in the + text describing the procedure, any prefix of these optional parameters may + be supplied, from zero arguments to the full list. When a procedure returns + multiple values, this is shown by listing the return values in square + brackets, as well. So, for example, the procedure with signature +-

        +-halts? f [x init-store] -> [boolean integer]
        ++

        ++
        ++halts? f [x init-store] -> [boolean integer]
        + 
        ++

        + would take one (f), two (f, x) + or three (f, x, init-store) input parameters, + and return two values, a boolean and an integer. +- ++

        +

        + A parameter followed by "..." means zero-or-more elements. + So the procedure with the signature +-

        +-sum-squares x ...  -> number
        ++

        ++
        ++sum-squares x ...  -> number
        + 
        ++

        + takes zero or more arguments (x ...), + while the procedure with signature +-

        +-spell-check doc dict1 dict2 ... -> string-list
        ++

        ++
        ++spell-check doc dict1 dict2 ... -> string-list
        + 
        ++

        + takes two required parameters + (doc and dict1) + and zero or more optional parameters (dict2 ...). +- ++

        + + +-

        General procedures

        ++

        General procedures

        +
        + + +-
        ++
        + +-char-set? obj -> boolean +-
        +- ++char-set? obj -> boolean ++ ++
        ++

        + Is the object obj a character set? +- ++

        ++
        + +-
        ++
        + +-char-set= cs1 ... -> boolean +-
        ++char-set= cs1 ... -> boolean ++ ++
        ++

        + Are the character sets equal? ++

        +

        + Boundary cases: +-

        +-(char-set=) => true
        +-(char-set= cs) => true
        ++

        ++
        ++(char-set=) => true
        ++(char-set= cs) => true
        + 
        +- +

        + Rationale: transitive binary relations are generally extended to n-ary + relations in Scheme, which enables clearer, more concise code to be +@@ -506,15 +579,17 @@ and zero or more optional parameters (dict2 ...). + certainly not arise in first-order uses of such relations, they may well + arise in higher-order cases or macro-generated code. + E.g., consider +-

        ++

        ++
        + (apply char-set= cset-list)
        + 
        +-

        ++

        + This is well-defined if the list is empty or a singleton list. Hence + we extend these relations to any number of arguments. Implementors + have reported actual uses of n-ary relations in higher-order cases + allowing for fewer than two arguments. The way of Scheme is to handle the + general case; we provide the fully general extension. ++

        +

        + A counter-argument to this extension is that + R5RS's +@@ -523,63 +598,69 @@ and zero or more optional parameters (dict2 ...). + require at least two arguments, hence + this decision is a break with the prior convention -- although it is + at least one that is backwards-compatible. +- ++

        ++
        + +-
        +- +-char-set<= cs1 ... -> boolean +-
        ++
        ++ ++char-set<= cs1 ... -> boolean ++
        ++
        ++

        + Returns true if every character set csi is + a subset of character set csi+1. +- ++

        +

        + Boundary cases: +-

        +-(char-set<=) => true
        +-(char-set<= cs) => true
        ++

        ++
        ++(char-set<=) => true
        ++(char-set<= cs) => true
        + 
        +

        + Rationale: See char-set= for discussion of zero- and one-argument + applications. Consider testing a list of char-sets for monotonicity +-with +-

        +-(apply char-set<= cset-list)
        ++with
        ++

        ++
        ++(apply char-set<= cset-list)
        + 
        +- ++
        + +-
        ++
        + +-char-set-hash cs [bound] -> integer +-
        ++char-set-hash cs [bound] -> integer ++ ++
        ++

        + Compute a hash value for the character set cs. + Bound is a non-negative + exact integer specifying the range of the hash function. A positive + value restricts the return value to the range [0,bound). +- +-

        ++

        ++

        + If bound is either zero or not given, the implementation may use + an implementation-specific default value, chosen to be as large as + is efficiently practical. For instance, the default range might be chosen + for a given implementation to map all strings into the range of + integers that can be represented with a single machine word. +- +- +-

        ++

        ++

        + Invariant: +-

        +-(char-set= cs1 cs2) => (= (char-set-hash cs1 b) (char-set-hash cs2 b))
        ++

        ++
        ++(char-set= cs1 cs2) => (= (char-set-hash cs1 b) (char-set-hash cs2 b))
        + 
        +- +-

        ++

        + A legal but nonetheless discouraged implementation: +-

        ++

        ++
        + (define (char-set-hash cs . maybe-bound) 1)
        + 
        +- +

        + Rationale: allowing the user to specify an explicit bound simplifies user + code by removing the mod operation that typically accompanies every hash +@@ -590,29 +671,31 @@ with + intermediate values never overflow into bignum integers, allowing the + implementor to provide a fixnum-specific "fast path" for computing the + common cases very rapidly. +- ++

        ++
        +
        + + +-

        Iterating over character sets

        ++

        Iterating over character sets

        + +
        + +-
        +- +- +- +- +-char-set-cursor cset -> cursor +-
        +-char-set-ref cset cursor -> char +-
        +-char-set-cursor-next cset cursor -> cursor +-
        +-end-of-char-set? cursor -> boolean +-
        ++
        ++char-set-cursor cset -> cursor ++
        ++
        ++char-set-ref cset cursor -> char ++
        ++
        ++char-set-cursor-next cset cursor -> cursor ++
        ++
        ++end-of-char-set? cursor -> boolean ++
        ++
        ++

        + Cursors are a low-level facility for iterating over the characters in a + set. A cursor is a value that indexes a character in a char set. + char-set-cursor produces a new cursor for a given char set. +@@ -624,28 +707,29 @@ with + answers true to end-of-char-set?. + It is an error to pass such a cursor to char-set-ref or to + char-set-cursor-next. +- ++

        +

        + A cursor value may not be used in conjunction with a different character + set; if it is passed to char-set-ref or + char-set-cursor-next with + a character set other than the one used to create it, the results and + effects are undefined. +- ++

        +

        + Cursor values are not necessarily distinct from other types. + They may be + integers, linked lists, records, procedures or other values. This license + is granted to allow cursors to be very "lightweight" values suitable for + tight iteration, even in fairly simple implementations. +- ++

        +

        + Note that these primitives are necessary to export an iteration facility + for char sets to loop macros. +- ++

        +

        + Example: +-

        ++

        ++
        + (define cs (char-set #\G #\a #\T #\e #\c #\h))
        + 
        + ;; Collect elts of CS into a list.
        +@@ -653,16 +737,15 @@ with
        +   (if (end-of-char-set? cur) ans
        +       (lp (char-set-cursor-next cs cur)
        +           (cons (char-set-ref cs cur) ans))))
        +-  => (#\G #\T #\a #\c #\e #\h)
        ++  => (#\G #\T #\a #\c #\e #\h)
        + 
        + ;; Equivalently, using a list unfold (from SRFI 1):
        + (unfold-right end-of-char-set? 
        +               (curry char-set-ref cs)
        + 	      (curry char-set-cursor-next cs)
        + 	      (char-set-cursor cs))
        +-  => (#\G #\T #\a #\c #\e #\h)
        ++  => (#\G #\T #\a #\c #\e #\h)
        + 
        +- +

        + Rationale: Note that the cursor API's four functions "fit" the functional + protocol used by the unfolders provided by the list, string and char-set +@@ -674,26 +757,31 @@ with + character set, then this function returned false instead of the character + value, and another end-of-char-set cursor. In this way, the other three + functions of the current API were combined together. +- ++

        ++
        + +-
        ++
        + +-char-set-fold kons knil cs -> object +-
        ++char-set-fold kons knil cs -> object ++ ++
        ++

        + This is the fundamental iterator for character sets. Applies the function + kons across the character set cs using initial state value knil. That is, + if cs is the empty set, the procedure returns knil. Otherwise, some + element c of cs is chosen; + let cs' be the remaining, unchosen characters. + The procedure returns +-

        ++

        ++
        + (char-set-fold kons (kons c knil) cs')
        + 
        +-

        ++

        + Examples: +-

        ++

        ++
        + ;; CHAR-SET-MEMBERS
        + (lambda (cs) (char-set-fold cons '() cs))
        + 
        +@@ -705,34 +793,39 @@ with
        +   (char-set-fold (lambda (c i) (if (vowel? c) (+ i 1) i))
        +                  0 cs))
        + 
        ++
        + + +-
        +- +- +-char-set-unfold  f p g seed [base-cs] -> char-set +-
        char-set-unfold! f p g seed base-cs -> char-set +-
        ++
        ++char-set-unfold  f p g seed [base-cs] -> char-set ++
        ++
        char-set-unfold! f p g seed base-cs -> char-set ++
        ++
        ++

        + This is a fundamental constructor for char-sets. ++

        +
          +
        • G is used to generate a series of "seed" values from the initial seed: + seed, (g seed), (g2 seed), (g3 seed), ... +-
        • P tells us when to stop -- when it returns true when applied to one ++
        • ++
        • P tells us when to stop -- when it returns true when applied to one + of these seed values. ++
        • +
        • F maps each seed value to a character. These characters are added + to the base character set base-cs to form the result; base-cs defaults to + the empty set. char-set-unfold! adds the characters to base-cs in a + linear-update -- it is allowed, but not required, to side-effect + and use base-cs's storage to construct the result. ++
        • +
        +- +-

        ++

        + More precisely, the following definitions hold, ignoring the + optional-argument issues: +- +-

        ++

        ++
        + (define (char-set-unfold p f g seed base-cs) 
        +   (char-set-unfold! p f g seed (char-set-copy base-cs)))
        + 
        +@@ -742,31 +835,34 @@ with
        +             (lp (g seed)                                ; Loop on (G SEED).
        +                 (char-set-adjoin! cs (f seed))))))      ; Add (F SEED) to set.
        + 
        +- ++

        + (Note that the actual implementation may be more efficient.) +- +-

        ++

        ++

        + Examples: +-

                                 
        +-(port->char-set p) = (char-set-unfold eof-object? values
        ++

        ++
                                 
        ++(port->char-set p) = (char-set-unfold eof-object? values
        +                                       (lambda (x) (read-char p))
        +                                       (read-char p))
        + 
        +-(list->char-set lis) = (char-set-unfold null? car cdr lis)
        ++(list->char-set lis) = (char-set-unfold null? car cdr lis)
        + 
        ++
        + +-
        +- +-char-set-for-each proc cs -> unspecified +-
        ++
        ++char-set-for-each proc cs -> unspecified ++
        ++
        ++

        + Apply procedure proc to each character in the character set cs. + Note that the order in which proc is applied to the characters in the + set is not specified, and may even change from one procedure application + to another. +- +-

        ++

        ++

        + Nothing at all is specified about the value returned by this procedure; it + is not even required to be consistent from call to call. It is simply + required to be a value (or values) that may be passed to a command +@@ -776,123 +872,137 @@ with + R5RS, + this restricts the procedure to returning a single value; + non-R5RS systems may not even provide this restriction. +- ++

        ++
        + +-
        +- +-char-set-map proc cs -> char-set +-
        +- proc is a char->char procedure. Apply it to all the characters in ++
        ++char-set-map proc cs -> char-set ++
        ++
        ++

        ++ proc is a char->char procedure. Apply it to all the characters in + the char-set cs, and collect the results into a new character set. +- +-

        +- Essentially lifts proc from a char->char procedure to a char-set -> ++

        ++

        ++ Essentially lifts proc from a char->char procedure to a char-set -> + char-set procedure. +- +-

        ++

        ++

        + Example: +-

        ++

        ++
        + (char-set-map char-downcase cset)
        + 
        ++
        +
        + +- + +-

        Creating character sets

        ++

        Creating character sets

        +
        + + +-
        +- +-char-set-copy cs -> char-set +-
        ++
        ++char-set-copy cs -> char-set ++
        ++
        ++

        + Returns a copy of the character set cs. "Copy" means that if either the + input parameter or the result value of this procedure is passed to one of + the linear-update procedures described below, the other character set is + guaranteed not to be altered. +- +-

        ++

        ++

        + A system that provides pure-functional implementations of the + linear-operator suite could implement this procedure as the identity + function -- so copies are not guaranteed to be distinct by eq?. +- ++

        ++
        + +-
        +- +-char-set char1 ... -> char-set +-
        ++
        ++char-set char1 ... -> char-set ++
        ++
        ++

        + Return a character set containing the given characters. +- ++

        ++
        + +-
        +- +- +-list->char-set  char-list [base-cs] -> char-set +-
        list->char-set! char-list base-cs -> char-set +-
        ++
        ++list->char-set  char-list [base-cs] -> char-set ++
        ++
        list->char-set! char-list base-cs -> char-set ++
        ++
        ++

        + Return a character set containing the characters in the list of + characters char-list. +- +-

        ++

        ++

        + If character set base-cs is provided, the characters from char-list +- are added to it. list->char-set! is allowed, but not required, ++ are added to it. list->char-set! is allowed, but not required, + to side-effect and reuse the storage in base-cs; +- list->char-set produces a fresh character set. +- ++ list->char-set produces a fresh character set. ++

        ++
        + +-
        +- +- +-string->char-set  s [base-cs] -> char-set +-
        string->char-set! s base-cs -> char-set +-
        +- ++
        ++ ++ ++string->char-set  s [base-cs] -> char-set ++
        ++
        string->char-set! s base-cs -> char-set ++
        ++
        ++

        + Return a character set containing the characters in the string s. +- +-

        ++

        ++

        + If character set base-cs is provided, the characters from s are added to +- it. string->char-set! is allowed, but not required, to side-effect and +- reuse the storage in base-cs; string->char-set produces a fresh character ++ it. string->char-set! is allowed, but not required, to side-effect and ++ reuse the storage in base-cs; string->char-set produces a fresh character + set. +- ++

        ++
        + +-
        ++
        + + +-char-set-filter  pred cs [base-cs] -> char-set +-
        char-set-filter! pred cs base-cs -> char-set +-
        +- ++char-set-filter  pred cs [base-cs] -> char-set ++ ++
        char-set-filter! pred cs base-cs -> char-set ++
        ++
        ++

        + Returns a character set containing every character c + in cs such that (pred c) + returns true. +- ++

        +

        + If character set base-cs is provided, the characters specified + by pred are added to it. + char-set-filter! is allowed, but not required, + to side-effect and reuse the storage in base-cs; + char-set-filter produces a fresh character set. +- ++

        +

        + An implementation may not save away a reference to pred and + invoke it after char-set-filter or + char-set-filter! returns -- that is, "lazy," + on-demand implementations are not allowed, as pred may have + external dependencies on mutable data or have other side-effects. +- ++

        +

        + Rationale: This procedure provides a means of converting a character + predicate into its equivalent character set; the cs parameter +@@ -900,52 +1010,56 @@ with + be aware that filtering a character set such as char-set:full + could be a very expensive operation in an implementation that provided an + extremely large character type, such as 32-bit Unicode. An earlier draft +- of this library provided a simple predicate->char-set ++ of this library provided a simple predicate->char-set + procedure, which was rejected in favor of char-set-filter for + this reason. +- ++

        ++
        + + +-
        +- +- +-ucs-range->char-set  lower upper [error? base-cs] -> char-set +-
        ucs-range->char-set! lower upper error? base-cs -> char-set +-
        ++
        ++ ++ ++ucs-range->char-set  lower upper [error? base-cs] -> char-set ++
        ++
        ucs-range->char-set! lower upper error? base-cs -> char-set ++
        ++
        ++

        + Lower and upper are exact non-negative integers; +- lower <= upper. +- +-

        ++ lower <= upper. ++

        ++

        + Returns a character set containing every character whose ISO/IEC 10646 + UCS-4 code lies in the half-open range [lower,upper). +- ++

        +
          +
        • If the requested range includes unassigned UCS values, these are + silently ignored (the current UCS specification has "holes" in the + space of assigned codes). +- ++
        • +
        • If the requested range includes "private" or "user space" codes, these + are handled in an implementation-specific manner; however, a UCS- or + Unicode-based Scheme implementation should pass them through + transparently. +- ++
        • +
        • If any code from the requested range specifies a valid, assigned + UCS character that has no corresponding representative in the + implementation's character type, then (1) an error is raised if error? + is true, and (2) the code is ignored if error? is false (the default). + This might happen, for example, if the implementation uses ASCII + characters, and the requested range includes non-ASCII characters. ++
        • +
        +- +-

        ++

        + If character set base-cs is provided, the characters specified by the +- range are added to it. ucs-range->char-set! is allowed, but not required, ++ range are added to it. ucs-range->char-set! is allowed, but not required, + to side-effect and reuse the storage in base-cs; +- ucs-range->char-set produces a fresh character set. +- +-

        ++ ucs-range->char-set produces a fresh character set. ++

        ++

        + Note that ASCII codes are a subset of the Latin-1 codes, which are in turn + a subset of the 16-bit Unicode codes, which are themselves a subset of the + 32-bit UCS-4 codes. We commit to a specific encoding in this routine, +@@ -954,14 +1068,17 @@ with + implementation may use EBCDIC or SHIFT-JIS to encode characters; it must + simply map the UCS characters from the given range into the native + representation when possible, and report errors when not possible. +- ++

        ++
        + +-
        +- +-->char-set x -> char-set +-
        ++
        ++ ++->char-set x -> char-set ++
        ++
        ++

        + Coerces x into a char-set. + X may be a string, character or + char-set. A string is converted to the set of its constituent characters; +@@ -969,76 +1086,94 @@ with + as-is. + This procedure is intended for use by other procedures that want to + provide "user-friendly," wide-spectrum interfaces to their clients. +- ++

        ++
        +
        +- + +-

        Querying character sets

        ++

        Querying character sets

        +
        + + +-
        ++
        + +-char-set-size cs -> integer +-
        ++char-set-size cs -> integer ++ ++
        ++

        + Returns the number of elements in character set cs. +- ++

        ++
        + +-
        ++
        + +-char-set-count pred cs -> integer +-
        ++char-set-count pred cs -> integer ++ ++
        ++

        + Apply pred to the chars of character set cs, and return the number + of chars that caused the predicate to return true. +- ++

        ++
        + +-
        +- +-char-set->list cs -> character-list +-
        ++
        ++ ++char-set->list cs -> character-list ++
        ++
        ++

        + This procedure returns a list of the members of character set cs. + The order in which cs's characters appear in the list is not defined, + and may be different from one call to another. +- ++

        ++
        + +-
        +- +-char-set->string cs -> string +-
        ++
        ++ ++char-set->string cs -> string ++
        ++
        ++

        + This procedure returns a string containing the members of character set cs. + The order in which cs's characters appear in the string is not defined, + and may be different from one call to another. +- ++

        ++
        + +-
        ++
        + +-char-set-contains? cs char -> boolean +-
        ++char-set-contains? cs char -> boolean ++ ++
        ++

        + This procedure tests char for membership in character set cs. +- +-

        ++

        ++

        + The MIT Scheme character-set package called this procedure + char-set-member?, but the argument order isn't consistent with the name. +- ++

        ++
        + +-
        ++
        + + +-char-set-every pred cs -> boolean +-
        char-set-any   pred cs -> boolean +-
        ++char-set-every pred cs -> boolean ++ ++
        char-set-any   pred cs -> boolean ++
        ++
        ++

        + The char-set-every procedure returns true if predicate pred + returns true of every character in the character set cs. + Likewise, char-set-any applies pred to every character in +@@ -1046,169 +1181,171 @@ with + If no character produces a true value, it returns false. + The order in which these procedures sequence through the elements of + cs is not specified. +- +-

        ++

        ++

        + Note that if you need to determine the actual character on which a + predicate returns true, use char-set-any and arrange for the predicate + to return the character parameter as its true value, e.g. +-

        ++

        ++
        + (char-set-any (lambda (c) (and (char-upper-case? c) c)) 
        +               cs)
        + 
        ++
        +
        +- + +-

        Character-set algebra

        ++

        Character-set algebra

        +
        + + +-
        ++
        + + +-char-set-adjoin cs char1 ... -> char-set +-
        char-set-delete cs char1 ... -> char-set +-
        ++char-set-adjoin cs char1 ... -> char-set ++ ++
        char-set-delete cs char1 ... -> char-set ++
        ++
        ++

        + Add/delete the chari characters to/from character set cs. +- ++

        ++
        + +-
        ++
        + + +-char-set-adjoin! cs char1 ... -> char-set +-
        char-set-delete! cs char1 ... -> char-set +-
        +- ++char-set-adjoin! cs char1 ... -> char-set ++ ++
        char-set-delete! cs char1 ... -> char-set ++
        ++
        ++

        + Linear-update variants. These procedures are allowed, but not + required, to side-effect their first parameter. +- ++

        ++
        + +-
        ++
        + + + + + + +-char-set-complement cs -> char-set +-
        char-set-union cs1 ... -> char-set +-
        char-set-intersection cs1 ... -> char-set +-
        char-set-difference cs1 cs2 ... -> char-set +-
        char-set-xor cs1 ... -> char-set +-
        char-set-diff+intersection cs1 cs2 ... -> [char-set char-set] +-
        ++char-set-complement cs -> char-set ++ ++
        char-set-union cs1 ... -> char-set ++
        ++
        char-set-intersection cs1 ... -> char-set ++
        ++
        char-set-difference cs1 cs2 ... -> char-set ++
        ++
        char-set-xor cs1 ... -> char-set ++
        ++
        char-set-diff+intersection cs1 cs2 ... -> [char-set char-set] ++
        ++
        ++

        + These procedures implement set complement, union, intersection, + difference, and exclusive-or for character sets. The union, intersection + and xor operations are n-ary. The difference function is also n-ary, + associates to the left (that is, it computes the difference between + its first argument and the union of all the other arguments), + and requires at least one argument. +- +-

        ++

        ++

        + Boundary cases: +-

        +-(char-set-union) => char-set:empty
        +-(char-set-intersection) => char-set:full
        +-(char-set-xor) => char-set:empty
        +-(char-set-difference cs) => cs
        ++

        ++
        ++(char-set-union) => char-set:empty
        ++(char-set-intersection) => char-set:full
        ++(char-set-xor) => char-set:empty
        ++(char-set-difference cs) => cs
        + 
        +- +-

        ++

        + char-set-diff+intersection returns both the difference and the + intersection of the arguments -- it partitions its first parameter. + It is equivalent to +-

        ++

        ++
        + (values (char-set-difference cs1 cs2 ...)
        +         (char-set-intersection cs1 (char-set-union cs2 ...)))
        + 
        ++

        + but can be implemented more efficiently. +- ++

        +

        + Programmers should be aware that char-set-complement could potentially + be a very expensive operation in Scheme implementations that provide + a very large character type, such as 32-bit Unicode. If this is a + possibility, sets can be complimented with respect to a smaller + universe using char-set-difference. +- +- ++

        ++
        + +-
        +- +- +- +- +- +- +-char-set-complement! cs -> char-set +-
        char-set-union! cs1 cs2 ... -> char-set +-
        char-set-intersection! cs1 cs2 ... -> char-set +-
        char-set-difference! cs1 cs2 ... -> char-set +-
        char-set-xor! cs1 cs2 ... -> char-set +-
        char-set-diff+intersection! cs1 cs2 cs3 ... -> [char-set char-set] +-
        ++
        ++char-set-complement! cs -> char-set ++
        ++
        char-set-union! cs1 cs2 ... -> char-set ++
        ++
        char-set-intersection! cs1 cs2 ... -> char-set ++
        ++
        char-set-difference! cs1 cs2 ... -> char-set ++
        ++
        char-set-xor! cs1 cs2 ... -> char-set ++
        ++
        char-set-diff+intersection! cs1 cs2 cs3 ... -> [char-set char-set] ++
        ++
        ++

        + These are linear-update variants of the set-algebra functions. + They are allowed, but not required, to side-effect their first (required) + parameter. +- +-

        ++

        ++

        + char-set-diff+intersection! is allowed to side-effect both + of its two required parameters, cs1 + and cs2. ++

        ++
        +
        + + +-

        Standard character sets

        ++

        Standard character sets

        +

        + Several character sets are predefined for convenience: +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-

        +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- ++

        ++
        ++
        char-set:lower-case Lower-case letters
        char-set:upper-case Upper-case letters
        char-set:title-case Title-case letters
        char-set:letter Letters
        char-set:digit Digits
        char-set:letter+digit Letters and digits
        char-set:graphic Printing characters except spaces
        char-set:printing Printing characters including spaces
        char-set:whitespace Whitespace characters
        char-set:iso-control The ISO control characters
        char-set:punctuation Punctuation characters
        char-set:symbol Symbol characters
        char-set:hex-digit A hexadecimal digit: 0-9, A-F, a-f
        char-set:blank Blank characters -- horizontal whitespace
        char-set:ascii All characters in the ASCII set.
        char-set:empty Empty set
        char-set:full All characters
        ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +
        char-set:lower-case Lower-case letters
        char-set:upper-case Upper-case letters
        char-set:title-case Title-case letters
        char-set:letter Letters
        char-set:digit Digits
        char-set:letter+digit Letters and digits
        char-set:graphic Printing characters except spaces
        char-set:printing Printing characters including spaces
        char-set:whitespace Whitespace characters
        char-set:iso-control The ISO control characters
        char-set:punctuation Punctuation characters
        char-set:symbol Symbol characters
        char-set:hex-digit A hexadecimal digit: 0-9, A-F, a-f
        char-set:blank Blank characters -- horizontal whitespace
        char-set:ascii All characters in the ASCII set.
        char-set:empty Empty set
        char-set:full All characters
        +
        +- +

        + Note that there may be characters in char-set:letter that are neither upper or + lower case---this might occur in implementations that use a character type +@@ -1216,8 +1353,9 @@ richer than ASCII, such as Unicode. A "graphic character" is one that would + put ink on your page. While the exact composition of these sets may vary + depending upon the character type provided by the underlying Scheme system, + here are the definitions for some of the sets in an ASCII implementation: +-

        +- ++

        ++
        ++
        + + + +@@ -1232,76 +1370,93 @@ here are the definitions for some of the sets in an ASCII implementation: + +
        char-set:lower-case a-z
        char-set:upper-case A-Z
        char-set:letter A-Z and a-z
        char-set:iso-control ASCII 0-31 and 127
        +
        +- +

        + Note that the existence of the char-set:ascii set implies that the underlying + character set is required to be at least as rich as ASCII (including + ASCII's control characters). +- ++

        +

        + Rationale: The name choices reflect a shift from the older "alphabetic/numeric" + terms found in + R5RS + and Posix to newer, Unicode-influenced "letter/digit" lexemes. +- ++

        + +-

        +- Unicode, Latin-1 and ASCII definitions of the standard character sets +-

        ++

        ++ Unicode, Latin-1 and ASCII definitions of the standard character sets ++

        +

        + In Unicode Scheme implementations, the base character sets are compatible with +-Java's Unicode specifications. For ASCII or Latin-1, we simply restrict the ++Java's Unicode specifications. ++ ++

        ++

        For ASCII or Latin-1, we simply restrict the + Unicode set specifications to their first 128 or 256 codes, respectively. + Scheme implementations that are not based on ASCII, Latin-1 or Unicode should + attempt to preserve the sense or spirit of these definitions. +- ++

        +

        + The following descriptions frequently make reference to the "Unicode character + database." This is a file, available at URL +-

        ++

        ++ +-

        ++

        + Each line contains a description of a Unicode character. The first + semicolon-delimited field of the line gives the hex value of the character's + code; the second field gives the name of the character, and the third field + gives a two-letter category. Other fields give simple 1-1 case-mappings for + the character and other information; see +-

        ++

        ++ +-

        ++

        + for further description of the file's format. Note in particular the +-two-letter category specified in the third field, which is referenced ++two-letter category specified in the the third field, which is referenced + frequently in the descriptions below. +- ++

        + +-

        char-set:lower-case

        ++

        char-set:lower-case

        +

        + For Unicode, we follow Java's specification: a character is lowercase if ++

        +
          +-
        • it is not in the range [U+2000,U+2FFF], and +-
        • the Unicode attribute table does not give a lowercase mapping for it, and +-
        • at least one of the following is true: +-
            +-
          • the Unicode attribute table gives a mapping to uppercase +- for the character, or +-
          • the name for the character in the Unicode attribute table contains ++
          • it is not in the range [U+2000,U+2FFF], and ++
          • ++
          • the Unicode attribute table does not give a lowercase mapping for it, and ++
          • ++
          • at least one of the following is true: ++
              ++
            • the Unicode attribute table gives a mapping to uppercase ++ for the character, or ++
            • ++
            • the name for the character in the Unicode attribute table contains + the words "SMALL LETTER" or "SMALL LIGATURE". +-
            ++
          • ++
          ++
        • +
        + +

        + The lower-case ASCII characters are +-

        ++

        ++
        + abcdefghijklmnopqrstuvwxyz +
        +-

        ++

        + Latin-1 adds another 33 lower-case characters to the ASCII set: +-

        +- ++

        ++
        ++
        + + + +@@ -1337,38 +1492,41 @@ Latin-1 adds another 33 lower-case characters to the ASCII set: + +
        00B5 MICRO SIGN
        00DF LATIN SMALL LETTER SHARP S
        00E0 LATIN SMALL LETTER A WITH GRAVE
        00FF LATIN SMALL LETTER Y WITH DIAERESIS
        +
        +-

        ++

        + Note that three of these have no corresponding Latin-1 upper-case character: +-

        +- ++

        ++
        ++
        + + + +
        00B5 MICRO SIGN
        00DF LATIN SMALL LETTER SHARP S
        00FF LATIN SMALL LETTER Y WITH DIAERESIS
        +
        +-

        ++

        + (The compatibility micro character uppercases to the non-Latin-1 Greek capital + mu; the German sharp s character uppercases to the pair of characters "SS," + and the capital y-with-diaeresis is non-Latin-1.) +- ++

        +

        + (Note that the Java spec for lowercase characters given at +-

        ++

        ++ +-

        ++

        + is inconsistent. U+00B5 MICRO SIGN fulfills the requirements for a lower-case + character (as of Unicode 3.0), but is not given in the numeric list of + lower-case character codes.) +- ++

        +

        + (Note that the Java spec for isLowerCase() given at +-

        ++

        ++ +-

        ++

        + gives three mutually inconsistent definitions of "lower case." The first is + the definition used in this SRFI. Following text says "A character is + considered to be lowercase if and only if it is specified to be lowercase by +@@ -1377,33 +1535,41 @@ file)." The former spec excludes U+00AA FEMININE ORDINAL INDICATOR and + U+00BA MASCULINE ORDINAL INDICATOR; the later spec includes them. Finally, + the spec enumerates a list of characters in the Latin-1 subset; this list + excludes U+00B5 MICRO SIGN, which is included in both of the previous specs.) +- ++

        + +-

        char-set:upper-case

        ++

        char-set:upper-case

        +

        + For Unicode, we follow Java's specification: a character is uppercase if ++

        +
          +-
        • it is not in the range [U+2000,U+2FFF], and +-
        • the Unicode attribute table does not give an uppercase mapping for it ++
        • it is not in the range [U+2000,U+2FFF], and ++
        • ++
        • the Unicode attribute table does not give an uppercase mapping for it + (this excludes titlecase characters), and +-
        • at least one of the following is true: +-
            +-
          • the Unicode attribute table gives a mapping to lowercase ++
          • ++
          • at least one of the following is true: ++
              ++
            • the Unicode attribute table gives a mapping to lowercase + for the character, or +-
            • the name for the character in the Unicode attribute table contains ++
            • ++
            • the name for the character in the Unicode attribute table contains + the words "CAPITAL LETTER" or "CAPITAL LIGATURE". +-
            ++
          • ++
          ++
        • +
        + +

        + The upper-case ASCII characters are +-

        ++

        ++
        + ABCDEFGHIJKLMNOPQRSTUVWXYZ +
        +-

        ++

        + Latin-1 adds another 30 upper-case characters to the ASCII set: +-

        +- ++

        ++
        ++
        + + + +@@ -1437,109 +1603,112 @@ Latin-1 adds another 30 upper-case characters to the ASCII set: +
        00C0 LATIN CAPITAL LETTER A WITH GRAVE
        00C1 LATIN CAPITAL LETTER A WITH ACUTE
        00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX
        +
        + +-

        char-set:title-case

        ++

        char-set:title-case

        +

        + In Unicode, a character is titlecase if it has the category Lt in + the character attribute database. There are very few of these characters; + here is the entire 31-character list as of Unicode 3.0: +-

        +- +-
        01C5 LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON ++

        ++
        ++ ++ +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +
        01C5 LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON +
        01C8 LATIN CAPITAL LETTER L WITH SMALL LETTER J ++
        01C8 LATIN CAPITAL LETTER L WITH SMALL LETTER J +
        01CB LATIN CAPITAL LETTER N WITH SMALL LETTER J ++
        01CB LATIN CAPITAL LETTER N WITH SMALL LETTER J +
        01F2 LATIN CAPITAL LETTER D WITH SMALL LETTER Z ++
        01F2 LATIN CAPITAL LETTER D WITH SMALL LETTER Z +
        1F88 GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI ++
        1F88 GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +
        1F89 GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI ++
        1F89 GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +
        1F8A GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI ++
        1F8A GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +
        1F8B GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI ++
        1F8B GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +
        1F8C GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI ++
        1F8C GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +
        1F8D GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI ++
        1F8D GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +
        1F8E GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI ++
        1F8E GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +
        1F8F GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI ++
        1F8F GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +
        1F98 GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI ++
        1F98 GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +
        1F99 GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI ++
        1F99 GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +
        1F9A GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI ++
        1F9A GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +
        1F9B GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI ++
        1F9B GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +
        1F9C GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI ++
        1F9C GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +
        1F9D GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI ++
        1F9D GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +
        1F9E GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI ++
        1F9E GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +
        1F9F GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI ++
        1F9F GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +
        1FA8 GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI ++
        1FA8 GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +
        1FA9 GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI ++
        1FA9 GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +
        1FAA GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI ++
        1FAA GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +
        1FAB GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI ++
        1FAB GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +
        1FAC GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI ++
        1FAC GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +
        1FAD GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI ++
        1FAD GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +
        1FAE GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI ++
        1FAE GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +
        1FAF GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI ++
        1FAF GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +
        1FBC GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI ++
        1FBC GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +
        1FCC GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI ++
        1FCC GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +
        1FFC GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI ++
        1FFC GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +
        +
        +

        + There are no ASCII or Latin-1 titlecase characters. +- ++

        + + +-

        char-set:letter

        ++

        char-set:letter

        +

        + In Unicode, a letter is any character with one of the letter categories + (Lu, Ll, Lt, Lm, Lo) in the Unicode character database. +- ++

        +

        + There are 52 ASCII letters +-

        +- abcdefghijklmnopqrstuvwxyz
        +- ABCDEFGHIJKLMNOPQRSTUVWXYZ
        ++

        ++
        ++ abcdefghijklmnopqrstuvwxyz
        ++ ABCDEFGHIJKLMNOPQRSTUVWXYZ
        +
        +

        + There are 117 Latin-1 letters. These are the 115 characters that are + members of the Latin-1 char-set:lower-case and char-set:upper-case sets, + plus +-

        +- ++

        ++
        ++
        + + +
        00AA FEMININE ORDINAL INDICATOR
        00BA MASCULINE ORDINAL INDICATOR
        +
        +-

        ++

        + (These two letters are considered lower-case by Unicode, but not by + Java or SRFI 14.) +- ++

        + +-

        char-set:digit

        ++

        char-set:digit

        + +

        + In Unicode, a character is a digit if it has the category Nd in +@@ -1547,26 +1716,27 @@ the character attribute database. In Latin-1 and ASCII, the only + such characters are 0123456789. In Unicode, there are other digit + characters in other code blocks, such as Gujarati digits and Tibetan + digits. +- ++

        + + +-

        char-set:hex-digit

        ++

        char-set:hex-digit

        +

        + The only hex digits are 0123456789abcdefABCDEF. +- ++

        + + +-

        char-set:letter+digit

        ++

        char-set:letter+digit

        +

        + The union of char-set:letter and char-set:digit. +- ++

        + +-

        char-set:graphic

        ++

        char-set:graphic

        +

        + A graphic character is one that would put ink on paper. The ASCII and Latin-1 + graphic characters are the members of +-

        +- ++

        ++
        ++
        + + + +@@ -1575,30 +1745,38 @@ graphic characters are the members of + + + +-

        char-set:printing

        ++

        char-set:printing

        +

        + A printing character is one that would occupy space when printed, i.e., + a graphic character or a space character. char-set:printing is the union + of char-set:whitespace and char-set:graphic. +- ++

        + +-

        char-set:whitespace

        ++

        char-set:whitespace

        +

        + In Unicode, a whitespace character is either ++

        +
          +
        • a character with one of the space, line, or paragraph separator categories + (Zs, Zl or Zp) of the Unicode character database. ++
        • +
        • U+0009 Horizontal tabulation (\t control-I) ++
        • +
        • U+000A Line feed (\n control-J) ++
        • +
        • U+000B Vertical tabulation (\v control-K) ++
        • +
        • U+000C Form feed (\f control-L) ++
        • +
        • U+000D Carriage return (\r control-M) ++
        • +
        + +

        + There are 24 whitespace characters in Unicode 3.0: +-

        +-
        char-set:letter
        char-set:digit
        char-set:punctuation
        ++

        ++
        ++
        + + + +@@ -1630,11 +1808,12 @@ The ASCII whitespace characters are the first six characters in the above list + -- line feed, horizontal tabulation, vertical tabulation, form feed, carriage + return, and space. These are also exactly the characters recognised by the + Posix isspace() procedure. Latin-1 adds the no-break space. +- ++

        +

        + Note: Java's isWhitespace() method is incompatible, including +-

        +-
        0009 HORIZONTAL TABULATION \t control-I
        000A LINE FEED \n control-J
        000B VERTICAL TABULATION \v control-K
        ++

        ++
        ++
        + + + +@@ -1642,10 +1821,11 @@ Note: Java's isWhitespace() method is incompatible, including + +
        0009 HORIZONTAL TABULATION (\t control-I)
        001C FILE SEPARATOR (control-\)
        001D GROUP SEPARATOR (control-])
        001F UNIT SEPARATOR (control-_)
        +
        +-

        ++

        + and excluding +-

        +- ++

        ++
        ++
        + +
        00A0 NO-BREAK SPACE
        +
        +@@ -1654,67 +1834,71 @@ Java's excluding the no-break space means that tokenizers can simply break + character streams at "whitespace" boundaries. However, the exclusion introduces + exceptions in other places, e.g. char-set:printing is no longer simply the + union of char-set:graphic and char-set:whitespace. +- ++

        + + +-

        char-set:iso-control

        ++

        char-set:iso-control

        +

        + The ISO control characters are the Unicode/Latin-1 characters in the ranges + [U+0000,U+001F] and [U+007F,U+009F]. +- ++

        +

        + ASCII restricts this set to the characters in the range [U+0000,U+001F] + plus the character U+007F. +- ++

        +

        + Note that Unicode defines other control characters which do not belong to this + set (hence the qualifying prefix "iso-" in the name). This restriction is + compatible with the Java IsISOControl() method. +- ++

        + + +-

        char-set:punctuation

        ++

        char-set:punctuation

        +

        + In Unicode, a punctuation character is any character that has one of the + punctuation categories in the Unicode character database (Pc, Pd, Ps, + Pe, Pi, Pf, or Po.) +- ++

        +

        + ASCII has 23 punctuation characters: +-

        ++

        ++
        + !"#%&'()*,-./:;?@[\]_{}
        + 
        +

        + Latin-1 adds six more: +-

        +- ++

        ++
        ++
        +
        00A1 INVERTED EXCLAMATION MARK +-
        00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +-
        00AD SOFT HYPHEN +-
        00B7 MIDDLE DOT +-
        00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +-
        00BF INVERTED QUESTION MARK +-
        ++
        00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK ++
        00AD SOFT HYPHEN ++
        00B7 MIDDLE DOT ++
        00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK ++
        00BF INVERTED QUESTION MARK ++
        +
        + +

        +-Note that the nine ASCII characters $+<=>^`|~ are not ++Note that the nine ASCII characters $+<=>^`|~ are not + punctuation. They are "symbols." +- ++

        + + +-

        char-set:symbol

        ++

        char-set:symbol

        +

        + In Unicode, a symbol is any character that has one of the symbol categories + in the Unicode character database (Sm, Sc, Sk, or So). There + are nine ASCII symbol characters: +-

        ++

        ++
        + $+<=>^`|~
        + 
        +

        + Latin-1 adds 18 more: +-

        +- ++

        ++
        ++
        + + + +@@ -1737,20 +1921,24 @@ Latin-1 adds 18 more: + + + +-

        char-set:blank

        ++

        char-set:blank

        + +

        + Blank chars are horizontal whitespace. In Unicode, a blank character is either ++

        +
          +
        • a character with the space separator category (Zs) in the Unicode + character database. ++
        • +
        • U+0009 Horizontal tabulation (\t control-I) ++
        • +
        + +

        + There are eighteen blank characters in Unicode 3.0: +-

        +-
        00A2 CENT SIGN
        00A3 POUND SIGN
        00A4 CURRENCY SIGN
        ++

        ++
        ++
        + + + +@@ -1774,21 +1962,22 @@ There are eighteen blank characters in Unicode 3.0: +

        + The ASCII blank characters are the first two characters above -- + horizontal tab and space. Latin-1 adds the no-break space. +- ++

        +

        + Java doesn't have the concept of "blank" characters, so there are no + compatibility issues. +- ++

        + + +-

        Reference implementation

        ++

        Reference implementation

        +

        + This SRFI comes with a reference implementation. It resides at: +-

        +- +-http://srfi.schemers.org/srfi-14/srfi-14.scm ++

        ++ +-

        ++

        + I have placed this source on the Net with an unencumbered, "open" copyright. + Some of the code in the reference implementation bears a distant family + relation to the MIT Scheme implementation, and being derived from that code, +@@ -1797,37 +1986,45 @@ open-source copyright -- see the source file for details). The remainder of + the code was written by myself for scsh or for this SRFI; I have placed this + code under the scsh copyright, which is also a generic BSD-style open-source + copyright. +- ++

        +

        + The code is written for portability and should be simple to port to + any Scheme. It has only the following deviations from R4RS, clearly + discussed in the comments: ++

        +
          +
        • an error procedure; ++
        • +
        • the R5RS values procedure for producing multiple return values; ++
        • +
        • a simple check-arg procedure for argument checking; ++
        • +
        • let-optionals* and :optional macros for for parsing, checking and defaulting + optional arguments from rest lists; ++
        • +
        • The SRFI-19 define-record-type form; ++
        • +
        • bitwise-and for the hash function; +-
        • %latin1->char and %char->latin1. ++
        • ++
        • %latin1->char and %char->latin1. ++
        • +
        + +

        + The library is written for clarity and well-commented; the current source is + about 375 lines of source code and 375 lines of comments and white space. + It is also written for efficiency. Fast paths are provided for common cases. +- ++

        +

        + This is not to say that the implementation can't be tuned up for + a specific Scheme implementation. There are notes in comments addressing + ways implementors can tune the reference implementation for performance. +- ++

        +

        + In short, I've written the reference implementation to make it as painless + as possible for an implementor -- or a regular programmer -- to adopt this + library and get good results with it. +- ++

        +

        + The code uses a rather simple-minded, inefficient representation for + ASCII/Latin-1 char-sets -- a 256-character string. The character whose code is +@@ -1836,15 +2033,15 @@ not in the set if s[i] = ASCII 0 (nul). + A much faster and denser representation would be 16 or 32 bytes worth + of bit string. A portable implementation using bit sets awaits standards for + bitwise logical-ops and byte vectors. +- ++

        +

        + "Large" character types, such as Unicode, should use a sparse representation, + taking care that the Latin-1 subset continues to be represented with a + dense 32-byte bit set. +- ++

        + + +-

        Acknowledgements

        ++

        Acknowledgements

        +

        + The design of this library benefited greatly from the feedback provided during + the SRFI discussion phase. Among those contributing thoughtful commentary and +@@ -1857,114 +2054,127 @@ Kiselyov, Bengt Kleberg, Donovan Kolbly, Bruce Korb, Shriram Krishnamurthi, + Bruce Lewis, Tom Lord, Brad Lucier, Dave Mason, David Rush, Klaus Schilling, + Jonathan Sobel, Mike Sperber, Mikael Staldal, Vladimir Tsyshevsky, Donald + Welsh, and Mike Wilson. I am grateful to them for their assistance. +- ++

        +

        + I am also grateful the authors, implementors and documentors of all the + systems mentioned in the introduction. Aubrey Jaffer should be noted for his + work in producing Web-accessible versions of the R5RS spec, which was a + tremendous aid. +- ++

        +

        + This is not to imply that these individuals necessarily endorse the final + results, of course. +- ++

        +

        + During this document's long development period, great patience was exhibited + by Mike Sperber, who is the editor for the SRFI, and by Hillary Sullivan, + who is not. +- ++

        + +-

        References & links

        ++ + +
        +-
        [Java] ++
        [Java] ++
        +
        +- The following URLs provide documentation on relevant Java classes.
        ++ The following URLs provide documentation on relevant Java classes.
        + + http://java.sun.com/products/jdk/1.2/docs/api/java/lang/Character.html +-
        ++
        + http://java.sun.com/products/jdk/1.2/docs/api/java/lang/String.html +-
        ++
        + http://java.sun.com/products/jdk/1.2/docs/api/java/lang/StringBuffer.html +-
        ++
        + http://java.sun.com/products/jdk/1.2/docs/api/java/text/Collator.html +-
        ++
        + http://java.sun.com/products/jdk/1.2/docs/api/java/text/package-summary.html + +-
        [MIT-Scheme] ++ ++
        [MIT-Scheme] ++
        +
        + http://www.swiss.ai.mit.edu/projects/scheme/ + +-
        [R5RS]
        +-
        Revised5 report on the algorithmic language Scheme.
        +- R. Kelsey, W. Clinger, J. Rees (editors).
        +- Higher-Order and Symbolic Computation, Vol. 11, No. 1, September, 1998.
        +- and ACM SIGPLAN Notices, Vol. 33, No. 9, October, 1998.
        ++
        ++
        [R5RS]
        ++
        Revised5 report on the algorithmic language Scheme.
        ++ R. Kelsey, W. Clinger, J. Rees (editors).
        ++ Higher-Order and Symbolic Computation, Vol. 11, No. 1, September, 1998.
        ++ and ACM SIGPLAN Notices, Vol. 33, No. 9, October, 1998.
        + Available at + http://www.schemers.org/Documents/Standards/. + +-
        [SRFI]
        ++ ++
        [SRFI]
        +
        +- The SRFI web site.
        +- http://srfi.schemers.org/ ++ The SRFI web site.
        ++ http://srfi.schemers.org/ + +-
        [SRFI-14]
        ++ ++
        [SRFI-14]
        +
        +- SRFI-14: String libraries.
        +- http://srfi.schemers.org/srfi-14/ +- ++ SRFI-14: String libraries.
        ++ http://srfi.schemers.org/srfi-14/ +
        +
        + This document, in HTML: +-
        +- http://srfi.schemers.org/srfi-14/srfi-14.html +- ++ ++
        ++ https://srfi.schemers.org/srfi-14/srfi-14.html ++
        +
        + This document, in plain text format: +-
        +- http://srfi.schemers.org/srfi-14/srfi-14.txt +- ++ ++
        ++ https://srfi.schemers.org/srfi-14/srfi-14.txt ++
        +
        Source code for the reference implementation: ++
        +
        +- +- http://srfi.schemers.org/srfi-14/srfi-14.scm +- ++ ++ https://srfi.schemers.org/srfi-14/srfi-14.scm ++
        +
        Scheme 48 module specification, with typings: ++
        +
        +- +- http://srfi.schemers.org/srfi-14/srfi-14-s48-module.scm +- ++ ++ https://srfi.schemers.org/srfi-14/srfi-14-s48-module.scm ++
        +
        Regression-test suite: +-
        +- http://srfi.schemers.org/srfi-14/srfi-14-tests.scm +- ++ ++
        ++ https://srfi.schemers.org/srfi-14/srfi-14-tests.scm ++
        +
        +
        + +-
        [Unicode] ++
        [Unicode] ++
        +
        + http://www.unicode.org/ +- +-
        [UnicodeData] ++ ++
        [UnicodeData] ++
        +
        +- The Unicode character database.
        ++ The Unicode character database.
        + ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt +-
        ++
        + ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.html ++
        +
        + + +-

        Copyright

        ++ + +

        + Certain portions of this document -- the specific, marked segments of text + describing the R5RS procedures -- were adapted with permission from the R5RS + report. +- ++

        +

        + All other text is copyright (C) Olin Shivers (1998, 1999, 2000). + All Rights Reserved. +- ++

        +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -1987,10 +2197,10 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        +- ++
        ++
        Editor: Michael Sperber
        + +- +- ++ +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-16.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-16.html +index a335320..81f4963 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-16.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-16.html +@@ -1,57 +1,78 @@ +- +- ++ ++ + ++ ++ + SRFI 16: Syntax for procedures of variable arity ++ ++ + + + + +-

        Title

        ++

        SRFI 16: Syntax for procedures of variable arity.

        + +-SRFI 16: Syntax for procedures of variable arity. ++

        by Lars T Hansen

        ++

        This copy of the SRFI 16 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-16/srfi-16.html.

        + +-

        Author

        ++

        Status

        + +-Lars T Hansen +- +-

        Status

        +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

          +-
        • Received: 1999/11/01 +-
        • Draft: 1999/11/06-2000/01/07 +-
        • Final: 2000/03/10 +-
        +- +-

        Abstract

        ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-16@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Received: 1999-11-01
        • ++
        • Draft: 1999-11-06--2000-01-07
        • ++
        • Final: 2000-03-10
        • ++
        + ++

        Abstract

        ++

        + CASE-LAMBDA, a syntax for procedures with a variable number of arguments, + is introduced. ++

        + +-

        Rationale

        +- ++

        Rationale

        ++

        + CASE-LAMBDA reduces the clutter of procedures that execute different + code depending on the number of arguments they were passed; it is + a pattern-matching mechanism that matches on the number of arguments. + CASE-LAMBDA is available in some Scheme systems. +- ++

        +

        While CASE-LAMBDA can be implemented as a macro using only facilities + available in R5RS Scheme, it admits considerable implementation-specific + optimization. ++

        + +- +-

        Specification

        ++

        Specification

        + +
        +-
        ++
        + (CASE-LAMBDA <clause> ...) +-
        Syntax ++
        Syntax ++
        +
        +-

        Each <clause> should have the form (<formals> <body>), where ++

        Each <clause> should have the form (<formals> <body>), where + <formals> is a formal arguments list as for LAMBDA, cf section + 4.1.4 of the R5RS. Each <body> is a <tail-body>, cf section + 3.5 of the R5RS. +- ++

        +

        A CASE-LAMBDA expression evaluates to a procedure that accepts + a variable number of arguments and is lexically scoped in the + same manner as procedures resulting from LAMBDA expressions. +@@ -63,10 +84,10 @@ optimization. + locations, the <body> is evaluated in the extended environment, + and the results of <body> are returned as the results of the + procedure call. +- ++

        +

        It is an error for the arguments not to agree with the <formals> + of any <clause>. +- ++

        +
        +              (define plus
        +                (case-lambda 
        +@@ -85,23 +106,26 @@ optimization.
        +                ((a b) (* a b)))
        +               1 2 3)                    --> error
        + 
        ++
        +
        + +-

        Implementation

        +- ++

        Implementation

        ++

        + The following implementation is written in R5RS Scheme. It is not + compatible with the IEEE Scheme standard because the IEEE standard does + not contain the high-level macro system. +- ++

        +

        The implementation assumes that some top-level names defined by the + R5RS are bound to their original values. +- +-

        ++

        +
        + ;; This code is in the public domain.
        + 
        + (define-syntax case-lambda
        +   (syntax-rules ()
        ++    ((case-lambda)
        ++     (lambda args
        ++       (error "CASE-LAMBDA without any clauses.")))
        +     ((case-lambda 
        +       (?a1 ?e1 ...) 
        +       ?clause1 ...)
        +@@ -135,15 +159,14 @@ R5RS are bound to their original values.
        +       ?clause1 ...))
        +     ((case-lambda "IMPROPER" ?args ?l ?k ?al (?ar ?e1 ...) 
        +       ?clause1 ...)
        +-     (if (>= ?l ?k)
        ++     (if (>= ?l ?k)
        +          (apply (lambda ?al ?e1 ...) ?args)
        +          (case-lambda "CLAUSE" ?args ?l 
        +            ?clause1 ...)))))
        + 
        + +-

        Copyright

        ++

        Copyright

        +

        Copyright (C) Lars T Hansen (1999). All Rights Reserved.

        +- +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -167,11 +190,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        +-
        Editor: Mike Sperber
        ++
        ++
        Editor: Mike Sperber
        + + +-Last modified: Mon Apr 19 20:38:48 CEST 2004 ++Last modified: Fri Sep 18 18:34:31 MST 2009 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-17.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-17.html +index dc06d9d..e21b0b6 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-17.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-17.html +@@ -1,41 +1,63 @@ +- +- ++ ++ + ++ ++ + SRFI 17: Generalized set! ++ ++ ++ + + + + +-

        Title

        +- +-SRFI 17: Generalized set! +- +-

        Author

        ++

        SRFI 17: Generalized set!

        + +-Per Bothner ++

        by Per Bothner

        ++

        This copy of the SRFI 17 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-17/srfi-17.html.

        + +-

        Status

        ++

        Status

        + +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

          +-
        • Received: 1999/12/08 +-
        • Draft: 2000/01/16-2000/03/17 +-
        • Revised: 2000/04/28 +-
        • Final: 2000/07/24 +-
        +- +-

        Abstract

        ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-17@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Received: 1999-12-08
        • ++
        • Draft: 2000-01-16--2000-03-17
        • ++
        • Revised: 2000-04-28
        • ++
        • Final: 2000-07-24
        • ++
        + ++

        Abstract

        ++

        + This is a proposal to allow procedure calls that evaluate + to the "value of a location" to be used to set + the value of the location, when used as the first + operand of set!. + For example: ++

        +
        + (set! (car x) (car y))
        + 
        ++

        + becomes equivalent to ++

        +
        + (set-car! x (car y))
        + 
        +@@ -49,14 +71,16 @@ which can be used in setf and some other special forms. + However, the Common Lisp concept is based on the idea of + compile-time recognition of special "location-producing" functions; + this does not seem to be in the "spirit of Scheme". ++

        +

        + This SRFI proposes an extension of set! + so that it provides similar functionality as Common Lisp's setf, + except that the updater is associated with a procedure value, + rather than a name. ++

        + +-

        Rationale

        +- ++

        Rationale

        ++

        + There is ample precedent for general "lvalues" on the + left-hand side of an assignment. This includes most statically + typed languages, and many dynamically typed languages (including APL +@@ -66,6 +90,7 @@ Another is that it becomes visually clearer which expression is the new value, + and which are parameters. Also, the visual consistency between + an expression evaluated for its value and one evaluated to yield + a location seems natural to people. ++

        +

        + For most languages, the set of lvalue-producing operators is limited + (typically array indexing and field selection). Some languages have +@@ -77,19 +102,21 @@ mutable variables are first-class "cells", and accessing the + contents of a cell requires an explicit operator. This is also not + compatible with Scheme. Instead we need to stick to the model + where using a variable in most contexts means using its value, +-but referring to a variable in certain lvalue contexts (lhs of ++but refering to a variable in certain lvalue contexts (lhs of + assignment) refers to its actual location. Sticking to this model + for general "lvalue expressions" in set! means + that "evaluation" must be done differently from normal + evaluation when in an "lvalue context". That is what this proposal does. ++

        +

        + This is a controversial issue. This srfi does not wish to imply that + all Scheme implementations should support this feature; it only + requests that implementations that do implement + generalized set! should be compatible with this srfi. ++

        + +-

        Specification

        +- ++

        Specification

        ++

        + The special form set! is extended so the first operand + can be a procedure application, and not just a variable. + The procedure is typically one that extracts a component from +@@ -97,10 +124,13 @@ some data structure. Informally, when the procedure is called + in the first operand of set!, it causes the corresponding + component to be replaced by the second operand. + For example, ++

        +
        + (set (vector-ref x i) v)
        + 
        ++

        + would be equivalent to: ++

        +
        + (vector-set! x i v)
        + 
        +@@ -109,12 +139,16 @@ Each procedure that may be used as the first operand to set! + must have a corresponding "setter" procedure. + The builtin procedure setter takes a procedure and returns the + corresponding setter procedure. ++

        +

        + We define: ++

        +
        + (set! (proc arg ...) value)
        + 
        ++

        + as: ++

        +
        + ((setter proc) arg ... value)
        + 
        +@@ -124,9 +158,11 @@ the existing Scheme convention for setter procedures, where + the new value is given last. For example we can define + (setter car) to be set-car!. + An alternative definition would be: ++

        +
        + ((setter proc) value arg ...) ;; Not the actual definition.
        + 
        ++

        + This definition would work better when you consider + procedures that take a variable number of arguments. + This is because it is straight-forward to add one extra +@@ -135,10 +171,12 @@ argument to the end of an argument list that has + a "rest" parameter, then things get more messy. + However, consistency with the existing new-value-last convention + seems more valuable. ++

        + +-

        Standard setters

        +- ++

        Standard setters

        ++

        + The following standard procedures have pre-defined setters: ++

        +
        + (set! (car x) v) == (set-car! x v)
        + (set! (cdr x) v) == (set-cdr! x v)
        +@@ -161,20 +199,23 @@ One useful addition:
        + variable-length mutable strings.)
        + -->
        + 
        +-

        Setting setters; properties

        +- ++

        Setting setters; properties

        ++

        + A setter procedure is a special case of the concept of procedures having + associated properties. Other properties might include + the procedures's name or usage documentation. + As a hypothetical example (i.e. not part of this SRFI), + we can use the Common Lisp documentation function, + where for example: ++

        +
        + (documentation sqrt)
        + 
        ++

        + returns the "documentation string" (if defined) for sqrt. + Such properties should also be settable using generalized set!. + For example: ++

        +
        + (set! (documentation sqrt) "Calculates the square root.")
        + 
        +@@ -184,19 +225,24 @@ This SRFI does + not propose a general "procedure properties" feature, but it + should be compatible with it. It does specify the special case + for the setter property. This is defined such that: ++

        +
        + (set! (setter proc) setter)
        + 
        ++

        + sets the setter procedure associated with proc + to setter. + For example, we can assume ++

        +
        + (set! (setter car) set-car!)
        + 
        ++

        + has been executed by the Scheme prologue. ++

        + +-

        Efficiency Issues

        +- ++

        Efficiency Issues

        ++

        + If (set! (foo ..) ...) is to be the preferred idiom, + we want to make ((setter foo) ...) as efficient + as (set-foo! ...). +@@ -216,32 +262,42 @@ compilation more difficult. However, the next section does define + a way to inherently tie a setter to a procedure, which does reduce + the problem of inlining generalized set! to the + standard inlining problem. ++

        + +-

        getter-with-setter

        ++

        getter-with-setter

        +

        The function getter-with-setter can be used + to define a procedure with associated properties. +-Specifically: ++Specifically: ++

        +
        + (getter-with-setter getter setter)
        + 
        ++

        + This evaluates to a new anonymous procedure which when + applied invokes getter, and whose setter is setter. + It is an error for a program to subsequently try to modify + the setter of the resulting compound. ++

        +

        + For example, we could define: ++

        +
        + (define car (getter-with-setter %primitive-car %primitive-set-car!))
        + (define set-car! %primitive-set-car!)
        + 
        ++

        + The advantage of this approach that whenever a compiler can inline + car, it can also inline (setter car). ++

        + +-

        Implementation

        +- +-Here is a sample implementation ++

        Implementation

        ++

        ++Here is a sample implementation + for Twobit. +-

        Here is a sample definition of getter-with-setter: ++

        ++

        ++Here is a sample definition of getter-with-setter: ++

        +
        + (define (getter-with-setter get set)
        +   (let ((proc (lambda args (apply get args))))
        +@@ -249,9 +305,8 @@ for Twobit.
        +     proc))
        + 
        + +-

        Copyright

        ++

        Copyright

        +

        Copyright (C) Per Bothner (1999, 2000). All Rights Reserved.

        +- +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -275,11 +330,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        +-
        Editor: Mike Sperber
        ++
        ++
        Editor: Mike Sperber
        + + +-Last modified: Mon Jul 24 12:00:06 MST 2000 ++Last modified: Fri Sep 18 17:00:11 MST 2009 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-19.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-19.html +index b2a612e..c7acadd 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-19.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-19.html +@@ -1,13 +1,32 @@ +- +- ++ ++ + ++ ++ + SRFI 19: Time Data Types and Procedures +- +- ++ ++ ++ ++ + + +- +- + + + + +-

        Title

        +- +-SRFI 19: Time Data Types and Procedures +- +-

        Author

        +- +-Will Fitzgerald +- +-

        Status

        ++

        SRFI 19: Time Data Types and Procedures

        + +-

        This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. You can +-access the discussion via +-the archive of the mailing list. ++

        by Will Fitzgerald

        ++

        This copy of the SRFI 19 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-19/srfi-19.html.

        + ++

        Status

        + +-
          +-
        • Draft: 2000-02-28 to 2000-08-28
        • +-
        • Final: 2000-08-31
        • +-
        • Fixed reference implementation: 2003-02-28
        • +-
        • Documentation bug for ~D fixed: 2003-05-30
        • +-
        • Various Documentation bugs fixed: 2004-03-15
        • +-
        +- +-

        Abstract

        +- +-Points in time are represented a the number of seconds (with ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-19@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Draft: 2000-02-28 to 2000-08-28
        • ++
        • Final: 2000-08-31
        • ++
        • Revised to fix errata: ++
            ++
          • 2003-02-28 (Fixed reference implementation.)
          • ++
          • 2003-05-30 (Fixed documentation bug for ~D.)
          • ++
          • 2004-03-15 (Fixed various documentation bugs.)
          • ++
          • 2017-05-05 (Fixed definition of Julian Day and Modified Julian Day.)
          • ++
          • 2019-6-11 (Fixed week number definitions in Table 1. Note that this was an incompatible change to the API.)
        ++ ++

        Abstract

        ++

        ++Points in time are represented as the number of seconds (with + nanosecond precision) since "the epoch," a zero point in time. Several + standard variants are defined, including UTC (universal coordinated + time), TAI (international atomic time), and monotonic time. A point in time can also be +@@ -160,45 +177,49 @@ routines are provided. The procedure CURRENT-TIME queries the current + time in a specified variant, with a system-dependent + resolution. Procedures for time arithmetic and time comparisons are + also provided. +- +-

        A date is a representation of a point in time in the Gregorian ++

        ++

        ++A date is a representation of a point in time in the Gregorian + calendar, a 24 hour clock (with nanosecond precision) and a + time zone offset from UTC. Procedures for + converting between time and dates are provided, as well as for reading + and writing string representations of dates. ++

        + +-

        Issues

        [None currently] +- ++

        Issues

        ++

        [None currently]

        + +-

        Rationale

        + ++

        Rationale

        ++

        + R5RS Scheme does not provide standard data types for time. This + SRFI addresses this lack by specifying data types for time and + associated procedures. ++

        + +- +-

        Specification

        ++

        Specification

        + +

        A Time object, which is distinct from all existing types, + defines a point in time or a time duration in some standard time +-system. The standard time systems are: +- ++system. The standard time systems are: ++

        +
          +
        • Universal Coordinated Time (UTC), +-
        • International Atomic Time (TAI), +-
        • monotonic time (a monotonically increasing point in time from some ++
        • International Atomic Time (TAI), ++
        • monotonic time (a monotonically increasing point in time from some + epoch, which is implementation-dependent), +-
        • CPU time in current thread (implementation dependent), +-
        • CPU time in current process (implementation dependent), +-
        • Time duration. +-
        +- ++
      • CPU time in current thread (implementation dependent), ++
      • CPU time in current process (implementation dependent), ++
      • Time duration. ++
      • ++

        + Implementations are required to implement UTC, monotonic time, CPU + time in current process, and time duration. Implementations are + allowed to create extensions (for example, amount of time spent in + garbage collection). +- +-

        A time object consists of three components: ++

        ++

        A time object consists of three components: ++

        +
          +
        • Time type, a symbol representing the time system + representation used. The constants TIME-TAI, +@@ -207,100 +228,110 @@ garbage collection). + TIME-DURATION must be provided for these + symbols. Implementations should provide constants for time type + extensions. +-
        • Second, an integer representing the number ++
        • Second, an integer representing the number + of whole seconds from "the epoch." +-
        • Nanosecond, an ++
        • Nanosecond, an + integer of the number of nanoseconds in the fractional + portion. Although a time object has nanosecond precision, clocks + may have a lower resolution. +-
        ++ + +-

        A Date object, which is distinct from all existing ++

        A Date object, which is distinct from all existing + types, represents a point in time as represented by the Gregorian + calendar as well as by a time zone. Dates are immutable. A date + consists of the following components: +- ++

        +
          +
        • Nanosecond, an integer between 0 and 9,999,999, inclusive. +-
        • Second, an integer 0 and 60, inclusive, ++
        • ++
        • Second, an integer 0 and 60, inclusive, + (60 represents a leap second) ++
        • +
        • Minute, an integer between 0 and 59, inclusive, ++
        • +
        • Hour, an integer between 0 and 23, inclusive, ++
        • +
        • Day, an integer between 0 and 31, inclusive, the upper limit depending + on the month and year of the point in time, ++
        • +
        • Month, an integer between 1 and 12, inclusive; in which 1 means + January, 2 February, and so on. ++
        • +
        • Year, an integer representing the year. ++
        • +
        • Time zone, an integer representing the number of seconds east of GMT for this timezone. ++
        • +
        ++

        ++A Julian Day represents a point in time as a real number of days ++since -4713-11-24T12:00:00Z (midday UT on 24 November 4714 BC in the ++proleptic Gregorian calendar (1 January 4713 BC in the proleptic Julian calendar)). ++

        ++

        ++A Modified Julian Day represents a point in time as a real number of ++days since 1858-11-17T00:00:00Z (midnight UT on 17 November AD 1858). ++

        + +-

        A Julian Day represents a point in time as a real number +-of days since -4714-11-24T12:00:00Z (November 24, -4714 at noon, +-UTC). +- +-

        A Modified Julian Day represents a point in time as a +-real number of days since 1858-11-17T00:00:00Z (November 17, +-1858 at midnight, UTC). +- +-

        Constants

        +-

        The following constants are required: +- +-

        +-
        time-duration +-
        Symbol representing Time duration. +-
        time-monotonic +-
        Symbol representing monotonic time. +-
        time-process +-
        Symbol representing time spent in current process. +-
        time-tai +-
        Symbol representing TAI time. +-
        time-thread +-
        Symbol representing time spent in current thread. +-
        time-utc +-
        Symbol representting UTC time. +-
        +-

        Current time and clock resolution

        +-

        The following procedures are required: +- +-

        +-
        current-date [tz-offset] -> date +-
        Date corresponding to the current UTC time. +-
        current-julian-day -> jdn +-
        Current Julian Day. +-
        current-modified-julian-day -> mjdn +-
        Current Modified Julian Day. +-
        current-time [time-type] -> time +-
        Current time, of type time-type system, which defaults to TIME-UTC. +-
        time-resolution [time-type] -> integer +-
        Clock resolution, in nanoseconds, of the system clock of type type time-type system, which defaults to TIME-UTC. +-
        +-

        Time object and accessors

        +-

        The following procedures are required: +-

        +-
        make-time type nanosecond second -> time +-
        Creates a time object. +-
        time? object -> boolean +-
        #t if object is a time object, otherwise, #f. +-
        time-type time -> time-type +-
        Time type. +-
        time-nanosecond time -> integer +-
        Time nanosecond. +-
        time-second time -> integer +-
        Time second. +-
        set-time-type! time time-type +-
        Changes time type. Note: This changes the semantics of the time object. To convert a time to another ++

        Constants

        ++

        The following constants are required: ++

        ++
        ++
        time-duration ++
        Symbol representing Time duration. ++
        time-monotonic ++
        Symbol representing monotonic time. ++
        time-process ++
        Symbol representing time spent in current process. ++
        time-tai ++
        Symbol representing TAI time. ++
        time-thread ++
        Symbol representing time spent in current thread. ++
        time-utc ++
        Symbol representing UTC time. ++
        ++

        Current time and clock resolution

        ++

        The following procedures are required: ++

        ++
        ++
        current-date [tz-offset] -> date ++
        Date corresponding to the current UTC time. ++
        current-julian-day -> jdn ++
        Current Julian Day. ++
        current-modified-julian-day -> mjdn ++
        Current Modified Julian Day. ++
        current-time [time-type] -> time ++
        Current time, of type time-type system, which defaults to TIME-UTC. ++
        time-resolution [time-type] -> integer ++
        Clock resolution, in nanoseconds, of the system clock of type type time-type system, which defaults to TIME-UTC. ++
        ++

        Time object and accessors

        ++

        The following procedures are required: ++

        ++
        ++
        make-time type nanosecond second -> time ++
        Creates a time object. ++
        time? object -> boolean ++
        #t if object is a time object, otherwise, #f. ++
        time-type time -> time-type ++
        Time type. ++
        time-nanosecond time -> integer ++
        Time nanosecond. ++
        time-second time -> integer ++
        Time second. ++
        set-time-type! time time-type ++
        Changes time type. Note: This changes the semantics of the time object. To convert a time to another + system of representation, use one of the conversion procedures. +-
        set-time-nanosecond! time integer +-
        Changes time nanosecond. +-
        set-time-second! time integer +-
        Changes time second. +-
        copy-time time1 -> time2 +-
        Creates a new time object, with the same time type, nanosecond, and second as time1. +-
        ++
        set-time-nanosecond! time integer ++
        Changes time nanosecond. ++
        set-time-second! time integer ++
        Changes time second. ++
        copy-time time1 -> time2 ++
        Creates a new time object, with the same time type, nanosecond, and second as time1. ++
        + +-

        Time comparison procedures

        ++

        Time comparison procedures

        + +-

        All of the time comparison procedures require the time objects to ++

        All of the time comparison procedures require the time objects to + be of the same type. It is an error to use these procedures on time + objects of different types. For the point-in-time measurements (e.g., + TIME-TAI and TIME-UTC), the semantics are +@@ -308,243 +339,259 @@ described in plain text. For durations, (e.g., + TIME-DURATION, TIME-CPU, the semantics are + described in parentheses. + +-

        The following procedures are required: +-

        +-
        time<=? time1 time2 -> boolean +-
        #t if time1 is before or at (less than or equal to) time2, #f otherwise. +-
        time<? time1 time2 -> boolean +-
        #t if time1 is before (less than) time2, #f otherwise. +-
        time=? time1 time2 -> boolean +-
        #t if time1 at (equal) time2, #f otherwise. +-
        time>=? time1 time2 -> boolean +-
        #t if time1 is at or after (greater than or equal to) time2, #f otherwise. +-
        time>? time1 time2 -> boolean +-
        #t if time1 is after (greater than) time2, #f otherwise. +-
        +- +-

        Time arithmetic procedures

        +- +-

        The following procedures are required. +-

        +-
        time-difference time1 time2 -> time-duration +-
        The TIME-DURATION between time1 and time2. It is an error if time1 and time2 are of different time types. A new time object is created. +-
        time-difference! time1 time2 -> time-duration +-
        The TIME-DURATION between time1 and time2. It is an error if time1 and time2 are of different time types. Time1 may be used to create the resulting TIME-DURATION object. +-
        add-duration time1 time-duration -> time +-
        The time resulting from adding time-duration to time1, which is a time object of the same time type as time1. A new time object is created. +-
        add-duration! time1 time-duration -> time +-
        The time resulting from adding time-duration to time1, which is a time object of the same time type as time1. Time1 may used to create the resulting time object. +-
        subtract-duration time1 time-duration -> time +-
        The time resulting from subtracting time-duration to time1, which is a time object of the same time type as time1. A new time object is created. +-
        subtract-duration! time1 time-duration -> time +-
        The time resulting from subtracting time-duration to time1, which is a time object of the same time type as time1. Time1 may used to create the resulting time object. +-
        +- +-

        Date object and accessors

        +- +-

        Date objects are immutable once created. The following procedures are required. +-

        +- +-
        make-date nanosecond second minute hour day month year zone-offset -> date +-
        Creates a date object. +-
        date? date -> boolean +-
        #t if object is a time object, otherwise, #f. +-
        date-nanosecond date -> integer +-
        Date nanosecond. +-
        date-second date -> integer +-
        Date second. +-
        date-minute date -> integer +-
        Date minute. +-
        date-hour date -> integer +-
        Date hour. +-
        date-day date -> integer +-
        Date day. +-
        date-month date -> integer +-
        Date month. +-
        date-year date -> integer +-
        Date year. +-
        date-zone-offset date -> integer +-
        Date time zone offset. +-
        date-year-day date -> integer +-
        The ordinal day of the year of this date. January 1 is 1, etc. +-
        date-week-day date -> integer +-
        The day of the week of this date, where Sunday=0, Monday=1, etc. +-
        date-week-number date day-of-week-starting-week -> integer +-
        The ordinal week of the year which holds this date, ignoring a first partial week. 'Day-of-week-starting-week' is the integer corresponding to the day of the week which is to be considered the first day of the week (Sunday=0, Monday=1, etc.). +-
        +- +-

        Time/Date/Julian Day/Modified Julian Day Converters

        ++

        The following procedures are required: ++

        ++
        ++
        time<=? time1 time2 -> boolean ++
        #t if time1 is before or at (less than or equal to) time2, #f otherwise. ++
        time<? time1 time2 -> boolean ++
        #t if time1 is before (less than) time2, #f otherwise. ++
        time=? time1 time2 -> boolean ++
        #t if time1 at (equal) time2, #f otherwise. ++
        time>=? time1 time2 -> boolean ++
        #t if time1 is at or after (greater than or equal to) time2, #f otherwise. ++
        time>? time1 time2 -> boolean ++
        #t if time1 is after (greater than) time2, #f otherwise. ++
        ++ ++

        Time arithmetic procedures

        ++ ++

        The following procedures are required. ++

        ++
        ++
        time-difference time1 time2 -> time-duration ++
        The TIME-DURATION between time1 and time2. It is an error if time1 and time2 are of different time types. A new time object is created. ++
        time-difference! time1 time2 -> time-duration ++
        The TIME-DURATION between time1 and time2. It is an error if time1 and time2 are of different time types. Time1 may be used to create the resulting TIME-DURATION object. ++
        add-duration time1 time-duration -> time ++
        The time resulting from adding time-duration to time1, which is a time object of the same time type as time1. A new time object is created. ++
        add-duration! time1 time-duration -> time ++
        The time resulting from adding time-duration to time1, which is a time object of the same time type as time1. Time1 may used to create the resulting time object. ++
        subtract-duration time1 time-duration -> time ++
        The time resulting from subtracting time-duration to time1, which is a time object of the same time type as time1. A new time object is created. ++
        subtract-duration! time1 time-duration -> time ++
        The time resulting from subtracting time-duration to time1, which is a time object of the same time type as time1. Time1 may used to create the resulting time object. ++
        ++ ++

        Date object and accessors

        ++ ++

        Date objects are immutable once created. The following procedures are required. ++

        ++
        ++
        make-date nanosecond second minute hour day month year zone-offset -> date ++
        Creates a date object. ++
        date? date -> boolean ++
        #t if object is a time object, otherwise, #f. ++
        date-nanosecond date -> integer ++
        Date nanosecond. ++
        date-second date -> integer ++
        Date second. ++
        date-minute date -> integer ++
        Date minute. ++
        date-hour date -> integer ++
        Date hour. ++
        date-day date -> integer ++
        Date day. ++
        date-month date -> integer ++
        Date month. ++
        date-year date -> integer ++
        Date year. ++
        date-zone-offset date -> integer ++
        Date time zone offset. ++
        date-year-day date -> integer ++
        The ordinal day of the year of this date. January 1 is 1, etc. ++
        date-week-day date -> integer ++
        The day of the week of this date, where Sunday=0, Monday=1, etc. ++
        date-week-number date day-of-week-starting-week -> integer ++
        The ordinal week of the year which holds this date, ignoring a first partial week. 'Day-of-week-starting-week' is the integer corresponding to the day of the week which is to be considered the first day of the week (Sunday=0, Monday=1, etc.). ++
        ++ ++

        Time/Date/Julian Day/Modified Julian Day Converters

        + + The following conversion procedures are required. +-
        +-
        date->julian-day date -> jd +-
        Convert date to Julian Day. +-
        date->modified-julian-day date -> mjd +-
        Convert date to Modified Julian Day. +-
        date->time-monotonic date -> time-monotonic +-
        Convert date to monotonic time. +-
        date->time-tai date -> time-tai +-
        Convert date to TAI time. +-
        date->time-utc date -> time-utc +-
        Convert date to UTC time. +-
        julian-day->date jd [tz-offset] -> date +-
        Convert Julian Day to date, , using time zone offset, which defaults to the local time zone. +-
        julian-day->time-monotonic jd -> time-monotonic +-
        Convert Julian Day to monotonic time. +-
        julian-day->time-tai jd -> time-tai +-
        Convert Julian Day to TAI time. +-
        julian-day->time-utc jd -> time-utc +-
        Convert Julian Day to UTC time. +-
        modified-julian-day->date mjd [tz-offset] -> date +-
        Convert Modified Julian Day to date, using time zone offset, which defaults to the local time zone. +-
        modified-julian-day->time-monotonic mjd -> time-monotonic +-
        Convert Modified Julian Day to monotonic time. +-
        modified-julian-day->time-tai mjd -> time-tai +-
        Convert Modified Julian Day to TAI time. +-
        modified-julian-day->time-utc mjd -> time-utc +-
        Convert Modified Julian Day to UTC time. +-
        time-monotonic->date time-monotonic [tz-offset] -> date +-
        Convert monotonic time to date, using time zone offset, which defaults to the local time zone. +-
        time-monotonic->julian-day time-monotonic -> jd +-
        Convert monotonic time to Julian Day. +-
        time-monotonic->modified-julian-day time-monotonic -> mjd +-
        Convert monotonic time to Modified Julian Day. +-
        time-monotonic->time-tai time-monotonic -> time-tai +-
        Convert monotonic time to TAI time. +-
        time-monotonic->time-tai! time-monotonic -> time-tai +-
        Convert monotonic time to TAI time. The time structure may be reused. +-
        time-monotonic->time-utc time-monotonic -> time-utc +-
        Convert monotonic time to UTC time. +-
        time-monotonic->time-utc! time-monotonic -> time-utc +-
        Convert monotonic time to UTC time. The time structure may be reused. +-
        time-tai->date time-tai [tz-offset] -> date +-
        Convert TAI time to date, using time zone offset, which defaults to the local time zone. +-
        time-tai->julian-day time-tai -> jd +-
        Convert TAI time to Julian Day. +-
        time-tai->modified-julian-day time-tai -> mjd +-
        Convert TAI time to Modified Julian Day. +-
        time-tai->time-monotonic time-tai -> time-monotonic +-
        Convert TAI time to monotonic time. +-
        time-tai->time-monotonic! time-tai -> time-monotonic +-
        Convert TAI time to monotonic time. The time structure may be reused. +-
        time-tai->time-utc time-tai -> time-utc +-
        Convert TAI time to monotonic time. +-
        time-tai->time-utc! time-tai -> time-utc +-
        Convert TAI time to monotonic time. The time structure may be reused. +-
        time-utc->date time-utc [tz-offset] -> time-utc +-
        Convert UTC time to date, using time zone offset, which defaults to the local time zone. +-
        time-utc->julian-day time-utc -> jd +-
        Convert UTC time to Julian Day +-
        time-utc->modified-julian-day time-utc -> mjd +-
        Convert UTC time to Modified Julian Day. +-
        time-utc->time-monotonic time-utc -> time-monotonic +-
        Convert UTC time to monotonic time. +-
        time-utc->time-monotonic! time-utc -> time-monotonic +-
        Convert UTC time to monotonic time. The time structure may be reused. +-
        time-utc->time-tai time-utc -> time-tai +-
        Convert UTC time to TAI time. +-
        time-utc->time-tai! time-utc -> time-tai +-
        Convert UTC time to TAI time. The time structure may be reused. +-
        +- +-

        Date to String/String to Date Converters

        ++
        ++
        date->julian-day date -> jd ++
        Convert date to Julian Day. ++
        date->modified-julian-day date -> mjd ++
        Convert date to Modified Julian Day. ++
        date->time-monotonic date -> time-monotonic ++
        Convert date to monotonic time. ++
        date->time-tai date -> time-tai ++
        Convert date to TAI time. ++
        date->time-utc date -> time-utc ++
        Convert date to UTC time. ++
        julian-day->date jd [tz-offset] -> date ++
        Convert Julian Day to date, , using time zone offset, which defaults to the local time zone. ++
        julian-day->time-monotonic jd -> time-monotonic ++
        Convert Julian Day to monotonic time. ++
        julian-day->time-tai jd -> time-tai ++
        Convert Julian Day to TAI time. ++
        julian-day->time-utc jd -> time-utc ++
        Convert Julian Day to UTC time. ++
        modified-julian-day->date mjd [tz-offset] -> date ++
        Convert Modified Julian Day to date, using time zone offset, which defaults to the local time zone. ++
        modified-julian-day->time-monotonic mjd -> time-monotonic ++
        Convert Modified Julian Day to monotonic time. ++
        modified-julian-day->time-tai mjd -> time-tai ++
        Convert Modified Julian Day to TAI time. ++
        modified-julian-day->time-utc mjd -> time-utc ++
        Convert Modified Julian Day to UTC time. ++
        time-monotonic->date time-monotonic [tz-offset] -> date ++
        Convert monotonic time to date, using time zone offset, which defaults to the local time zone. ++
        time-monotonic->julian-day time-monotonic -> jd ++
        Convert monotonic time to Julian Day. ++
        time-monotonic->modified-julian-day time-monotonic -> mjd ++
        Convert monotonic time to Modified Julian Day. ++
        time-monotonic->time-tai time-monotonic -> time-tai ++
        Convert monotonic time to TAI time. ++
        time-monotonic->time-tai! time-monotonic -> time-tai ++
        Convert monotonic time to TAI time. The time structure may be reused. ++
        time-monotonic->time-utc time-monotonic -> time-utc ++
        Convert monotonic time to UTC time. ++
        time-monotonic->time-utc! time-monotonic -> time-utc ++
        Convert monotonic time to UTC time. The time structure may be reused. ++
        time-tai->date time-tai [tz-offset] -> date ++
        Convert TAI time to date, using time zone offset, which defaults to the local time zone. ++
        time-tai->julian-day time-tai -> jd ++
        Convert TAI time to Julian Day. ++
        time-tai->modified-julian-day time-tai -> mjd ++
        Convert TAI time to Modified Julian Day. ++
        time-tai->time-monotonic time-tai -> time-monotonic ++
        Convert TAI time to monotonic time. ++
        time-tai->time-monotonic! time-tai -> time-monotonic ++
        Convert TAI time to monotonic time. The time structure may be reused. ++
        time-tai->time-utc time-tai -> time-utc ++
        Convert TAI time to monotonic time. ++
        time-tai->time-utc! time-tai -> time-utc ++
        Convert TAI time to monotonic time. The time structure may be reused. ++
        time-utc->date time-utc [tz-offset] -> time-utc ++
        Convert UTC time to date, using time zone offset, which defaults to the local time zone. ++
        time-utc->julian-day time-utc -> jd ++
        Convert UTC time to Julian Day ++
        time-utc->modified-julian-day time-utc -> mjd ++
        Convert UTC time to Modified Julian Day. ++
        time-utc->time-monotonic time-utc -> time-monotonic ++
        Convert UTC time to monotonic time. ++
        time-utc->time-monotonic! time-utc -> time-monotonic ++
        Convert UTC time to monotonic time. The time structure may be reused. ++
        time-utc->time-tai time-utc -> time-tai ++
        Convert UTC time to TAI time. ++
        time-utc->time-tai! time-utc -> time-tai ++
        Convert UTC time to TAI time. The time structure may be reused. ++
        ++ ++

        Date to String/String to Date Converters

        + + These procedures provide conversion to and from strings. They are required. The specification below describes a 'locale;' the + specification of locales is beyond this SRFI. + +-
        +-
        date->string date [format-string] -> string +-
        Converts a date to a string, using the format string. The format string is copied as is; except +-escape characters (indicated by the tilde) are replaced with specific conversions. Table 1 lists the required conversion specifiers; +-implementations are free to extend this list. +-
        string->date input-string template-string -> date +-
        Converts an input string to a date, using the template string. The input string must match the template +-sting as is; except escape characters (indicate by the tilde) indicate special converters which (1) move to the next character in the input string fulfilling a criterion; (2) read a value, and (3) act on this value in some way. Table 2 lists the required +-converters; implementations are free to extend this list. +-
        +- +-

        PLT-specific extensions

        +- +-

        The ~? wildcard is specific to the PLT implementation of string->date: it parses 1 and 2 digit years like ~y and 3 and 4 digit years like ~Y.

        +- +-
        0009 HORIZONTAL TABULATION \t control-I
        0020 SPACE Zs
        00A0 NO-BREAK SPACE Zs
        +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-

        ChConversion

        ~~a literal ~
        ~alocale's abbreviated weekday name (Sun...Sat)
        ~Alocale's full weekday name (Sunday...Saturday)
        ~blocale's abbreviate month name (Jan...Dec)
        ~Blocale's full month day (January...December)
        ~clocale's date and time (e.g., "Fri Jul 14 20:28:42-0400 2000")
        ~dday of month, zero padded (01...31)
        ~Ddate (mm/dd/yy)
        ~eday of month, blank padded ( 1...31)
        ~fseconds+fractional seconds, using locale's decimal separator (e.g. 5.2).
        ~hsame as ~b
        ~Hhour, zero padded, 24-hour clock (00...23)
        ~Ihour, zero padded, 12-hour clock (01...12)
        ~jday of year, zero padded
        ~khour, blank padded, 24-hour clock (00...23)
        ~lhour, blank padded, 12-hour clock (01...12)
        ~mmonth, zero padded (01...12)
        ~Mminute, zero padded (00...59)
        ~nnew line
        ~Nnanosecond, zero padded
        ~plocale's AM or PM
        ~rtime, 12 hour clock, same as "~I:~M:~S ~p"
        ~snumber of full seconds since "the epoch" (in UTC)
        ~Ssecond, zero padded (00...60)
        ~thorizontal tab
        ~Ttime, 24 hour clock, same as "~H:~M:~S"
        ~Uweek number of year with Sunday as first day of week (00...53)
        ~Vweek number of year with Monday as first day of week (01...52)
        ~w day of week (0...6)
        ~Wweek number of year with Monday as first day of week (01...52)
        ~xweek number of year with Monday as first day of week (00...53)
        ~Xlocale's date representation, for example: "07/31/00"
        ~ylast two digits of year (00...99)
        ~Yyear
        ~ztime zone in RFC-822 style
        ~Zsymbol time zone (not-implemented)
        ~1ISO-8601 year-month-day format
        ~2ISO-8601 hour-minute-second-timezone format
        ~3ISO-8601 hour-minute-second format
        ~4ISO-8601 year-month-day-hour-minute-second-timezone format
        ~5ISO-8601 year-month-day-hour-minute-second format

        Table 1: DATE->STRING conversion specifiers

        +- +-

        +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-

        ChSkip toReadSet

        ~~anyread literal ~nothing
        ~achar-alphabetic?abbreviated weekday in localenothing
        ~Achar-alphabetic?full weekday in localenothing
        ~bchar-alphabetic?abbreviated month name in localenothing
        ~Bchar-alphabetic?full month name in localenothing
        ~dchar-numeric?day of monthdate-day
        ~eanyday of month, blank paddeddate-day
        ~hchar-alphabetic?same as ~bnothing
        ~Hchar-numeric?hourdate-hour
        ~kanyhour, blank paddeddate-hour
        ~mchar-numeric?monthdate-month
        ~Mchar-numeric?minutedate-minute
        ~Schar-numeric?seconddate-second
        ~yany2-digit yeardate-year within 50 years
        ~Ychar-numeric?yeardate-year
        ~zanytime zonedate-zone-offset
        ~?char-numeric?2-digit or 4-digit year (PLT-specific extension)date-year

        Table 2: STRING->DATE conversion specifiers

        +- +-

        Implementation

        ++
        ++
        date->string date [format-string] -> string ++
        ++
        ++

        ++ Converts a date to a string, using the format string. The format string ++ is copied as is; except escape characters (indicated by the tilde) are ++ replaced with specific conversions. Table 1 lists the required ++ conversion specifiers; implementations are free to extend this list. ++

        ++
        ++
        string->date input-string template-string -> date ++
        ++
        ++

        ++ Converts an input string to a date, using the template string. The input ++ string must match the template sting as is; except escape characters ++ (indicate by the tilde) indicate special converters which (1) move to ++ the next character in the input string fulfilling a criterion; (2) read ++ a value, and (3) act on this value in some way. Table 2 lists the ++ required converters; implementations are free to extend this list. ++

        ++

        PLT-specific extension: The ~? wildcard is ++specific to the PLT implementation of string->date: ++it parses 1 and 2 digit years like ~y and 3 and 4 ++digit years like ~Y.

        ++
        ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++

        ChConversion

        ~~a literal ~
        ~alocale's abbreviated weekday name (Sun...Sat)
        ~Alocale's full weekday name (Sunday...Saturday)
        ~blocale's abbreviate month name (Jan...Dec)
        ~Blocale's full month day (January...December)
        ~clocale's date and time (e.g., "Fri Jul 14 20:28:42-0400 2000")
        ~dday of month, zero padded (01...31)
        ~Ddate (mm/dd/yy)
        ~eday of month, blank padded ( 1...31)
        ~fseconds+fractional seconds, using locale's decimal separator (e.g. 5.2).
        ~hsame as ~b
        ~Hhour, zero padded, 24-hour clock (00...23)
        ~Ihour, zero padded, 12-hour clock (01...12)
        ~jday of year, zero padded
        ~khour, blank padded, 24-hour clock ( 0...23)
        ~lhour, blank padded, 12-hour clock ( 1...12)
        ~mmonth, zero padded (01...12)
        ~Mminute, zero padded (00...59)
        ~nnew line
        ~Nnanosecond, zero padded
        ~plocale's AM or PM
        ~rtime, 12 hour clock, same as "~I:~M:~S ~p"
        ~snumber of full seconds since "the epoch" (in UTC)
        ~Ssecond, zero padded (00...60)
        ~thorizontal tab
        ~Ttime, 24 hour clock, same as "~H:~M:~S"
        ~Uweek number of year with Sunday as first day of week (00...53)
        ~VISO 8601 week number of the year with Monday as first day of week (01..53)[1]
        ~w day of week (0...6)
        ~Wweek number of year with Monday as first day of week (01...52)
        ~xlocale's date representation[1]
        ~Xlocale's time representation[1]
        ~ylast two digits of year (00...99)
        ~Yyear
        ~ztime zone in RFC-822 style
        ~Zsymbol time zone (not-implemented)
        ~1ISO-8601 year-month-day format
        ~2ISO-8601 hour-minute-second-timezone format
        ~3ISO-8601 hour-minute-second format
        ~4ISO-8601 year-month-day-hour-minute-second-timezone format
        ~5ISO-8601 year-month-day-hour-minute-second format

        Table 1: DATE->STRING conversion specifiers

        ++ ++

        [1] These lines were changed as part of a fix to errata on 2009-06-11.

        ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++

        ChSkip toReadSet

        ~~anyread literal ~nothing
        ~achar-alphabetic?abbreviated weekday in localenothing
        ~Achar-alphabetic?full weekday in localenothing
        ~bchar-alphabetic?abbreviated month name in localenothing
        ~Bchar-alphabetic?full month name in localenothing
        ~dchar-numeric?day of monthdate-day
        ~eanyday of month, blank paddeddate-day
        ~hchar-alphabetic?same as ~bnothing
        ~Hchar-numeric?hourdate-hour
        ~kanyhour, blank paddeddate-hour
        ~mchar-numeric?monthdate-month
        ~Mchar-numeric?minutedate-minute
        ~Schar-numeric?seconddate-second
        ~yany2-digit yeardate-year within 50 years
        ~Ychar-numeric?yeardate-year
        ~zanytime zonedate-zone-offset
        ~?char-numeric?2-digit or 4-digit year (PLT-specific extension)date-year

        Table 2: STRING->DATE conversion specifiers

        ++ ++

        Implementation

        + + This SRFI cannot be written in completely standard Scheme. In + particular, there must be some system-independent method of finding +@@ -553,34 +600,31 @@ the values for CURRENT-TIME. The GNU C function, + +

        The difference between TAI and UTC is not determinate, and + implementations must provide some method for getting TAI. A procedure +-is provided in the accompany implmentation for reading the leap second ++is provided in the accompany implementation for reading the leap second + table provided by the Time Service of the US Naval Observatory +-(available at ftp://maia.usno.navy.mil/ser7/tai-utc.dat). +- +-

        The accompanying implementation assumes SRFI 6 Basic String Ports. +-The accompanying implementation also assumes an error +-procedure. The accompanying implementation also assumes SRFI 8 RECEIVE: Binding to ++(available at ftp://maia.usno.navy.mil/ser7/tai-utc.dat). ++ ++

        The accompanying implementation assumes SRFI 6 Basic String Ports. ++The accompanying implementation also assumes an error ++procedure. The accompanying implementation also assumes SRFI 8 RECEIVE: Binding to + multiple values. which is easy to implement with the following + syntax: +- +- +-

        ++

        ++
        + (define-syntax receive
        +   (syntax-rules ()
        +     ((receive formals expression body ...)
        +      (call-with-values (lambda () expression)
        +                        (lambda formals body ...)))))
        +-
        +-
        +- +-

        Note that it contains TAI-UTC.DAT reader. ++

        + +-

        The accompanying ++

        ++Note that it contains TAI-UTC.DAT reader. ++

        ++

        ++The accompanying + implementation is written in MzScheme. MzScheme provides the procedure +-current-seconds, which returns the number of seconds (UTC) ++current-seconds, which returns the number of seconds (UTC) + since 1970-01-01T00:00:00Z+00:00, and + current-milliseconds, which is a monotonic time + clock. Combining these provides an implementation of +@@ -590,46 +634,51 @@ UTC are resolved through a leap second table. According to the + International Earth Rotation Service, there will be no leap second in + December, 2000. Thus, the leap second table is guaranteed to be + correct through June, 2000. +- +-

        Also, MzScheme (as of version 102, I believe) provides a method for ++

        ++

        ++Also, MzScheme (as of version 102, I believe) provides a method for + returning the current time zone offset, via its SECONDS->DATE and +-CURRENT-DATE procedures. +- +-

        MzScheme's DEFINE-STRUCT was used to define the time +-and date objects. SRFI 9, Defining Record ++CURRENT-DATE procedures. ++

        ++

        ++MzScheme's DEFINE-STRUCT was used to define the time ++and date objects. SRFI 9, Defining Record + Types, could be used instead. +- +-

        Procedures meant to be used internally have names beginning with ++

        ++

        ++Procedures meant to be used internally have names beginning with + TM:. Locale-related constants and procedures have + locale in their name; if a 'locale' SRFI is ever written, + it might be good to use that code instead. ++

        ++

        ++From this, the rest of the implementation was built. ++

        ++

        ++There is also a test suite. ++

        + +-

        From this, the rest of the implementation was built. +- +-

        There is also a test suite. +- +-

        Acknowledgements

        +- +-Claus Tøndering's Frequently Asked Questions about calendars was a very ++

        Acknowledgements

        ++

        ++Claus ++Tøndering's Frequently Asked Questions about calendars was a very + useful resource. The implementation of Julian Day, Modified Julian +-Day, and Year Day comes from his FAQ. Markus Kuhn has a useful +-description of the ISO Standard 8601 for +-Date/Time notation; The W3 Consortium also has a useful Note. +- +-

        Mike Sperber, Marc Feely, Dave Mason, and "Prfnoff" all made useful ++Day, and Year Day comes from his FAQ. Markus Kuhn has a useful ++description of the ISO Standard 8601 for ++Date/Time notation; The W3 Consortium also has a useful Note. ++

        ++

        ++Mike Sperber, Marc Feeley, Dave Mason, and "Prfnoff" all made useful + comments on previous versions of this draft. Thanks to Shriram + Krishnamurthi for his editing help. +- +-

        The DATE->STRING procedure uses a format string, based on ++

        ++

        ++The DATE->STRING procedure uses a format string, based on + GNU C's date procedure, as well as scsh's + FORMAT-DATE procedure. ++

        + +- +-

        Copyright

        ++

        Copyright

        + +

        Copyright (C) Neodesic Corporation (2000). All Rights Reserved.

        + +@@ -656,11 +705,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        ++
        + +-
        Editor: Shriram +-Krishnamurthi
        ++
        Editor: Shriram ++Krishnamurthi
        + Last +-modified by the author:
        (display (date->string (current-date 0) +-"~4")): 2004-03-15T02:21:15Z +- ++modified by the author:
        (display (date->string (current-date 0) ++"~4")): 2017-05-05T21:42:17Z ++ +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-2.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-2.html +index 18b6ba7..3c51824 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-2.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-2.html +@@ -1,38 +1,70 @@ +- +- +- SRFI 2: AND-LET*: an AND with local bindings, a guarded LET* special form ++ ++ ++ ++ ++ ++ SRFI 2: AND-LET*: an AND with local bindings, a guarded LET* special form ++ ++ ++ ++ + + +-

        Title

        +- +-SRFI-2: AND-LET*: an AND with local bindings, a guarded LET* special form +- +-

        Author

        +- +-Oleg Kiselyov +- +-

        Status

        +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion on this SRFI via the archive of the mailing list. +-

          +-
        • Received: 1998/12/28 +-
        • Revised: 1999/02/09 +-
        • Draft: 1998/12/28-1999/02/28 +-
        • Final: 1999/03/01 +-
        +- +-

        Abstract

        +- +-

        Like an ordinary AND, an AND-LET* special form evaluates its arguments -- ++

        SRFI 2: AND-LET*: an AND with local bindings, a guarded LET* special form

        ++ ++

        by Oleg Kiselyov

        ++

        This copy of the SRFI 2 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-2/srfi-2.html.

        ++ ++

        Status

        ++ ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-2@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Received: 1998-12-28 ++
        • Revised: 1999-02-09 ++
        • Draft: 1998-12-28--1999-02-28 ++
        • Final: 1999-03-01 ++
        • Revised to fix errata: ++
            ++
          • 2020-06-08 (Fixed: Variables bound by AND-LET* needn't ++ be unique. This requirement was based on the mistaken ++ impression that LET* imposed that requirement, which it ++ doesn't. Also, updated link to sample implementation to ++ point to a more recent version by Oleg.)
          • ++
          • 2020-10-26 (Clarified what is meant by BODY in (and-let* ++ (CLAWS) BODY).)
        • ++
        ++ ++

        Abstract

        ++ ++

        Like an ordinary AND, an AND-LET* special form evaluates its arguments -- + expressions -- one after another in order, till the first one that + yields #f. Unlike AND, however, a non-#f result of one expression can + be bound to a fresh variable and used in the subsequent expressions. + AND-LET* is a cross-breed between LET* and AND. ++

        + +-

        Rationale

        ++

        Rationale

        + +-

        In case of an ordinary AND formed of proper boolean expressions:
        +-(AND E1 E2 ...)
        ++

        In case of an ordinary AND formed of proper boolean expressions:
        ++(AND E1 E2 ...)
        + expression E2, if it gets to be evaluated, knows that E1 has returned + non-#f. Moreover, E2 knows exactly what the result of E1 was -- #t -- + which E2 can use to its advantage. If E1 however is an extended +@@ -44,8 +76,8 @@ not an #f, and throws it away. If E2 needs it, it has to compute that + value anew. This proposed AND-LET* special form lets constituent + expressions get hold of the results of already evaluated expressions, + without re-doing their work. +- +-

        AND-LET* can be thought of as a combination of LET* and AND, or a ++

        ++

        AND-LET* can be thought of as a combination of LET* and AND, or a + generalization of COND's send operator =>. An AND-LET* form can also be + considered a sequence of guarded expressions. In a regular program, + forms may produce results, bind them to variables and let other forms +@@ -53,21 +85,23 @@ use these results. AND-LET* differs in that it checks to make sure that + every produced result "makes sense" (that is, not an #f). The first + "failure" triggers the guard and aborts the rest of the sequence + (which presumably would not make any sense to execute anyway). +- ++

        ++

        + Examples: +-

        ++

        ++
        + (AND-LET* ((my-list (compute-list)) ((not (null? my-list))))
        +-          (do-something my-list))
        ++    (do-something my-list))
        + 
        + (define (look-up key alist)
        +   (and-let* ((x (assq key alist))) (cdr x)))
        + 
        + (or
        +-  (and-let* ((c (read-char))
        +-    ((not (eof-object? c))))
        +-    (string-set! some-str i c)  
        +-    (set! i (+ 1 i)))
        +-  (begin (do-process-eof)))
        ++ (and-let* ((c (read-char))
        ++            ((not (eof-object? c))))
        ++     (string-set! some-str i c)
        ++   (set! i (+ 1 i)))
        ++ (begin (do-process-eof)))
        + 
        + 			; A more realistic example
        +                         ; Parse the 'timestamp' ::= 'token1' 'token2'
        +@@ -88,47 +122,48 @@ Examples:
        +                    (string-ref token2 2) (string-ref token2 3))))
        +              ((positive? timestamp)))
        +            timestamp))
        +-
        +- +-

        ++

        ++

        + AND-LET* is also similar to an "anaphoric AND" LISP macro [Rob Warnock, + comp.lang.scheme, 26 Feb 1998 09:06:43 GMT, Message-ID: + 6d3bb3$3804h@fido.asd.sgi.com]. AND-LET* allows however more than one + intermediate result, each of which continues to be bound through the + rest of the form. ++

        + ++

        Specification

        + +-

        Specification

        +- +-

        Syntax and Informal Semantics

        ++

        Syntax and Informal Semantics

        + +-
        ++
        + AND-LET* (CLAWS) BODY
        + 
        + CLAWS ::= '() | (cons CLAW CLAWS)
        + CLAW  ::=  (VARIABLE EXPRESSION) | (EXPRESSION) |
        +            BOUND-VARIABLE
        +-
        ++
        + +-
          +-
        • The CLAWS are evaluated in the strict left-to-right order +-
        • For each CLAW, the EXPRESSION part is evaluated first (or BOUND-VARIABLE is looked up) +-
        • If the result is #f, AND-LET* immediately returns #f +-
        • Otherwise, if the CLAW is of the form (VARIABLE EXPRESSION) ++
            ++
          • The CLAWS are evaluated in the strict left-to-right order ++
          • For each CLAW, the EXPRESSION part is evaluated first (or BOUND-VARIABLE is looked up) ++
          • If the result is #f, AND-LET* immediately returns #f ++
          • Otherwise, if the CLAW is of the form (VARIABLE EXPRESSION) + the EXPRESSION's value is bound to a freshly made VARIABLE +-
          • The VARIABLE is available for the rest of the CLAWS , and the BODY +-
          • As usual, all VARIABLEs must be unique (like in let*) +-
          ++
        • The VARIABLE is available for the rest of the CLAWS , and the BODY ++
        • As usual, all VARIABLEs must be unique (like in let*) ++
        • BODY is a body as in a LET* form.
        • ++ ++
        + +-

        Formal (Denotational) Semantics

        ++

        Formal (Denotational) Semantics

        + +-
        ++
        + eval[ (AND-LET* (CLAW1 ...) BODY), env] =
        +    eval_claw[ CLAW1, env ] andalso
        +    eval[ (AND-LET* ( ...) BODY), ext_claw_env[CLAW1, env]]
        + 
        + eval[ (AND-LET* (CLAW) ), env] = eval_claw[ CLAW, env ]
        +-eval[ (AND-LET* () FORM1 ...), env] = eval[ (BEGIN FORM1 ...), env ]
        ++eval[ (AND-LET* () FORM1 ...), env] = eval[ (LET* () FORM1 ...), env ]
        + eval[ (AND-LET* () ), env] = #t
        + 
        + eval_claw[ BOUND-VARIABLE, env ] =
        +@@ -144,21 +179,15 @@ ext_claw_env[ (EXPRESSION), env ] =
        + ext_claw_env[ (VARIABLE EXPRESSION), env ] =
        +    extend-env[ env-after-eval[ EXPRESSION, env ],
        +               VARIABLE boundto eval[ EXPRESSION, env ]]
        +-
        +- +-

        Implementation

        ++
        ++

        Implementation

        + +-

        The full implementation plus the validation code are available here (which is a copy of +- +-http://pobox.com/~oleg/ftp/Scheme/vland.scm). +- +-

        This is an implementation of AND-LET* as a (Gambit) low-level macro that +-re-writes AND-LET* as a "tree" of AND and LET forms. A validation code is +-also presented, which verifies not only that everything works as +-expected, but also that AND-LET* finds syntax errors where expected. +- +-

        Copyright

        ++

        A full sample implementation is available at http://okmij.org/ftp/Scheme/lib/myenv-chez.scm. The test suite is at http://okmij.org/ftp/Scheme/tests/vland.scm. ++

        ++

        Copyright

        ++

        + Copyright (C) Oleg Kiselyov (1998). All Rights Reserved. ++

        +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -182,14 +211,13 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        +-
        Editor: Dave Mason
        ++
        ++
        Editor: Dave Mason
        + +-

        ++

        + +-Last modified: Wed Feb 6 17:21:57 MET 2002 ++Last modified: Sun Jan 28 13:40:28 MET 2007 + +- +- +- ++

        ++ + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-23.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-23.html +index 8ac31ca..ae2545c 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-23.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-23.html +@@ -1,44 +1,57 @@ +- +- ++ ++ + ++ ++ + SRFI 23: Error reporting mechanism ++ ++ ++ + + + + +-

        Title

        ++

        SRFI 23: Error reporting mechanism

        + +-SRFI 23: Error reporting mechanism ++

        by Stephan Houben

        ++

        This copy of the SRFI 23 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-23/srfi-23.html.

        + +-

        Author

        ++

        Status

        + +-Stephan Houben ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-23 @nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Draft: 2001-03-09--2001-06-09
        • ++
        • Revised: 2001-03-22 ++
        • Revised: 2001-04-26 ++
        + +-

        Status

        + +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +-You can access +-the discussion via +- +-the archive of the mailing list. +-

        +-

          +-
        • Draft: 2001/03/09-2001/06/09
        • +-
        • Revised: 2001/03/22 +-
        • Revised: 2001/04/26 +-
        +-

        +- +-

        Abstract

        ++

        Abstract

        + + A mechanism is proposed to allow Scheme code to report errors and abort + execution. + The proposed mechanism is already implemented in several Scheme systems + and can be implemented, albeit imperfectly, in any R5RS conforming Scheme. + +-

        Rationale

        ++

        Rationale

        + +

        + R5RS Scheme requires certain operations to signal an error when they fail. +@@ -46,14 +59,14 @@ R5RS Scheme requires certain operations to signal an error when they fail. + the error. + Moreover, R5RS encourages, but not requires, + implementations to signal an error in many more circumstances. +- ++

        +

        + However, there is no direct way for the Scheme application programmer to report +-an error that occurred in his or her own application. ++an error that occured in his or her own application. + This means that Scheme procedures created by applications or libraries are + in this respect not on equal footing with procedures provided by the + Scheme system. +- ++

        +

        + Many Scheme systems already provide a mechanism that allows application code + to report an error. At least the following implementations support +@@ -63,80 +76,96 @@ Of these implementations, the following have an error mechanism compatible + with this SRFI: Guile, MIT Scheme, PLT Scheme, RScheme, Scsh. + The implementation in SLIB has a different name than the + one proposed in this SRFI. +- ++

        +

        + To summarise, many implementations already have the error reporting + mechanism described in this SRFI and others are easily made compatible + with this SRFI. This shows that the proposed mechanism is considered useful + and that it is easy to implement in most major implementations. ++

        + +-

        Specification

        ++

        Specification

        + +

        + The following procedure should be provided: +-

        ++

        ++

        + (error <reason> [<arg1> [<arg2> ...]]) ++

        +

        + The argument <reason> should be a string. + The procedure error will signal an error, + as described in R5RS, and it will report the message <reason> +-and the objects <arg1>, <arg2>, .... ++and the objects <arg1>, <arg2>, .... + What exactly constitutes "signalling" and "reporting" is not prescribed, because of the large variation in Scheme systems. So it is left to the implementor + to do something reasonable. To that end, a few examples of possible behaviour + are given. ++

        +
          +
        1. + Display <reason> and <arg1>... on the screen and terminate + the Scheme program. (This might be suitable for a Scheme system + implemented as a batch compiler.) +-
        2. ++
        3. ++
        4. + Display <reason> and <arg1>... on the screen and + go back to the read-evaluate-print loop. (This might be suitable for + an interactive implementation). ++
        5. +
        6. + In the case of a multi-threaded system: terminate the current + thread, but do not terminate the other threads. Possibly make the + arguments to error available to other threads in some + way. See the thread-join! mechanism in SRFI-18 on + how this could be done. ++
        7. +
        8. + Package <reason> and <arg1>... up into an error object + and pass this error object to an exception handler. The default + exception handler then might do something as described in points 1 to 3. ++
        9. +
        10. + In the case of a Scheme system that runs completely unattended + and that has no way to notify a human, the only reasonable + course of action might be to do nothing at all. However, this should + be considered a last resort. Clearly, if all implementors would choose + this strategy, this SRFI would not be very useful. +-
        ++
      • ++ ++

        + An implementation might report more information than just + <reason> and <arg1>... . For instance, it might report the procedure name in which + the error occurred or even print a stack trace. + However, this will require additional support in the Scheme implementation. ++

        + ++

        Why error is a procedure

        + +-

        Why error is a procedure

        +- ++

        + It is conceivable to allow error to be a special form, + such as a macro, rather than a procedure. This might make providing + information such as the source code location easier. This possibility + has been considered, but rejected, for two reasons. ++

        +
          +
        1. + Since error accepts a variable number of arguments, + it could occasionally be useful to use apply to call + error. However, this is not possible if error + was allowed to be a special form. ++
        2. +
        3. + Since error is currently a procedure in all Scheme + implementations mentioned above, it doesn't seem all that + worthwhile to allow it to be a special form. ++
        4. +
        + +-

        Implementation

        ++

        Implementation

        + ++

        + An implementation that works in almost any R5RS Scheme is the following: ++

        +
        +   (define (error reason . args)
        +       (display "Error: ")
        +@@ -148,36 +177,42 @@ An implementation that works in almost any R5RS Scheme is the following:
        +       (newline)
        +       (scheme-report-environment -1))  ;; we hope that this will signal an error
        + 
        ++

        + This implementation has a flaw, + namely, in many implementations this + will actually print 2 messages. ++

        +
          +
        1. The message message, followed by objs, and +-
        2. A message about scheme-report-environment getting an invalid argument. +-
        ++ ++
      • A message about scheme-report-environment getting an invalid argument. ++
      • ++ ++

        + This might be confusing to the user. +- ++

        +

        + The SLIB procedure slib:error works like the error + procedure described in this document. + Thus, when SLIB is loaded, error can be defined as: ++

        +
        +   (define error slib:error)
        + 
        +- +

        +-If SRFI 18 is supported, it is allowed ++If SRFI 18 is supported, it is allowed + (but not required) to implement error in + terms of the exception mechanism of SRFI 18. ++

        +
        +   (define (error reason . args)
        +     (raise (make-error-exception reason args)))
        + 
        ++

        + Here, make-error-exception is implementation dependent. +- +-

        Copyright

        ++

        ++

        Copyright

        +

        Copyright (C) Stephan Houben (2001). All Rights Reserved.

        +- +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -200,13 +235,11 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        +- +-
        +-
        Editor: Mike Sperber
        ++
        ++
        Editor: Mike Sperber
        + + +-Last modified: Mon Feb 4 14:46:29 MET 2002 ++Last modified: Sun Jan 28 13:40:28 MET 2007 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-25.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-25.html +index 4d81d03..000adb1 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-25.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-25.html +@@ -1,36 +1,50 @@ +- +- ++ ++ + ++ ++ + SRFI 25: Multi-dimensional Array Primitives ++ ++ ++ + + + + +-

        Title

        ++

        SRFI 25: Multi-dimensional Array Primitives

        + +-SRFI 25: Multi-dimensional Array Primitives ++

        by Jussi Piitulainen

        ++

        This copy of the SRFI 25 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-25/srfi-25.html.

        + +-

        Author

        ++

        Status

        + +-Jussi Piitulainen ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-25 @nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Draft: 2001-11-12--2002-01-11
        • ++
        • Revised: 2002-02-03
        • ++
        • Final: 2002-05-21
        • ++
        + +-

        Status

        + +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. You can access +-the discussion via +- +-the archive of the mailing list. +-

        +-

          +-
        • Draft: 2001/11/12-2002/01/11
        • +-
        • Revised: 2002/02/03
        • +-
        • Final: 2002/05/21
        • +-
        +-

        +- +-

        Abstract

        ++

        Abstract

        + +

        + A core set of procedures for creating and manipulating heterogeneous +@@ -45,7 +59,7 @@ The specification is based on an original contribution by Alan Bawden + in 1993. +

        + +-

        Rationale

        ++

        Rationale

        + +

        + The proposed arrays encourage a natural declarative programming +@@ -108,7 +122,7 @@ It is not required that vectors not be arrays. It is not required that + they be, either. +

        + +-

        Specification

        ++

        Specification

        + +

        + Arrays are heterogeneous data structures whose elements are indexed by +@@ -141,8 +155,8 @@ alternately the lower and upper bounds for the dimensions of an array. + The following ten procedures should be implemented. +

        + +-

        +-(array? obj)
        ++

        ++(array? obj)
        + + Returns #t if obj is an array, otherwise + returns #f. +@@ -150,14 +164,14 @@ returns #f. + +

        + Note: there is no reasonable way to implement this procedure +-accurately in R5RS; SRFI ++accurately in R5RS; SRFI + 9 (Defining Record Types) specifies a way, and many Scheme + implementations provide something similar. +

        + +-

        +-(make-array shape)
        +-(make-array shape obj)
        ++

        ++(make-array shape)
        ++(make-array shape obj)
        + + Returns a newly allocated array whose shape is given by + shape. If obj is provided, then each element is +@@ -166,8 +180,8 @@ unspecified. The array does not retain a dependence to + shape. +

        + +-

        +-(shape bound ...)
        ++

        ++(shape bound ...)
        + + Returns a shape. The sequence bound ... must consist of an + even number of exact integers that are pairwise not decreasing. Each +@@ -190,42 +204,42 @@ corresponding upper bound, where k satisfies + (< k d). +

        + +-

        +-(array shape obj ...)
        ++

        ++(array shape obj ...)
        + + Returns a new array whose shape is given by shape and the + initial contents of the elements are obj ... in row major + order. The array does not retain a dependence to shape. +

        + +-

        +-(array-rank array)
        ++

        ++(array-rank array)
        + + Returns the number of dimensions of array. ++

        +
        +     (array-rank
        +        (make-array (shape 1 2 3 4)))
        + 
        +- +

        + Returns 2. +

        + +-

        +-(array-start array k)
        ++

        ++(array-start array k)
        + + Returns the lower bound for the index along dimension k. +

        + +-

        +-(array-end array k)
        ++

        ++(array-end array k)
        + + Returns the upper bound for the index along dimension k. +

        + + + +-

        +-(array-ref array k ...)
        +-(array-ref array index)
        ++

        ++(array-ref array k ...)
        ++(array-ref array index)
        + + Returns the contents of the element of array at index + k .... The sequence k ... must be a valid index +@@ -280,30 +294,29 @@ Returns cuatro. + Returns (3 1 4). +

        + +-

        +-(array-set! array k ... obj)
        +-(array-set! array index obj)
        ++

        ++(array-set! array k ... obj)
        ++(array-set! array index obj)
        + + Stores obj in the element of array at index + k .... Returns an unspecified value. The sequence k + ... must be a valid index to array. In the second + form, index must be either a vector or a 0-based + 1-dimensional array containing k .... +- ++

        +
        +     (let ((a (make-array
        +                 (shape 4 5 4 5 4 5))))
        +        (array-set! a 4 4 4 'huuhkaja)
        +        (array-ref a 4 4 4))
        + 
        +- +

        + Returns huuhkaja. +

        + +-

        ++

        + (share-array array shape proc) +-
        ++
        + + Returns a new array of shape shape that shares elements of + array through proc. The procedure +@@ -351,7 +364,7 @@ This document does not specify when arrays are equal?. + (Indeed, R5RS equal? will do the wrong thing.) +

        + +-

        Examples

        ++

        Examples

        + +

        + The reference implementation comes with a number of files that +@@ -361,36 +374,33 @@ in testing an implementation; that is their origin). + +

          + +-
        1. A library arlib.scm that contains, among ++
        2. A library arlib.scm that contains, among + several other things, tabulate-array for a more + useful initialization of a new array, an + array-equal?, and a transpose that can + permute the dimensions of an array any which way. + +-
        3. A test suite test.scm for array, +- and another test suite list.scm for ++
        4. A test suite test.scm for array, ++ and another test suite list.scm for + arlib. + +-
        5. A rudimentary display procedure (play array) in play.scm, for playing around with the system. ++
        6. A rudimentary display procedure (play array) in play.scm, for playing around with the system. + +-
        ++ + +-

        Implementation

        ++

        Implementation

        + +

        + A portable reference implementation is provided. It uses a minimal +-error reporting mechanism that conforms to SRFI 23 (Error reporting ++error reporting mechanism that conforms to SRFI 23 (Error reporting + mechanism). Type disjointness requires support from the host +-implementation, such as support for SRFI 9 (Defining Record ++implementation, such as support for SRFI 9 (Defining Record + Types). All names not defined in this proposal are in the prefix + "array:", which serves as a module system. +

        + +

        +-You can get source for the reference ++You can get source for the reference + implementation as a single file and stop reading. But there are + variations. This single file represents arrays as procedures (so the + type predicate is very approximate); it represents index mapping as +@@ -410,18 +420,18 @@ consists of the following parts, each in its own file. + type disjointness, or portable as procedures, in a file + as-*.scm, and + +-

      • indexing operations to match the type, in a file ++
      • indexing operations to match the type, in a file + ix-*.scm, and + +-
      • an affine recogniser of one of three types, optimised ++
      • an affine recogniser of one of three types, optimised + up to some number of dimensions, in a file op-*.scm, and + +-
      • the main source file array.scm. ++
      • the main source file array.scm. + +- ++
      • + +

        +-Affine recognisers are made by a program opt.scm ++Affine recognisers are made by a program opt.scm + but one of each type is also available here, optimized for 0, 1, 2 and + 3 dimensions. Choose one type: pick a recogniser with matching index + procedures; load as-, ix- and op- and +@@ -430,36 +440,34 @@ procedures; load as-, ix- and op- and + +

          + +-
        1. In the mbda type representation, index ++
        2. In the mbda type representation, index + mappings are procedures that accept an optional argument. The +- matching access procedures apply the ++ matching access procedures apply the + mapping to the arguments of array-ref and + array-set!. + +-
        3. In the tter type representation, index ++
        4. In the tter type representation, index + mappings are pairs of procedures: one takes exactly the indices, +- the other takes indices and an object. The matching access procedures apply the first ++ the other takes indices and an object. The matching access procedures apply the first + procedure to the argumets of array-ref and the + second procedure to the arguments of array-set!. + +-
        5. In ctor representation, index mappings +- are coefficient vectors. The access ++
        6. In ctor representation, index mappings ++ are coefficient vectors. The access + procedures compute the sum of products of coefficients and + indexes in a loop on the list. + +-
        ++ + +

        +-Record implementations are available for +-generic Scheme (arrays are not disjoint from procedures), for SRFI 9 (Defining Record Types) +-(not tested), and for PLT ++Record implementations are available for ++generic Scheme (arrays are not disjoint from procedures), for SRFI 9 (Defining Record Types) ++(not tested), and for PLT + Scheme (arrays belong to a struct type). +

        + +

        +-With the three files from above, the main source ++With the three files from above, the main source + file should work in any Scheme implementation without need of + modification. +

        +@@ -471,7 +479,7 @@ code. (Sharing uses a check that is exponential in the number of + dimensions. It is disabled above a threshold rank.) +

        + +-

        Acknowledgements

        ++

        Acknowledgements

        + +

        + The original concept comes from a message to the Usenet newsgroup +@@ -490,11 +498,10 @@ wording, hidden shapes, and two kinds of index objects. + +

        + The exact title of the proposal comes from a message titled "a process that might work" by William D. Clinger to the rrrs-authors +-mailing list in 1998. That appears to be a part of the past of the SRFI process. ++mailing list in 1998. That appears to be a part of the past of the SRFI process. +

        + +-

        Copyright

        ++

        Copyright

        +

        Copyright (C) Jussi Piitulainen (2001). All Rights Reserved.

        + +

        +@@ -520,12 +527,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        +-
        Editor: Mike Sperber
        ++
        ++
        Editor: Mike Sperber
        + + +-Last modified: Tue May 28 18:46:09 MST 2002 ++Last modified: Sun Jan 28 13:40:29 MET 2007 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-26.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-26.html +index a6cf487..0d6d83e 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-26.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-26.html +@@ -1,39 +1,54 @@ +- +- ++ ++ + ++ ++ + SRFI 26: Notation for Specializing Parameters without Currying ++ ++ ++ + + + + +-

        Title

        ++

        SRFI 26: Notation for Specializing Parameters without Currying

        + +-SRFI 26: Notation for Specializing Parameters without Currying ++

        by Sebastian Egner

        ++

        This copy of the SRFI 26 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-26/srfi-26.html.

        + +-

        Author

        ++

        Status

        + +-Sebastian Egner ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-26@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Draft: 2002-02-06--2002-04-06
        • ++
        • Revised: 2002-02-15
        • ++
        • Revised: 2002-02-28
        • ++
        • Revised: 2002-06-04
        • ++
        • Revised: 2002-06-06
        • ++
        • Final: 2002-06-14
        • ++
        + +-

        Status

        +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. You can access +-the discussion via +- +-the archive of the mailing list. +- +-
          +-
        • Draft: 2002/02/06-2002/04/06
        • +-
        • Revised: 2002/02/15
        • +-
        • Revised: 2002/02/28
        • +-
        • Revised: 2002/06/04
        • +-
        • Revised: 2002/06/06
        • +-
        • Final: 2002/06/14
        • +-
        +- +-

        Abstract

        ++

        Abstract

        + ++

        + When programming in functional style, + it is frequently necessary to specialize some of the + parameters of a multi-parameter procedure. +@@ -41,40 +56,41 @@ For example, from the binary operation cons + one might want to obtain the unary operation + (lambda (x) (cons 1 x)). + This specialization of parameters is also known as +-"partial application", "operator section" or "projection".

        +- ++"partial application", "operator section" or "projection". ++

        ++

        + The mechanism proposed here allows to write this sort + of specialization in a simple and compact way. +-The mechanism is best explained by a few examples:

        +- +- +- +- +- +- +- +- +- +- +- +- +-
        (cut cons (+ a 1) <>) +-is the same as +-(lambda (x2) (cons (+ a 1) x2)) +-
        (cut list 1 <> 3 <> 5) +-is the same as +-(lambda (x2 x4) (list 1 x2 3 x4 5)) +-
        (cut list) +-is the same as +-(lambda () (list)) +-
        (cut list 1 <> 3 <...>) +-is the same as +-(lambda (x2 . xs) (apply list 1 x2 3 xs)) +-
        (cut <> a b) +-is the same as +-(lambda (f) (f a b)) +-

        +- ++The mechanism is best explained by a few examples: ++

        ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
        (cut cons (+ a 1) <>)is the same as(lambda (x2) (cons (+ a 1) x2))
        (cut list 1 <> 3 <> 5)is the same as(lambda (x2 x4) (list 1 x2 3 x4 5))
        (cut list)is the same as(lambda () (list))
        (cut list 1 <> 3 <...>)is the same as(lambda (x2 . xs) (apply list 1 x2 3 xs))
        (cut <> a b)is the same as(lambda (f) (f a b))
        ++

        + As you see, the macro cut specializes some of the + parameters of its first argument. + The parameters that are to show up as formal +@@ -83,27 +99,29 @@ pronouced as "slot". In addition, the symbol <...>, + pronounced as "rest-slot", matches all residual arguments of a variable + argument procedure. + As you can see from the last example above, the first argument can also +-be a slot, as one should expect in Scheme.

        +- ++be a slot, as one should expect in Scheme. ++

        ++

        + In addition to cut, there is a variant called cute + (a mnemonic for "cut with evaluated non-slots") which evaluates + the non-slot expressions at the time the procedure is specialized, not at + the time the specialized procedure is called. +-For example,

        +- +- +- +- +-
        (cute cons (+ a 1) <>) +-is the same as +-(let ((a1 (+ a 1))) (lambda (x2) (cons a1 x2))) +-

        +- ++For example, ++

        ++ ++ ++ ++ ++ ++ ++
        (cute cons (+ a 1) <>)is the same as(let ((a1 (+ a 1))) (lambda (x2) (cons a1 x2)))
        ++

        + As you see from comparing this example with the first example above, + the cute-variant will evaluate (+ a 1) + once, while the cut-variant will evaluate it during +-every invokation of the resulting procedure.

        +- ++every invokation of the resulting procedure. ++

        ++

        + The mechanism proposed in this SRFI allows specializing any subset + of the variables of a procedure. + The result can be of fixed arity or of variable arity. +@@ -111,11 +129,13 @@ The mechanism does not allow permutation, omission, duplication + or any other processing of the arguments; + for this it is necessary to write to use a different + mechanism such as lambda. ++

        + +-

        Rationale

        ++

        Rationale

        + ++

        + A particularly elegant way to deal with specialization is known +-as currying (Schönfinkel 1924, Curry 1958). ++as currying (Schönfinkel 1924, Curry 1958). + The idea of currying is to reduce multi-argument functions to + single-argument functions by regarding an n-ary + function as a unary function mapping its first argument into +@@ -123,8 +143,9 @@ an (n-1)-ary function (which is curried in turn). + This point of view, apart from its theoretical elegance, + allows an extremely compact notation for specializing the + first argument of a function. +-In the first example, one could simply write (cons 1).

        +- ++In the first example, one could simply write (cons 1). ++

        ++

        + Yet, Scheme is not a curried language---the + number of arguments passed to a procedure must match + the number of its parameters at all times. +@@ -135,73 +156,91 @@ and invent some irrelevant identifiers for its + formal variables (x in the example). + For this reason, the mechanism proposed in this SRFI + provides a simple and compact notation for specializing +-any subset of the parameters of a procedure.

        +- +-Note: The mechanism proposed here is not currying!

        +- ++any subset of the parameters of a procedure. ++

        ++

        ++Note: The mechanism proposed here is not currying! ++

        ++

        + The purpose of the mechanism proposed here is to make the benefits + of currying available within the programming language Scheme. + There are two primary benefits of currying in practice: + Higher-order types are substantially simplified and + there is a simple notation for specializing parameters. + The type aspect is irrelevant as Scheme has latent typing. +-The specialization aspect is largly covered with this SRFI.

        +- ++The specialization aspect is largly covered with this SRFI. ++

        ++

        + Here are a few more examples for illustration: ++

        ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
        (map (cut * 2 <>) '(1 2 3 4))
        (map (cut vector-set! x <> 0) indices)
        (for-each (cut write <> port) exprs)
        (map (cut <> x y z) (list min max))
        (for-each (cut <>) thunks)
        ++ ++

        Specification

        + +- +- +- +- +- +- +- +- +- +- +- +-
        (map (cut * 2 <>) '(1 2 3 4)) +-
        (map (cut vector-set! x <> 0) indices) +-
        (for-each (cut write <> port) exprs) +-
        (map (cut <> x y z) (list min max)) +-
        (for-each (cut <>) thunks) +-
        +- +-

        Specification

        +- +- ++

        + The formal syntax of a specialized expression, in the style of the +-Revised^5 Report on the Algorithmic Language Scheme:

        +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-
        <cut-expression> +---> +-(cut <slot-or-expr> <slot-or-expr>*) +- +-
        |(cut <slot-or-expr> <slot-or-expr>* <...>) +-; with "rest-slot" +-
        |(cute <slot-or-expr> <slot-or-expr>*) +-; evaluate non-slots at specialization time +-
        |(cute <slot-or-expr> <slot-or-expr>* <...>) +-; with "rest-slot" +-
        <slot-or-expr> +---> +-<>; a "slot" +-
        | <expression>; a "non-slot expression" +-

        +- ++Revised^5 Report on the Algorithmic Language Scheme:

        ++

        ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
        <cut-expression>-->(cut <slot-or-expr> <slot-or-expr>*)
        |(cut <slot-or-expr> <slot-or-expr>* <...>); with "rest-slot"
        |(cute <slot-or-expr> <slot-or-expr>*); evaluate non-slots at specialization time
        |(cute <slot-or-expr> <slot-or-expr>* <...>); with "rest-slot"
        <slot-or-expr>--><>; a "slot"
        | <expression>; a "non-slot expression"
        ++

        + The macro cut transforms a <cut-expression> + into a <lambda expression> with as many formal variables + as there are slots in the list <slot-or-expr>*. +@@ -210,18 +249,21 @@ the first <slot-or-expr> with arguments from + <slot-or-expr>* in the order they appear. + In case there is a rest-slot symbol, the resulting procedure is also of + variable arity, and the body calls the first <slot-or-expr> +-with all arguments provided to the actual call of the specialized procedure.

        +- ++with all arguments provided to the actual call of the specialized procedure. ++

        ++

        + The macro cute is similar to the macro cut, + except that it first binds new variables to the result of evaluating + the non-slot expressions (in an unspecific order) and then substituting + the variables for the non-slot expressions. + In effect, cut evaluates non-slot expressions at the time + the resulting procedure is called, whereas cute evaluates +-the non-slot expressions at the time the procedure is constructed.

        ++the non-slot expressions at the time the procedure is constructed. ++

        + +-

        Implementation

        ++

        Implementation

        + ++

        + The reference implementation defines the two macros + cut and cute using macro + mechanism of R5RS. +@@ -232,24 +274,26 @@ As macros in R5RS are hygienic and referentially transparent, + the macro mechanism makes sure the names of the newly + introduced formal variables are unique and do not clash. + The template (param ... slot), see +-Sect. 7.1.5. of R5RS, ++Sect. 7.1.5. of R5RS, + allows to preserve the order of arguments---which would get + reversed otherwise. +- ++

        ++

        + The reference implementation has been written by +-Al Petrofsky. It can be found here.

        +- ++Al Petrofsky. It can be found here. ++

        ++

        + Finally, there is a small collection of +-confidence tests. ++confidence tests. + It checks some special cases of the mechanism defined + in this SRFI and signals an error in case something is wrong. + Passing the tests does not mean a correct implementation. ++

        + ++

        Design Rationale

        + +-

        Design Rationale

        +- +-

        Why not real currying/uncurrying?

        +- ++

        Why not real currying/uncurrying?

        ++

        + It is possible in Scheme to implement a macro turning a multi-argument + procedure into a nesting of single-argument procedures and back. + These operations are usually called "curry" and "uncurry" in +@@ -261,11 +305,12 @@ if you apply it in the sequence "curry, specialize some arguments, + and uncurry again"---which is exactly the purpose of the macro + cut specified in this document. + The primary relevance of currying/uncurrying in Scheme is to +-teach concepts of combinatory logic.

        +- +-

        Why not a more general mechanism, also allowing permutation, +-omission and duplication of arguments?

        ++teach concepts of combinatory logic. ++

        + ++

        Why not a more general mechanism, also allowing permutation, ++omission and duplication of arguments?

        ++

        + The reason is that I, the author of this SRFI, consider more general + mechanisms too dangerous to mix them with the mechanism proposed here. + In particular, as soon as parameters are being rearranged it +@@ -273,13 +318,14 @@ is usually necessary to be aware of the meaning of the parameters; + unnamed variables can be quite harmful then. + The mechanism proposed here is designed to prevent this. + Please refer to the discussion threads +-"OK, how about...," (Alan Bawden), +-"is that useful?" (Walter C. Pelissero), and +-"l, the ultimate curry that is not curry" (Al Petrofsky).

        +- +-

        Why are the macro called cut/cute and not +-[enter your favourite here]?

        ++"OK, how about...," (Alan Bawden), ++"is that useful?" (Walter C. Pelissero), and ++"l, the ultimate curry that is not curry" (Al Petrofsky). ++

        + ++

        Why are the macro called cut/cute and not ++[enter your favourite here]?

        ++

        + Well, the original name proposed for this SRFI was curry + which immediately stirred some emotions as it does not what is + commonly known as currying. +@@ -306,23 +352,26 @@ concept is often called in other programming languages, + but I tend to remember it as the acronym for "Curry Upon This" ;-). + The names for the evaluating version of cut that + have been proposed were cut!, cutlet, +-cut*, and cute.

        +- +-

        Is it possible to implement the SRFI without macros?

        ++cut*, and cute. ++

        + ++

        Is it possible to implement the SRFI without macros?

        ++

        + Not really. + As Stephan Houben has pointed out during the discussion (refer to +-"Implementing it as a procedure") it is possible to implement the ++"Implementing it as a procedure") it is possible to implement the + cute-mechanism as a procedure. + Refer also to Al Petrofsky's posting +-"Problems with "curry"'s formal specification" for details. ++"Problems with "curry"'s formal specification" for details. + However, the procedural implementation comes with a slight performance + penalty and it is not possible the implement the cut-mechanism + as a procedure, too. + As both are needed, we rely on macros to implement the SRFI. ++

        + +-

        Why is there another symbol for the rest-slot when lambda-expressions +-use the dotted notation for variable length argument lists?

        ++

        Why is there another symbol for the rest-slot when lambda-expressions ++use the dotted notation for variable length argument lists?

        ++

        + There are two reasons. + The first one is the existence of a procedural implementation + of a related mechanism (refer to the previous paragraph). +@@ -330,10 +379,11 @@ For a procedure, however, it is not possible to have dotted notation. + The second reason is the way the hygienic macro mechanism in R5RS + is defined to deal with dotted notation, as Felix Winkelmann has pointed out. + Refer to the discussion threads +-"Improper lists in macros [WAS: none]".

        ++"Improper lists in macros [WAS: none]". ++

        + +-

        Why is it impossible to specify when a non-slot is evaluated individually +-per non-slot?

        ++

        Why is it impossible to specify when a non-slot is evaluated individually per non-slot?

        ++

        + Cut evaluates all non-slots at the time the specialized + procedure is called and cute evaluates all non-slots at + the time the procedure is being specialized. +@@ -343,32 +393,34 @@ However, I am convinced that the benefit of the greater flexibility + is not worth the risk of confusion. + If a piece of code really depends on the distinction, it might be + better to make this explicit through let and +-lambda.

        +- +-

        Why is (cut if <> 0 1) etc. illegal?

        ++lambda. ++

        + ++

        Why is (cut if <> 0 1) etc. illegal?

        ++

        + It is specified that a <slot-or-expr> must be + either the slot symbol or an <expression> in the sense +-of R5RS, +-Section 7.1.3. ++of R5RS, ++Section 7.1.3. + As if is no <expression>, + the above case is illegal. + The reason why cut and cute are + restricted in this sense is the difficulty of defining + the meaning of such generalized expressions. + Please refer to the discussion archive for details. ++

        + +-

        Acknowledgements

        +- ++

        Acknowledgements

        ++

        + An important part of this SRFI is based on the contribution + of other people, mostly through the discussion archive. + In particular, the semantics and the design rationale have + been greatly improved in the course of the discussion. + I would like to thank all who have contributed. ++

        + +-

        Copyright

        ++

        Copyright

        +

        Copyright (C) Sebastian Egner (2002). All Rights Reserved.

        +- +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -392,12 +444,12 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        +-
        Editor: Mike Sperber
        ++
        ++
        Editor: Mike Sperber
        +
        Author: Sebastian Egner
        + + +-Last modified: Wed Jun 19 10:54:36 MST 2002 ++Last modified: Sun Jan 28 13:40:30 MET 2007 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-27.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-27.html +index 14a88ff..c568d78 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-27.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-27.html +@@ -1,55 +1,67 @@ +- +- ++ ++ + ++ ++ + SRFI 27: Sources of Random Bits ++ ++ ++ + +- + +- +-

        Title

        +- +-SRFI 27: Sources of Random Bits +- +-

        Author

        +- +-Sebastian Egner +- +-

        Status

        +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +-You can access +-previous messages via +- +-the archive of the mailing list. +- +-
          +-
        • Draft: 2002/02/12-2002/04/12
        • +-
        • Revised: 2002/04/04 +-
        • Revised: 2002/04/10 +-
        • Revised: 2002/04/10 +-
        • Final: 2002/06/03 +-
        +- +-

        Abstract

        +- ++

        SRFI 27: Sources of Random Bits

        ++ ++

        by Sebastian Egner

        ++

        This copy of the SRFI 27 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-27/srfi-27.html.

        ++ ++

        Status

        ++ ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-27@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Draft: 2002-02-12--2002-04-12
        • ++
        • Revised: 2002-04-04 ++
        • Revised: 2002-04-10 ++
        • Revised: 2002-04-10 ++
        • Final: 2002-06-03 ++
        ++ ++

        Abstract

        ++

        + This document specifies an interface to sources of random bits, + or "random sources" for brevity. + In particular, there are three different ways to use the interface, + with varying demands on the quality of the source and the +-amout of control over the production process: +- +-

          +-
        • ++amount of control over the production process: ++

          ++
            ++
          • + The "no fuss" interface specifies that +-(random-integer n) +-produces the next random integer in {0, ..., n-1} and ++(random-integer n) ++produces the next random integer in {0, ..., n-1} and + (random-real) produces the next random + real number between zero and one. + The details of how these random values are produced may not be + very relevant, as long as they appear to be sufficiently random. +-
          • ++
          • ++
          • + For simulation purposes, on the contrary, it is usually necessary + to know that the numbers are produced deterministically by a pseudo + random number generator of high quality and to have explicit access +@@ -57,18 +69,19 @@ to its state. + In addition, one might want to use several independent sources of + random numbers at the same time and it can be useful to have some + simple form of randomization. +-
          • ++
          • ++
          • + For security applications a serious form of true randomization + is essential, in the sense that it is difficult for an adversary to + exploit or introduce imperfections into the distribution of random bits. + Moreover, the linear complexity of the stream of random bits is more + important than its statistical properties. +-In these applications, an entropy source (producing truly random ++In these applications, an entropy source (producing truely random + bits at a low rate) is used to randomize a pseudo random number + generator to increase the rate of available bits. +-
          ++
        • ++
        +

        +- + Once random sources provide the infrastructure to obtain + random bits, these can be used to construct other random deviates. + Most important are floating point numbers of various distributions +@@ -78,17 +91,20 @@ limited use elsewhere), we do not include them in this SRFI. + In other words, this SRFI is not about making + all sorts of random objects---it is about obtaining random + bits in a portable, flexible, reliable, and efficient way. ++

        + +-

        Rationale

        ++

        Rationale

        + ++

        + This SRFI defines an interface for sources of random bits + computed by a pseudo random number generator. + The interface provides range-limited integer and real numbers. + It allows accessing the state of the underlying generator. + Moreover, it is possible to obtain a large number of + independent generators and to invoke a mild form of true +-randomization.

        +- ++randomization. ++

        ++

        + The design aims at sufficient flexibility to cover the + usage patterns of many applications as diverse as + discrete structures, numerical simulations, and cryptographic protocols. +@@ -96,8 +112,9 @@ At the same time, the interface aims at simplicity, + which is important for occasional use. + As there is no "one size fits all" random number generator, + the design necessarily represents some form of compromise +-between the needs of the various applications.

        +- ++between the needs of the various applications. ++

        ++

        + Although strictly speaking not part of the specification, + the emphasis of this proposal is on high quality + random numbers and on high performance. +@@ -105,51 +122,49 @@ As the state of the art in pseudo random number generators + is still advancing considerably, the choice of method for + the reference implementation should essentially be + considered preliminary. ++

        + +-

        Specification

        +- +-
        +- +-
        +-(random-integer n) -> x +-
        ++

        Specification

        + +-
        +-The next integer x in {0, ..., n-1} ++
        ++
        ++(random-integer n) -> x ++
        ++
        ++

        ++The next integer x in {0, ..., n-1} + obtained from default-random-source. + Subsequent results of this procedure appear to be independent +-uniformly distributed over the range {0, ..., n-1}. +-The argument n must be a positive integer, ++uniformly distributed over the range {0, ..., n-1}. ++The argument n must be a positive integer, + otherwise an error is signalled. +-

        +- +-
        +- +-
        +- +-
        +-(random-real) -> x +-
        +- +-
        +-The next number 0 < x < 1 obtained from ++

        ++
        ++
        ++ ++
        ++
        ++(random-real) -> x ++
        ++
        ++

        ++The next number 0 < x < 1 obtained from + default-random-source. + Subsequent results of this procedure appear to be + independent uniformly distributed. + The numerical type of the results and the + quantization of the output range depend on the implementation; + refer to random-source-make-reals for details. +-

        +- +-
        +- +-
        ++

        ++
        ++
        + +-
        ++
        ++
        + default-random-source +-
        +- +-
        ++
        ++
        ++

        + A random source from which random-integer and + random-real have been derived using + random-source-make-integers and +@@ -157,18 +172,18 @@ A random source from which random-integer and + Note that an assignment to default-random-source + does not change random or random-real; + it is also strongly recommended not to assign a new value. +-

        +- +- +-
        +-
        +- +-
        +-(make-random-source) -> s +-
        +- +-
        +-Creates a new random source s. ++

        ++
        ++
        ++ ++
        ++
        ++
        ++(make-random-source) -> s ++
        ++
        ++

        ++Creates a new random source s. + Implementations may accept additional, optional arguments in + order to create different types of random sources. + A random source created with make-random-source +@@ -177,146 +192,148 @@ by some form of pseudo random number generator. + Each random source obtained as (make-random-source) + generates the same stream of values, unless the state is modified + with one of the procedures below. +-

        +- +-
        +- +-
        +- +-
        +-(random-source? obj) -> bool +-
        +- +-
        +-Tests if obj is a random source. ++

        ++
        ++
        ++ ++
        ++
        ++(random-source? obj) -> bool ++
        ++
        ++

        ++Tests if obj is a random source. + Objects of type random source are distinct from all + other types of objects. +-

        +- +-
        +- +-
        +- +-
        +-(random-source-state-ref s) -> state
        +-(random-source-state-set! s state) +-
        +- +-
        +-Get and set the current state of a random source s. The +-structure of the object state depends on the implementation; ++

        ++
        ++
        ++ ++
        ++
        ++(random-source-state-ref s) -> state
        ++(random-source-state-set! s state) ++
        ++
        ++

        ++Get and set the current state of a random source s. The ++structure of the object state depends on the implementation; + the only portable use of it is as argument to + random-source-state-set!. + It is, however, required that a state possess an external + representation. +-

        +- +-
        +- +-
        +-
        +-(random-source-randomize! s) +-
        +- +-
        ++

        ++
        ++
        ++ ++
        ++
        ++(random-source-randomize! s) ++
        ++
        ++

        + Makes an effort to set the state of the random +-source s to a truly random state. ++source s to a truly random state. + The actual quality of this randomization depends on the implementation +-but it can at least be assumed that the procedure sets s to a ++but it can at least be assumed that the procedure sets s to a + different state for each subsequent run of the Scheme system. +-

        +-
        +- +-
        +-
        +-(random-source-pseudo-randomize! s i j) +-
        +- +-
        +-Changes the state of the random source s into the initial +-state of the (i, j)-th independent random source, +-where i and j are non-negative integers. ++

        ++
        ++
        ++ ++
        ++
        ++(random-source-pseudo-randomize! s i j) ++
        ++
        ++

        ++Changes the state of the random source s into the initial ++state of the (i, j)-th independent random source, ++where i and j are non-negative integers. + This procedure provides a mechanism to obtain a large number of + independent random sources (usually all derived from the same backbone + generator), indexed by two integers. + In contrast to random-source-randomize!, + this procedure is entirely deterministic. +-

        +-
        +- +- +-
        ++

        ++ ++ + +-
        + +-
        +-(random-source-make-integers s) -> rand +-
        ++
        + +-
        +-Obtains a procedure rand to generate random integers +-using the random source s. +-Rand takes a single argument n, ++
        ++
        ++(random-source-make-integers s) -> rand ++
        ++
        ++

        ++Obtains a procedure rand to generate random integers ++using the random source s. ++Rand takes a single argument n, + which must be a positive integer, and returns the next uniformly +-distributed random integer from the interval {0, ..., n-1} +-by advancing the state of the source s.

        +- ++distributed random integer from the interval {0, ..., n-1} ++by advancing the state of the source s. ++

        ++

        + If an application obtains and uses several generators for the same +-random source s, a call to any of these generators advances +-the state of s. Hence, the generators do not produce ++random source s, a call to any of these generators advances ++the state of s. Hence, the generators do not produce + the same sequence of random integers each but rather share a state. + This also holds for all other types of generators derived from + a fixed random sources. + Implementations that support concurrency make sure that +-the state of a generator is properly advanced.

        +-

        +- +-
        +- +-
        +- +-
        +-(random-source-make-reals s) -> rand
        +-(random-source-make-reals s unit) -> rand
        +-
        +- +-
        +-Obtains a procedure rand to generate random real numbers +-0 < x < 1 using the random source s. +-The procedure rand is called without arguments.

        +- +-The optional parameter unit determines the type of numbers +-being produced by rand and the quantization of the output. +-Unit must be a number such that 0 < unit < 1. +-The numbers created by rand are of the same numerical +-type as unit and the potential output values are +-spaced by at most unit. One can imagine rand +-to create numbers as x*unit where x +-is a random integer in {1, ..., floor(1/unit)-1}. ++the state of a generator is properly advanced.

        ++
        ++
        ++ ++ ++
        ++
        ++(random-source-make-reals s) -> rand
        ++(random-source-make-reals s unit) -> rand
        ++
        ++
        ++

        ++Obtains a procedure rand to generate random real numbers ++0 < x < 1 using the random source s. ++The procedure rand is called without arguments. ++

        ++

        ++The optional parameter unit determines the type of numbers ++being produced by rand and the quantization of the output. ++Unit must be a number such that 0 < unit < 1. ++The numbers created by rand are of the same numerical ++type as unit and the potential output values are ++spaced by at most unit. One can imagine rand ++to create numbers as x*unit where x ++is a random integer in {1, ..., floor(1/unit)-1}. + Note, however, that this need not be the way the values + are actually created and that the actual resolution of +-rand can be much higher than unit. +-In case unit is absent it defaults to a reasonably ++rand can be much higher than unit. ++In case unit is absent it defaults to a reasonably + small value (related to the width of the mantissa of an + efficient number format). +-

        +- +-
        ++

        ++
        ++
        + + +-

        Design Rationale

        ++

        Design Rationale

        + +-

        Why not combine random-integer and +-random-real?

        ++

        Why not combine random-integer and random-real?

        + ++

        + The two procedures are not combined into a single variable-arity + procedures to save a little time and space during execution. + Although some Scheme systems can deal with variable arity as + efficiently as with fixed arity this is not always the case + and time efficiency is very important here. ++

        + +-

        Why not some object-oriented interface?

        ++

        Why not some object-oriented interface?

        + ++

        + There are many alternatives to the interface as specified in this SRFI. + In particular, every framework for object-orientation can be used to + define a class for random sources and specify the interface for the +@@ -324,9 +341,11 @@ methods on random sources. + However, as the object-oriented frameworks differ considerably + in terms of syntax and functionality, this SRFI does not make + use of any particular framework. ++

        + +-

        Why is there not just a generator with a fixed range?

        ++

        Why is there not just a generator with a fixed range?

        + ++

        + A bare fixed-range generator is of very limited use. + Nearly every application has to add some functionality + to make use of the random numbers. +@@ -337,22 +356,26 @@ This is exactly what is provided by + In addition, is saves the user from the pitfall of changing + the range with a simple modulo-computation + which may substantially reduce the quality of the +-numbers being produced.

        +- ++numbers being produced. ++

        ++

        + The design of the interface is based on three prototype applications: +-

          +-
        1. ++

          ++
            ++
          1. + Repeatedly choose from relatively small sets: + As the size of the set is likely to vary from call to call, +-random-integer accepts a range argument n in every call. ++random-integer accepts a range argument n in every call. + The implementation should try to avoid boxing/unboxing of values + if the ranges fit into immediate integers. +-
          2. ++
          3. ++
          4. + Generate a few large integers with a fixed number of bits: + As generating the random number itself is expensive, + passing the range argument in every call does not hurt performance. + Hence, the same interface as in the first application can be used. +-
          5. ++
          6. ++
          7. + Generate real numbers: + Unlike the choose-from-set case, + the range and the quantization is constant over a +@@ -365,10 +388,11 @@ Therefore, + random-real does not accept any parameters but + the procedure random-source-make-reals creates + a properly configured random-real procedure. +-
          +- +-

          Why bother about floating point numbers at all?

          ++
        2. ++
        + ++

        Why bother about floating point numbers at all?

        ++

        + A proper floating point implementation of a random number generator + is potentially much more efficient that an integer implementation + because it can use more powerful arithmetics hardware. +@@ -378,19 +402,21 @@ produce floating point random numbers. + A secondary reason is to save the user from the 'not as easy as + it seems' task of converting an integer generator into a real + generator. ++

        + +-

        Why are zero and one excluded from random-real?

        +- ++

        Why are zero and one excluded from random-real?

        ++

        + The procedure random-real does not return +-x = 0 or x = 1 in order to allow +-(log x) and +-(log (- 1 x)) ++x = 0 or x = 1 in order to allow ++(log x) and ++(log (- 1 x)) + without the danger of a numerical exception. ++

        + +-

        Implementation

        +- +-

        Choice of generator

        ++

        Implementation

        + ++

        Choice of generator

        ++

        + The most important decision about the implementation is + the choice of the random number generator. + The basic principle here is: Let quality prevail! +@@ -399,8 +425,9 @@ a cheap price to pay for some avoided catastrophes. + It may be unexpected, but I have also seen many examples + where the better generator was also the faster. + Simple linear congruential generator cannot be recommended +-as they tend to be ill-behaved in several ways.

        +- ++as they tend to be ill-behaved in several ways. ++

        ++

        + For this reason, my initial proposal was George Marsaglia's + COMBO generator, which is the combination of a 32-bit + multiplicative lagged Fibonacci-generator with a 16-bit +@@ -408,16 +435,17 @@ multiply with carry generator. + The COMBO generator passes all tests of Marsaglia's + DIEHARD + testsuite for random number generators and has +-a period of order 2^60.

        +- ++a period of order 2^60. ++

        ++

        + As an improvement, Brad Lucier suggested +-suggested ++suggested + Pierre L'Ecuyer's + MRG32k3a + generator which is combination of two recursive generators + of degree three, both of which fit into 54-bit arithmetics. + The MRG32k3a generator also passes DIEHARD and in addition, +-has desirable spectral properties and a period in the ++has desireable spectral properties and a period in the + order of 2^191. + As a matter of fact, multiple recursive generators (MRGs) are + theoretically much better understood than special constructions +@@ -425,10 +453,12 @@ as the COMBO generator. + This is the reason why the implementations provided here + implements the MRG32k3a generator. + When implemented in floating point arithmetics with sufficient +-mantissa-width, this generator is also very fast.

        ++mantissa-width, this generator is also very fast. ++

        + +-

        Choice of arithmetics

        ++

        Choice of arithmetics

        + ++

        + The next important decision about the implementation is + the type of arithmetics to be used. + The choice is difficult and depends heavily on the +@@ -441,8 +471,9 @@ And if you do not have floats either, then at least + try to make sure you work with immediate integers + (instead of allocated objects). + Unfortunately, there is no portable way in Scheme to +-find out about native and emulated arithmetics.

        +- ++find out about native and emulated arithmetics. ++

        ++

        + As performance is critical to many applications, + one might want to implement the actual + generator itself in native code. +@@ -450,17 +481,20 @@ For this reason, I provide three different + implementations of the backbone generator + as a source of inspiration. + See the code below. ++

        + +-

        Data Type for Random Sources

        ++

        Data Type for Random Sources

        + ++

        + An important aspect of the specification in this SRFI + is that random sources are objects of a distinct type. + Although this is straight-forward and available in nearly + every Scheme implementation, there is no portable way + to do this at present. + One way to define the record type is to use +-SRFI-9.

        +- ++SRFI-9. ++

        ++

        + The reference implementations below define a record + type to contain the exported procedures. + The actual state of the generator is stored in the +@@ -468,42 +502,51 @@ binding time environment of make-random-source. + This has the advantage that access to the state is fast + even if the record type would be slow (which need not be + the case). ++

        + +-

        Entropy Source for Randomization

        ++

        Entropy Source for Randomization

        + ++

        + Another problematic part of the specification with respect + to portability is random-source-randomize! as +-it needs access to a real entropy source.

        +- ++it needs access to a real entropy source. ++

        ++

        + A reasonable choice for such as source is to use the system + clock in order to obtain a value for randomization, for example + in the way John David Stone recommends (see reference below). + This is good enough for most applications with the + notable exception of security related programs. + One way to obtain the time in Scheme is to use +-SRFI-19.

        ++SRFI-19. ++

        + +-

        Implementation of the specified interface

        ++

        Implementation of the specified interface

        + ++

        + Once the portability issues are resolved, + one can provide the remaining functionality as +-specified in this SRFI document.

        +- ++specified in this SRFI document. ++

        ++

        + For the reference implementation, a relatively large part + of the code deals with the more advanced features of the + MRG32k3a generator, + in particular random-source-pseudo-randomize!. + This code is inspired by Pierre L'Ecuyer's own implementation +-of the MRG32k3a generator.

        +- ++of the MRG32k3a generator. ++

        ++

        + Another part of this generic code deals with changing + the range and quantization of the random numbers and +-with error checking to detect common mistakes and abuses.

        ++with error checking to detect common mistakes and abuses. ++

        + +-

        Implementation Examples

        ++

        Implementation Examples

        + +-Here are three alternative implementations of the SRFI. +-(Here are all files, tar-gzipped, 13300 bytes.) ++

        ++Here are three alternative implementations of the SRFI. ++(Here are all files, tar-gzipped, 53K bytes.) + Keep in mind that a SRFI is a "request for implementation", + which means these implementations are merely examples + to illustrate the specification and inspire people to implement +@@ -513,35 +556,35 @@ on a Pentium3, 800 Mhz, Linux; x int/s, y real/s + means (random-integer 2) can be computed about x + times a second and (random-real) about y times a second. + The implementations are ++

        + +-
          +- +-
        1. for Scheme 48 0.57, using 54-bit integer only. ++
            ++
          1. for Scheme 48 0.57, using 54-bit integer only. + This implementation aims at portability, not at performance + (30000 ints/s, 3000/s reals/s). +- +-
          2. for Scheme 48 0.57 with the core generator being implemented ++
          3. ++
          4. for Scheme 48 0.57 with the core generator being implemented + in C using (double)-arithmetics. + The generator is made available in Scheme 48 via the + C/Scheme + interface. + The performance of this generator is good + (160000 ints/s, 180000 reals/s). +- +-
          5. for Gambit 3.0, using flonum and ++
          6. ++
          7. for Gambit 3.0, using flonum and + 54-bit integer. + This code is inspired by a program by Brad Lucier as +-posted ++posted + to the discussion archive of this SRFI. + The performance of this generator is good when compiled + (5000 ints/s, 25000/s reals/s when interpreted, + 200000 ints/s, 400000/s reals/s when compiled; + see acknowledgements). +- +-
          +- ++
        2. ++
        ++

        + In addition to the implementations there is a small +-collection of confidence tests ++collection of confidence tests + for the interface specified. + The tests merely check a few assertions expressed by the specification. + It is not the intention to provide a complete test of the interface here. +@@ -550,12 +593,13 @@ generator itself. + However, there is a function to write random bits from + the generators to a file in a way readable by the DIEHARD + testsuite. This makes it easier for implementors to find out +-about their favorite generators and check their implementation.

        +- ++about their favorite generators and check their implementation. ++

        + + +-

        Recommended Usage Patterns

        ++

        Recommended Usage Patterns

        + ++

        + Unless the functionality defined in this SRFI is sufficient, + an application has to implement more procedures to construct + other random deviates. +@@ -565,24 +609,27 @@ examples of increasing difficulty + with respect to the interface. + Note that the code below is not part of the specification, + it is merely meant to illustrate the spirit ++

        + +-

        Generating Random Permutations

        ++

        Generating Random Permutations

        + ++

        + The following code defines procedures to generate random +-permutations of the set {0, ..., n-1}. ++permutations of the set {0, ..., n-1}. + Such a permutation is represented by a vector +-of length n for the images of the points.

        +- ++of length n for the images of the points. ++

        ++

        + Observe that the implementation first defines the procedure + random-source-make-permutations to +-turn a random source s into a procedure to generate +-permutations of given degree n. ++turn a random source s into a procedure to generate ++permutations of given degree n. + In a second step, this is applied to the default source + to define a ready-to-use procedure for permutations: +-(random-permutation n) +-constructs a random permutation of degree n. +- +-

        ++(random-permutation n)
        ++constructs a random permutation of degree n.
        ++

        ++
        + (define (random-source-make-permutations s)
        +   (let ((rand (random-source-make-integers s)))
        +     (lambda (n)
        +@@ -601,19 +648,21 @@ constructs a random permutation of degree n.
        + 
        + (define random-permutation
        +   (random-source-make-permutations default-random-source))
        +-
        +- ++
        ++

        + For the algorithm refer to Knuth's "The Art of Computer Programming", + Vol. II, 2nd ed., Algorithm P of Section 3.4.2. ++

        + +-

        Generating Exponentially-Distributed Random Numbers

        ++

        Generating Exponentially-Distributed Random Numbers

        + ++

        + The following code defines procedures to generate exponentially + Exp(mu)-distributed random numbers. + The technical difficulty of the interface addressed here is + how to pass optional arguments to random-source-make-reals. +- +-

        ++

        ++
        + (define (random-source-make-exponentials s . unit)
        +   (let ((rand (apply random-source-make-reals s unit)))
        +     (lambda (mu)
        +@@ -621,17 +670,20 @@ how to pass optional arguments to random-source-make-reals.
        + 
        + (define random-exponential
        +   (random-source-make-exponentials default-random-source))
        +-
        +- ++
        ++

        + The algorithm is folklore. Refer to Knuth's "The Art of Computer + Programming", Vol. II, 2nd ed., Section 3.4.1.D. ++

        + +-

        Generating Normally-Distributed Random Numbers

        ++

        Generating Normally-Distributed Random Numbers

        + ++

        + The following code defines procedures to generate + normal N(mu, sigma)-distributed real numbers using +-the polar method.

        +- ++the polar method. ++

        ++

        + The technical difficulty of the interface addressed here + is that the polar method generates two results per computation. + We return one of the result and store the second one to be +@@ -639,8 +691,8 @@ returned by the next call to the procedure. + Note that this implies that random-source-state-set! + (and the other procedures modifying the state) does not necessarily + affect the output of random-normal immediately! +- +-

        ++

        ++
        + (define (random-source-make-normals s . unit)
        +   (let ((rand (apply random-source-make-reals s unit))
        + 	(next #f))
        +@@ -653,7 +705,7 @@ affect the output of random-normal immediately!
        + 	    (let* ((v1 (- (* 2 (rand)) 1))
        + 		   (v2 (- (* 2 (rand)) 1))
        + 		   (s (+ (* v1 v1) (* v2 v2))))
        +-	      (if (>= s 1)
        ++	      (if (>= s 1)
        + 		  (loop)
        + 		  (let ((scale (sqrt (/ (* -2 (log s)) s))))
        + 		    (set! next (* scale v2))
        +@@ -661,38 +713,40 @@ affect the output of random-normal immediately!
        + 
        + (define random-normal
        +   (random-source-make-normals default-random-source))
        +-
        +- ++
        ++

        + For the algorithm refer to Knuth's "The Art of Computer Programming", + Vol. II, 2nd ed., Algorithm P of Section 3.4.1.C. ++

        + +-

        Acknowledgements

        +- ++

        Acknowledgements

        ++

        + I would like to thank all people who have participated in the discussion, + in particular Brad Lucier and Pierre l'Ecuyer. + Their contributions have greatly improved the design of this SRFI. + Moreover, Brad has optimized the Gambit implementation quite substantially. ++

        + +-

        References

        ++

        References

        + +-
          ++
            + +-
          1. ++
          2. + G. Marsaglia: + Diehard -- Testsuite for Random Number Generators. + stat.fsu.edu/~geo/diehard.html + (Also contains some generators that do pass Diehard.) +-
          3. ++ + +-
          4. ++
          5. + D. E. Knuth: + The Art of Computer Programming; + Volume II Seminumerical Algorithms. + 2nd ed. Addison-Wesley, 1981. + (The famous chapter on random number generators.) +-
          6. ++ + +-
          7. ++
          8. + P. L'Ecuyer: + "Software for Uniform Random Number Generation: + Distinguishing the Good and the Bad", +@@ -700,93 +754,92 @@ Moreover, Brad has optimized the Gambit implementation quite substantially. + IEEE Press, Dec. 2001, 95--105. + www.iro.umontreal.ca/~lecuyer/myftp/papers/wsc01rng.pdf + (Profound discussion of random number generators.) +-
          9. ++ + +-
          10. ++
          11. + P. L'Ecuyer: + "Good Parameter Sets for Combined Multiple Recursive + Random Number Generators", + Shorter version in Operations Research, 47, 1 (1999), 159--164. + www.iro.umontreal.ca/~lecuyer/myftp/papers/combmrg2.ps + (Actual numbers for good generators.) +-
          12. ++ + +-
          13. ++
          14. + P. L'Ecuyer: + "Software for Uniform Random Number Generation: + Distinguishing the Good and the Bad", + Proceedings of the 2001 Winter Simulation Conference, + IEEE Press, Dec. 2001, 95--105. +-
          15. ++ + +-
          16. ++
          17. + MIT Scheme v7.6: + random flo:random-unit *random-state* make-random-state + random-state? + http://www.swiss.ai.mit.edu/projects/scheme/documentation/scheme_5.html#SEC53 + (A mechanism to run a fixed unspecified generator.) +-
          18. ++ + +-
          19. ++
          20. + A. Jaffer: + SLIB 2d2 with (require 'random): +- random *random-state* copy-random-state seed->random-state ++ random *random-state* copy-random-state seed->random-state + make-random-state random:uniform random:exp random:normal-vector! + random-hollow-sphere! random:solid-sphere! +- http://www.swiss.ai.mit.edu/~jaffer/slib_4.html#SEC92 +- (Based on the MIT Scheme mechanism.) +-
          21. ++ http://swiss.csail.mit.edu/~jaffer/slib_5.html#SEC108 ++ (Uses RC-4.) ++ + +-
          22. ++
          23. + R. Kelsey, J. Rees: + Scheme 48 v0.57 'random.scm': + make-random make-random-vector + (Internal procedures of Scheme48; a fixed 28-bit generator.) +-
          24. ++ + +-
          25. ++
          26. + M. Flatt: + PLT MzScheme Version 200alpha1: + random random-seed current-pseudo-random-generator + make-pseudo-random-generator pseudo-random-generator? +- http://download.plt-scheme.org/doc/200alpha1/html/mzscheme/mzscheme-Z-H-3.html#%_idx_144 ++ http://download.plt-scheme.org/doc/200alpha1/html/mzscheme/mzscheme-Z-H-3.html#%_idx_144 + (A mechanism to run a generator and to exchange the generator.) +-
          27. ++ + +-
          28. ++
          29. + H. Abelson, G. J. Sussmann, J. Sussman: + Structure and Interpretation of Computer Programs. +- http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_idx_2934 ++ http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#%_idx_2934 + (The rand-example shows a textbook way to define a + random number generator.) +-
          30. ++ + +-
          31. ++
          32. + John David Stone: + A portable random-number generator. + http://www.math.grin.edu/~stone/events/scheme-workshop/random.html + (An implementation of a linear congruental generator in Scheme.) +-
          33. ++ + +-
          34. ++
          35. + Network Working Group: + RFC1750: Randomness Recommendations for Security. + http://www.cis.ohio-state.edu/htbin/rfc/rfc1750.html + (A serious discussion of serious randomness for serious security.) +-
          36. ++ + +-
          37. +- http://www.random.org/essay.html
            ++
          38. ++ http://www.random.org/essay.html
            + http://www.taygeta.com/random/randrefs.html + (Resources on random number generators and randomness.) +-
          39. ++ + +-
          ++
        + + +-

        Copyright

        ++

        Copyright

        +

        Copyright (C) Sebastian Egner (2002). All Rights Reserved.

        +- +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -810,12 +863,12 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        +-
        Editor: Mike Sperber
        ++
        ++
        Editor: Mike Sperber
        +
        Author: Sebastian Egner
        + + +-Last modified: Fri Sep 5 16:11:17 MST 2003 ++Last modified: Wed Jul 21 08:44:49 MST 2010 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-28.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-28.html +index 8aae23b..c2a0de5 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-28.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-28.html +@@ -1,41 +1,58 @@ +- +- ++ ++ + +- ++ ++ ++ + SRFI 28: Basic Format Strings +- +- ++ ++ ++ ++ ++ + + + + +-

        Title

        ++

        SRFI 28: Basic Format Strings

        + +- SRFI 28: Basic Format Strings ++

        by Scott G. Miller

        ++

        This copy of the SRFI 28 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-28/srfi-28.html.

        + +-

        Author

        ++

        Status

        + +- Scott G. Miller ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-28@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Draft: 2002-03-23--2002-05-23
        • ++
        • Final: 2002-06-25 ++
        + +-

        Status

        +- +- This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +- +- You can access the discussion on this SRFI via the archive of the mailing list. +- +-
          +-
        • Draft: 2002/03/23-2002/05/23
        • +-
        • Final: 2002/06/25 +-
        +- +-

        Abstract

        ++

        Abstract

        + + This document specifies Format Strings, a method of + interpreting a Scheme string which contains a number of escape + sequences that are replaced with other string data according to + the semantics of each sequence. + +-

        Rationale

        ++

        Rationale

        + + Many Scheme systems provide access to a function called + format. This function takes as arguments a format string, +@@ -47,9 +64,9 @@ + allow portable code to be written using the function without + much (if any) effort on the part of Scheme implementors. + +-

        Specification

        ++

        Specification

        + +- format format-string [obj ...] -> ++ format format-string [obj ...] -> + string + +
        +@@ -84,7 +101,7 @@ + value.

        +
        + +-

        Examples

        ++

        Examples

        +
        + (format "Hello, ~a" "World!")
        + ; => "Hello, World!"
        +@@ -93,10 +110,10 @@
        + ; => "Error, list is too short: (one \"two\" 3))"
        + 
        + +-

        Implementation

        ++

        Implementation

        + + The implementation below requires SRFI-6 (Basic string ports) +- and SRFI-23 (Error reporting mechanism).
        ++ and SRFI-23 (Error reporting mechanism).
        + +
        + (define format
        +@@ -134,7 +151,7 @@
        +     
        + 
        + +-

        Copyright

        ++

        Copyright

        + +

        Copyright (C) Scott G. Miller (2002). All Rights Reserved.

        + +@@ -161,10 +178,10 @@ + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +

        +-
        ++
        + +
        +- Editor: ++ Editor: + Francisco Solsona +
        + +@@ -178,4 +195,3 @@ + + + +- +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-29.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-29.html +index e493c05..bc144b0 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-29.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-29.html +@@ -1,36 +1,46 @@ +- ++ + + +- +- ++ ++ + SRFI 29: Localization +- +- +- ++ ++ ++ + + +-

        29: Localization

        ++

        SRFI 29: Localization

        + +

        by Scott G. Miller

        ++

        This copy of the SRFI 29 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-29/srfi-29.html.

        + +

        Status

        + +

        This SRFI is currently in final status. Here is + an + explanation of each status that a SRFI can hold. To provide +- input on this SRFI, please send email to srfi-29@nospamsrfi.schemers.org. +- To subscribe to the list, follow these ++ input on this SRFI, please send email to srfi-29@nospamsrfi.schemers.org. ++ To subscribe to the list, follow these + instructions. You can access previous messages via the +- mailing list archive.

        ++ mailing list archive.

        + +
          +
        • Draft: 2002-03-26--2002-06-19
        • +@@ -124,9 +134,9 @@ + no-argument procedures:

          + +

          current-language +- -> symbol
          ++ -> symbol
          + current-language symbol -> +- undefined

          ++ undefined

          + +
          + When given no arguments, returns the current ISO 639-1 language +@@ -137,9 +147,9 @@ +
          + +

          current-country +- -> symbol
          ++ -> symbol
          + current-country symbol -> +- undefined

          ++ undefined

          + +
          + returns the current ISO 3166-1 country code as a symbol. +@@ -149,11 +159,10 @@ + is not possible).    +
          + +-

          current-locale-details +- -> list of symbols
          ++

          current-locale-details ++ -> list of symbols
          + current-locale-details list-of-symbols -> +- undefined

          ++ undefined

          + +
          + Returns a list of additional locale details as a list of +@@ -211,7 +220,7 @@ + +

          declare-bundle! + bundle-specifier association-list -> +- undefined

          ++ undefined

          + +
          + Declares a new bundle named by the given bundle-specifier. +@@ -219,10 +228,10 @@ + association list.  The list contains associations between + Scheme symbols and the message templates (Scheme strings) they + name.  If a bundle already exists with the given name, it +- is overwritten with the newly declared bundle.
          ++ is overwritten with the newly declared bundle.
          +
          + store-bundle +- bundle-specifier -> boolean
          ++ bundle-specifier -> boolean
          + +
          + Attempts to store a bundle named by the given bundle specifier, +@@ -231,10 +240,10 @@ + an unspecified mechanism that may be persistent across Scheme + system restarts.  If successful, a non-false value is + returned.  If unsuccessful, #f is +- returned.
          ++ returned.
          +
          + load-bundle! +- bundle-specifier -> boolean
          ++ bundle-specifier -> boolean
          + +
          + Attempts to retrieve a bundle from an unspecified mechanism +@@ -243,7 +252,7 @@ + non-false value, and the bundle is immediately available to the + Scheme system. If the bundle could not be found or loaded + successfully, the function returns #f, and the +- Scheme system's bundle registry remains unaffected.
          ++ Scheme system's bundle registry remains unaffected.
          +
          + +

          A compliant Scheme system may choose not to provide any +@@ -259,14 +268,14 @@ + +

          localized-template + package-name message-template-name +- -> string or #f

          ++ -> string or #f

          + +
          + Retrieves a localized message template for the given package + name and the given message template name (both symbols). +  If no such message could be found, false (#f) is +- returned.
          +-
          ++ returned.
          ++
          +
          + +

          After retrieving a template, the calling program can use +@@ -324,7 +333,7 @@ + of those functions in the reference implementation are not + capable of that distinction. Their implementation is provided + only so that the following code can run in any R4RS scheme +- system.  

          ++ system.  

          + +

          In addition, the below implementation of a compliant + format requires SRFI-6 (Basic String Ports) and +@@ -500,11 +509,10 @@ + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE.

          + +-
          ++
          + +
          +- Editor: David ++ Editor: David + Rush +
          + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-30.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-30.html +index b6c2fdc..ee5fafa 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-30.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-30.html +@@ -1,63 +1,69 @@ +- +- ++ ++ + ++ ++ + SRFI 30: Nested Multi-line Comments ++ ++ ++ + + + + +-

          Title

          ++

          SRFI 30: Nested Multi-line Comments

          + +-SRFI 30: Nested Multi-line Comments ++

          by Martin Gasbichler

          ++

          This copy of the SRFI 30 specification document ++is distributed as part of the Racket package ++srfi-doc.

          The canonical source of this document is ++https://srfi.schemers.org/srfi-30/srfi-30.html.

          ++ ++

          Status

          + +-

          Author

          ++

          This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-30@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

          + +-Martin Gasbichler +- +-

          Status

          +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. It will +-remain in draft until 2002-04-06, or as amended. to provide input on +-this SRFI, please +- +-mail to srfi-30@srfi.schemers.org. +-See +-instructions here to subscribe to the list. You can access +-previous messages via +- +-the archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +- +-
            +-
          • Draft: 2002/04/12-2002/06/10
          • +-
          • Revised: 2002/06/05
          • +-
          • Final: 2002/08/07
          • +-
          +- +-

          Related SRFIs

          ++
            ++
          • Draft: 2002-04-12--2002-06-10
          • ++
          • Revised: 2002-06-05
          • ++
          • Final: 2002-08-07
          • ++
          ++ ++

          Related SRFIs

          + +-

          SRFI 22 defines ++

          SRFI 22 defines + a multi line comment that may only appear at the beginning of a + file.

          + +-

          SRFI 10 +- proposes the notation ++

          SRFI 10 ++ proposes the notation

          + +-
           "#" <discriminator> <other-char>*
          for further +- SRFIs that introduce values which may be read and written.

          ++
           "#" <discriminator> <other-char>*
          ++

          for further SRFIs that introduce values which may be read and ++ written.

          + +-

          Abstract

          ++

          Abstract

          + +

          This SRFI extends R5RS by possibly nested, multi-line + comments. Multi-line comments start with #| and end + with |#.

          + +-

          Rationale

          ++

          Rationale

          + +

          Multi-line comments are common to many programming languages. They + provide a convenient mean for adding blocks of text inside a program and +@@ -70,13 +76,11 @@ the archive of the mailing list. + with R5RS. Nested comments are an important feature for + incrementally commenting out code.

          + +-

          Specification

          ++

          Specification

          + +-

          This SRFI extends the specification of comments -- R5RS ++

          This SRFI extends the specification of comments -- R5RS + section 2.2 -- as follows:

          + +- +

          The sequence #| indicates the start of a + multi-line comment. The multi-line comment continues until + |# appears. If the closing |# is +@@ -88,8 +92,7 @@ the archive of the mailing list. + +

          This SRFI furthermore extends the production for + <comment> in the specification of lexical +- structure -- R5RS ++ structure -- R5RS + section 7.1.1 -- to: +

          +
          +@@ -101,11 +104,10 @@ the archive of the mailing list.
          +     
          + + +-

          <delimiter> and #

          ++

          <delimiter> and #

          + +

          The SRFI does not extend the specification of +- <delimiter> from R5RS ++ <delimiter> from R5RS + section 7.1.1. It is therefore required to separate tokens + which require implicit termination (identifiers, numbers, + characters, and dot) from multi-line comments by a +@@ -116,7 +118,7 @@ the archive of the mailing list. + incompatible with existing implementations which allow + # as legal character within identifiers.

          + +-

          Implementation

          ++

          Implementation

          + +

          The following procedure skip-comment deletes a + leading multi-line comment from the current input port. Its +@@ -143,7 +145,7 @@ the archive of the mailing list. + ((#\#) (lp 'read-sharp nested-level)) + (else (lp 'start nested-level)))) + ((read-bar) (case (next-char) +- ((#\#) (if (> nested-level 1) ++ ((#\#) (if (> nested-level 1) + (lp 'start (- nested-level 1)))) + (else (lp 'start nested-level)))) + ((read-sharp) (case (next-char) +@@ -151,18 +153,16 @@ the archive of the mailing list. + (else (lp 'start nested-level))))))) +

    + +-

    A SRFI 22 script to remove nested multi-line comments is ++

    A SRFI 22 script to remove nested multi-line comments is + available at + +- http://srfi.schemers.org/srfi-30/remove-srfi30-comments-script.scm. ++ https://srfi.schemers.org/srfi-30/remove-srfi30-comments-script.scm. + + The script will read a Scheme program containing nested + multi-line comments from standard input and emit the same + programs with the comments removed to standard output. The + script mimics the Scheme 48 reader and uses the +- error procedure from SRFI 23.

    ++ error procedure from SRFI 23.

    + +

    A number of Scheme implemenations already support this SRFI: + Chez Scheme, Chicken, Gambit-C, Kawa, MIT Scheme, MzScheme and +@@ -171,7 +171,7 @@ the archive of the mailing list. + implementations, Scheme 48 and Guile do not support this SRFI + yet.

    + +-

    Copyright

    ++

    Copyright

    +

    Copyright (C) Martin Gasbichler (2002). All Rights Reserved.

    + +

    +@@ -199,12 +199,11 @@ the archive of the mailing list. +

    + + +-
    +-
    Editor: Mike Sperber
    ++
    ++
    Editor: Mike Sperber
    + + +-Last modified: Sun Sep 1 17:14:55 MST 2002 ++Last modified: Sun Jan 28 13:40:31 MET 2007 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-31.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-31.html +index faf6eb9..dd8dc91 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-31.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-31.html +@@ -1,306 +1,319 @@ +- +- ++ ++ + +- ++ ++ + SRFI 31: A special form `rec' for recursive evaluation ++ ++ ++ + + + + +-

    Title

    ++

    SRFI 31: A special form rec for recursive evaluation

    + +-SRFI 31: A special form rec for recursive evaluation ++

    by Mirko Luedde

    ++

    This copy of the SRFI 31 specification document ++is distributed as part of the Racket package ++srfi-doc.

    The canonical source of this document is ++https://srfi.schemers.org/srfi-31/srfi-31.html.

    + +-

    Author

    ++

    Status

    + +-Mirko Luedde <Mirko.Luedde@SAP.com> ++

    This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-31@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

    ++
      ++
    • Draft: 2002-05-24--2002-08-24
    • ++
    • Revised: 2002-08-12
    • ++
    • Final: 2002-12-02
    • ++
    + +-

    Status

    +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +- +-You can access the discussion via the +-archive of the mailing list. +- +-
      +-
    • Draft: 2002/05/24-2002/08/24
    • +-
    • Revised: 2002/08/12
    • +-
    • Final: 2002/12/02
    • +-
    +- +-

    Abstract

    ++

    Abstract

    + + We propose the implementation of a special form +-called rec. This form is a generalization and +-combination of the forms rec and +-named-lambda of [Clinger1985]. It allows the simple and ++called rec. This form is a generalization and ++combination of the forms rec and ++named-lambda of [Clinger1985]. It allows the simple and + non-imperative construction of self-referential expressions. As an + important special case, it extends the A. Church form +-lambda such that it allows the direct definition of ++lambda such that it allows the direct definition of + recursive procedures without using further special forms like +-let or letrec, without using advanced ++let or letrec, without using advanced + constructions like the H. B. Curry combinator and, unlike +-define, without introducing variable bindings into the ++define, without introducing variable bindings into the + external environment. + +-

    Rationale

    ++

    Rationale

    + +-

    General

    Among the prominent features of the Scheme +-programming language as defined in [KCR1998] ++

    General

    Among the prominent features of the Scheme ++programming language as defined in [KCR1998] + are the following. + +-
      ++
        + +-
      1. It has simple syntax.
      2. ++
      3. It has simple syntax.
      4. + +-
      5. It encourages recursive definitions, e.g. by ensuring memory +- efficient tail recursion.
      6. ++
      7. It encourages recursive definitions, e.g. by ensuring memory ++ efficient tail recursion.
      8. + +-
      9. It supports non-imperative programming.
      10. ++
      11. It supports non-imperative programming.
      12. + +-
      ++
    + + Nevertheless Scheme does not provide a syntax for recursive + evaluations with the properties of + +-
      ++
        + +-
      1. being as simple, intuitive and close to the mathematical standard +-notation as possible,
      2. ++
      3. being as simple, intuitive and close to the mathematical standard ++notation as possible,
      4. + +-
      5. allowing general recursion,
      6. ++
      7. allowing general recursion,
      8. + +-
      9. being non-imperative.
      10. ++
      11. being non-imperative.
      12. + +-
      ++
    + +-

    Example

    +- +-

    Problem 1

    ++

    Example

    + ++

    Problem 1

    ++

    + Let us look at the factorial function. In mathematical notation this + function is expressed as +- +-

     
    +-  (F : N |--> 1,            if N = 0; 
    ++

    ++
     
    ++  (F : N |--> 1,            if N = 0; 
    +               N * F(N - 1), otherwise).
    +-
    +- ++
    ++

    + This expression is a term and not a definition or proposition. +- +-

    We investigate some approaches to express the factorial function in +-Scheme. +- +-

      +- +-
    • ++

      ++

      ++We investigate some approaches to express the factorial function in Scheme. ++

      ++
        ++
      • ++

        + The simplest way perhaps is as +- +-

        ++

        ++
        + (define (F N) 
        +   (if (zero? N) 1 
        +     (* N (F (- N 1)))))
        +-
        +- ++
        ++

        + But this expression is not a term. It binds the factorial function to + the variable F. The expression itself may not occur in a +-syntactical context where a name of the factorial is required.

      • +- +-
      • ++syntactical context where a name of the factorial is required. ++

        ++
      • ++
      • ++

        + We list several ways to express the factorial as a function term. +- +-

          +- +-
        1. +-
          ++

          ++
            ++
          1. ++
            + (let () 
            +   (define (F N)
            +     (if (zero? N) 1 
            +         (* N (F (- N 1)))))
            +     F)
            +-
            +-
          2. +- +-
          3. +-
            ++
            ++
          4. ++
          5. ++
            + (lambda (N) 
            +   (let F ( (N N) ) 
            +        (if (zero? N) 1 
            + 	 (* N (F (- N 1))))))
            +-
            +-
          6. ++
          ++
        2. + +-
        3. +-
          ++
        4. ++
          + (letrec ( (F (lambda (N) 
          + 	       (if (zero? N) 1 
          + 		 (* N (F (- N 1)))))) )	F)
          +-
          +-
        5. ++
          ++
        6. + +-
        7. +-
          ++
        8. ++
          + ((lambda (F) 
          +    (F F))
          +  (lambda (G) 
          +    (lambda (N) 
          +      (if (zero? N) 1 
          +        (* N ((G G) (- N 1)))))))
          +-
          +-
        9. +- +-
        ++
    ++ + ++ ++

    + All these expressions define the factorial anonymously, not binding it + to a variable. However, all these expressions are more verbose than it + seems necessary and they are less intuitive than it seems +-desirable. +- +- ++desirable. ++

    ++ + +-

    Solution 1

    ++ + +-A solution to our problem was already provided in [Clinger1985] by the form +-named-lambda. An even earlier solution with a slightly ++

    Solution 1

    ++

    ++A solution to our problem was already provided in [Clinger1985] by the form ++named-lambda. An even earlier solution with a slightly + different syntax was implemented in Kent Dybvig's Chez Scheme system. +- ++

    + Using this special form, we can denote the factorial simply by +- +-

    ++

    ++
    + (named-lambda (F N) 
    +               (if (zero? N) 1 
    +                 (* N (F (- N 1)))))
    +-
    +- ++
    ++

    + This expression is a function term that denotes the factorial in the + appropriate brevity. + +-

    However, the form named-lambda has been dropped from ++

    However, the form named-lambda has been dropped from + later versions of the Scheme Report. Also it is missing in + state-of-the-art implementations such as Chez Scheme (6.0a) and MIT + Scheme (7.7.0). (The latter actually knows a form +-named-lambda with different semantics). ++named-lambda with different semantics). ++

    + +-

    Problem 2

    ++

    Problem 2

    + + The constant stream of ones can be defined via + +-
    (define S (cons 1 (delay S)))
    ++
    (define S (cons 1 (delay S)))
    + + As in the case of the factorial, we are able to define the recursive + object at the price of spending an externally bound name. Remedying +-this with let or letrec leads to similar ++this with let or letrec leads to similar + objections as above. + +-

    Solution 2

    +- ++

    Solution 2

    ++

    + This particular case of the self-referential problem was solved by the +-rec form in [Clinger1985]. +- ++rec form in [Clinger1985]. ++

    + This form allows writing +- +-

    (rec S (cons 1 (delay S)))
    +- ++

    ++
    (rec S (cons 1 (delay S)))
    ++

    + This expression is non-imperative and does not introduce an external + variable binding. + +-

    Also this form has been dropped from later versions of the Scheme ++

    Also this form has been dropped from later versions of the Scheme + Report. Moreover, from our point of view this form alone is not + capable of solving Problem 1. The respective definition would look + like +- +-

    ++

    ++
    + (rec F 
    +      (lambda (N) 
    +        (if (zero? N) 1 
    + 	 (* N (F (- N 1))))))
    +-
    +- ++
    ++

    + This again does not seem quite as simple and intuitive as the + mathematical notation. ++

    + +-

    Proposal

    ++

    Proposal

    + +-We therefore propose to implement the rec special form in ++We therefore propose to implement the rec special form in + a generalized way that combines the advantages of the +-named-lambda and rec forms. ++named-lambda and rec forms. + + The factorial function could be written +-
    ++
    + (rec (F N) 
    +      (if (zero? N) 1 
    +        (* N (F (- N 1)))))
    +-
    ++
    + +-

    Specification

    ++

    Specification

    + +-

    Syntax

    ++

    Syntax

    + +-The following production rules are to be added to those of [KCR1998] (we reuse names of non-terminals). ++The following production rules are to be added to those of [KCR1998] (we reuse names of non-terminals). + +-
      ++
        + +-
      1. <derived expression> --> <rec expression>
      2. ++
      3. <derived expression> --> <rec expression>
      4. + +-
      5. <rec expression> --> (rec <variable> +-<expression>)
      6. ++
      7. <rec expression> --> (rec <variable> ++<expression>)
      8. + +-
      9. <rec expression> --> (rec (<variable>+) +-<body>)
      10. ++
      11. <rec expression> --> (rec (<variable>+) ++<body>)
      12. + +-
      ++
    + +-

    Semantics

    ++

    Semantics

    + +-Scheme versions such as [KCR1998] providing +-define-syntax, syntax-rules, +-letrec and lambda might implement +-rec as follows. ++Scheme versions such as [KCR1998] providing ++define-syntax, syntax-rules, ++letrec and lambda might implement ++rec as follows. + +-
    ++
    + (define-syntax rec
    +   (syntax-rules ()
    +     ((rec (NAME . VARIABLES) . BODY)
    +      (letrec ( (NAME (lambda VARIABLES . BODY)) ) NAME))
    +     ((rec NAME EXPRESSION)
    +      (letrec ( (NAME EXPRESSION) ) NAME))))
    +-
    ++
    + +-

    Test

    ++

    Test

    + +-The following session shows in which way rec allows a ++The following session shows in which way rec allows a + tail-recursive implementation of the factorial function. + +-
    +-> (define F (rec (F N)
    ++
    ++> (define F (rec (F N)
    + 		((rec (G K L)
    + 		   (if (zero? K) L
    + 		     (G (- K 1) (* K L)))) N 1)))
    +-> F
    ++> F
    + #<procedure>
    +-> (F 0)
    ++> (F 0)
    + 1
    +-> (F 10)
    ++> (F 10)
    + 3628800
    +-
    ++
    + +-

    Acknowledgements

    ++

    Acknowledgements

    + + The author thanks Al Petrofsky for the final solution and Hal Abelson, + Chris Hanson and others for their input. The work of the maintainers + of the SRFI forum is highly appreciated. + +-

    Bibliography

    ++

    Bibliography

    + +- + +-

    Copyright

    ++

    Copyright

    + +

    Copyright (C) Dr. Mirko Luedde (2002). All Rights Reserved.

    + +@@ -350,11 +362,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

    + +-
    ++
    + +-
    Author: Mirko Luedde
    ++
    Author: Mirko Luedde
    + +-
    Editor: Francisco Solsona
    ++
    Editor: Francisco Solsona
    + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-34.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-34.html +index aa46757..144337e 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-34.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-34.html +@@ -1,82 +1,131 @@ +- +- ++ ++ + +-SRFI 34: Exception Handling for Programs ++ ++ ++ SRFI 34: Exception Handling for Programs ++ ++ ++ + + + +-

    Title

    ++

    SRFI 34: Exception Handling for Programs

    + +-SRFI 34: Exception Handling for Programs ++

    by Richard Kelsey and Michael Sperber

    ++

    This copy of the SRFI 34 specification document ++is distributed as part of the Racket package ++srfi-doc.

    The canonical source of this document is ++https://srfi.schemers.org/srfi-34/srfi-34.html.

    + +-

    Authors

    ++

    Status

    + +-Richard Kelsey and Michael Sperber ++

    This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-34@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

    + +-

    Status

    +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. It will +-remain in draft until 2002-10-20, or as amended. to provide input on +-this SRFI, please mail to +- +-srfi-34@srfi.schemers.org. +-See +-instructions here to subscribe to the list. You can access +-the discussion via +- +-the archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +- +-
      +-
    • Draft: 2002/07/24-2002/10/20
    • +-
    • Revised: 2002/09/20
    • +-
    • Final: 2002/12/1
    • +-
    • Fixed reference implementation: 2003/03/10
    • +-
    ++
      ++
    • Draft: 2002-07-24--2002-10-20
    • ++
    • Revised: 2002-09-20
    • ++
    • Final: 2002-12-01
    • ++
    • Revised to fix errata: ++
        ++
      • 2003-03-10
      • ++
      • 2018-01-13 (missing test in guard-aux implementation)
      • ++
      ++
    • ++
    + +-

    Abstract

    +-This SRFI defines exception-handling and exception-raising constructs for Scheme, including
    • a with-exception-handler +- procedure and a guard +- form for installing exception-handling procedures,
    • +-
    • a raise +- procedure for invoking the current exception handler.
    • ++

      Abstract

      ++

      ++ This SRFI defines exception-handling and exception-raising constructs for Scheme, including ++

      ++
        ++
      • a with-exception-handler ++ procedure and a guard ++ form for installing exception-handling procedures, ++
      • ++
      • a raise ++ procedure for invoking the current exception handler. ++
      • +
      +-

      This SRFI is based on (withdrawn) SRFI 12: Exception Handling +-by William Clinger, R. Kent Dybvig, Matthew Flatt, and Marc Feeley.

      +-

      Rationale

      +-

      The goals of the exception mechanism specified in this SRFI are to help programmers share code which relies on exception handling, and to be easily added to existing Scheme systems.

      +-

      This SRFI is primarily useful in conjunction with one or more companion SRFIs:

      +-
      • a SRFI specifying exception-describing objects (conditions). An example is SRFI 35 +- (Conditions).
      • +-
      • a SRFI specifying a set of standard condition types to be raised by the primitives provided by the Scheme implementation, and requiring that certain Scheme primitives indeed raise exceptions within the framework described. An example is SRFI 36 +- (I/O Conditions).
      • +-
      • a SRFI specifying how computations may be resumed after an exception is raised.
      • ++

        ++ This SRFI is based on (withdrawn) ++ SRFI 12: Exception Handling ++ by William Clinger, R. Kent Dybvig, Matthew Flatt, and Marc Feeley. ++

        ++

        Rationale

        ++

        ++ The goals of the exception mechanism specified in this SRFI are to ++ help programmers share code which relies on exception handling, and ++ to be easily added to existing Scheme systems. ++

        ++

        ++ This SRFI is primarily useful in conjunction with one or more companion SRFIs: ++

        ++
          ++
        • ++ a SRFI specifying exception-describing objects (conditions). An ++ example is SRFI 35 ++ (Conditions). ++
        • ++
        • ++ a SRFI specifying a set of standard condition types to be raised ++ by the primitives provided by the Scheme implementation, and ++ requiring that certain Scheme primitives indeed raise exceptions ++ within the framework described. An example ++ is SRFI 36 (I/O ++ Conditions). ++
        • ++
        • ++ a SRFI specifying how computations may be resumed after an exception is raised. ++
        • +
        +-

        Specification

        ++

        Specification

        +

        Exception handlers are one-argument procedures that determine the action the program takes when an exceptional situation is signalled. The system implicitly maintains a current exception handler.

        +

        The program raises an exception by invoking the current exception handler, passing to it an object encapsulating information about the exception. Any procedure accepting one argument may serve as an exception handler and any object may be used to represent an exception.

        +

        The system maintains the current exception handler as part of the dynamic environment of the program, akin to the current input or output port, or the context for dynamic-wind. The dynamic environment can be thought of as that part of a continuation that does not specify the destination of any returned values. It includes the current input and output ports, the dynamic-wind + context, and this SRFI's current exception handler. See the reference implementation for portable definitions of current-dynamic-environment + and with-dynamic-environment.

        +

        The initial current exception handler of the program is implementation-dependent. However, it should interrupt the program in some way visible to the user, either by aborting it, invoking a debugger, or some similar action.

        +-

        Establishing Exception Handlers

        +-
        (with-exception-handler handler +- thunk)
        +-

        Returns the result(s) of invoking thunk. Handler +- must be a procedure that accepts one argument. It is installed as the current exception handler for the dynamic extent (as determined by dynamic-wind) of the invocation of thunk.

        ++

        Establishing Exception Handlers

        ++
        ++
        (with-exception-handler handler ++thunk)
        ++
        ++

        ++ Returns the result(s) of ++ invoking thunk. Handler must be a procedure ++ that accepts one argument. It is installed as the current ++ exception handler for the dynamic extent (as determined ++ by dynamic-wind) of the invocation ++ of thunk. ++

        +
        +
        +-
        (guard ( ++ ++
        ++
        (guard ( + <var> <clause1 + > <clause2 + > ...) +- <body>) (syntax)
        +-

        Syntax: ++<body>) (syntax) ++

        ++
        ++

        Syntax: + Each <clause> should have the same form as a cond + clause

        +

        Semantics: +@@ -91,17 +140,28 @@ by William Clinger, R. Kent Dybvig, Matthew Flatt, and Marc Feeley.

        + expression.

        +
        +
        +-

        Raising Exceptions

        +-
        (raise obj)
        +-

        Invokes the current exception handler on obj. The handler is called in the dynamic environment of the call to raise, except that the current exception handler is that in place for the call to with-exception-handler +- that installed the handler being called. The handler's continuation is otherwise unspecified.

        ++ ++

        Raising Exceptions

        ++
        ++
        (raise obj) ++
        ++
        ++

        ++ Invokes the current exception handler on obj. The handler ++ is called in the dynamic environment of the call ++ to raise, except that the current exception handler is ++ that in place for the call to with-exception-handler ++ that installed the handler being called. The handler's continuation ++ is otherwise unspecified. ++

        +
        +
        +-

        Examples

        ++ ++

        Examples

        +
        (call-with-current-continuation
        +  (lambda (k)
        +    (with-exception-handler (lambda (x)
        +-                             (display "condition: ")
        ++                             (display "condition: ")
        +                              (write x)
        +                              (newline)
        +                              (k 'exception))
        +@@ -113,7 +173,7 @@ PRINTS: condition: an-error
        + (call-with-current-continuation
        +  (lambda (k)
        +    (with-exception-handler (lambda (x)
        +-                             (display "something went wrong")
        ++                             (display "something went wrong")
        +                              (newline)
        +                              'dont-care)
        +      (lambda ()
        +@@ -123,7 +183,7 @@ then behaves in an unspecified way
        + 
        + (guard (condition
        +          (else
        +-          (display "condition: ")
        ++          (display "condition: ")
        +           (write condition)
        +           (newline)
        +           'exception))
        +@@ -133,7 +193,7 @@ PRINTS: condition: an-error
        + 
        + (guard (condition
        +          (else
        +-          (display "something went wrong")
        ++          (display "something went wrong")
        +           (newline)
        +           'dont-care))
        +  (+ 1 (raise 'an-error)))
        +@@ -143,7 +203,7 @@ PRINTS: something went wrong
        + (call-with-current-continuation
        +  (lambda (k)
        +    (with-exception-handler (lambda (x)
        +-                             (display "reraised ") (write x) (newline)
        ++                             (display "reraised ") (write x) (newline)
        +                              (k 'zero))
        +      (lambda ()
        +        (guard (condition
        +@@ -155,7 +215,7 @@ PRINTS: something went wrong
        + (call-with-current-continuation
        +  (lambda (k)
        +    (with-exception-handler (lambda (x)
        +-                             (display "reraised ") (write x) (newline)
        ++                             (display "reraised ") (write x) (newline)
        +                              (k 'zero))
        +      (lambda ()
        +        (guard (condition
        +@@ -167,7 +227,7 @@ PRINTS: something went wrong
        + (call-with-current-continuation
        +  (lambda (k)
        +    (with-exception-handler (lambda (x)
        +-                             (display "reraised ") (write x) (newline)
        ++                             (display "reraised ") (write x) (newline)
        +                              (k 'zero))
        +      (lambda ()
        +        (guard (condition
        +@@ -188,13 +248,14 @@ PRINTS: reraised 0
        +          ((assq 'b condition)))
        +   (raise (list (cons 'b 23))))
        + => (b . 23)
        +-

        Reference Implementation

        +-

        The reference implementation makes use of SRFI 9 +- ("Defining Record Types"), and SRFI 23 +- ("Error reporting mechanism").

        ++
    ++

    Reference Implementation

    ++

    The reference implementation makes use of SRFI 9 ++ ("Defining Record Types"), and SRFI 23 ++ ("Error reporting mechanism").

    +
    (define *current-exception-handlers*
    +   (list (lambda (condition)
    +-          (error "unhandled exception" condition))))
    ++          (error "unhandled exception" condition))))
    + 
    + (define (with-exception-handler handler thunk)
    +   (with-exception-handlers (cons handler *current-exception-handlers*)
    +@@ -214,7 +275,7 @@ PRINTS: reraised 0
    +     (with-exception-handlers (cdr handlers)
    +       (lambda ()
    +         ((car handlers) obj)
    +-        (error "handler returned"
    ++        (error "handler returned"
    +                (car handlers)
    +                obj)))))
    + 
    +@@ -255,7 +316,7 @@ PRINTS: reraised 0
    +            (result temp)
    +            (guard-aux reraise clause1 clause2 ...))))
    +     ((guard-aux reraise (test))
    +-     test)
    ++     (or test reraise))
    +     ((guard-aux reraise (test) clause1 clause2 ...)
    +      (let ((temp test))
    +        (if temp
    +@@ -269,10 +330,11 @@ PRINTS: reraised 0
    +      (if test
    +          (begin result1 result2 ...)
    +          (guard-aux reraise clause1 clause2 ...)))))
    +-

    References

    +-
    • SRFI 12: Exception Handling ++ ++

      References

      ++ + +-

      Copyright

      ++

      Copyright

      + +

      Copyright (C) Richard Kelsey, Michael Sperber (2002). All Rights + Reserved.

      +@@ -321,6 +383,6 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

      + +-
      +-
      Editor: Francisco Solsona
      ++
      ++
      Editor: Francisco Solsona
      + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-35.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-35.html +index de261a8..a369fca 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-35.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-35.html +@@ -1,71 +1,73 @@ +- +-SRFI 35: Conditions +-

      Title

      +- +-Conditions +- +-

      Authors

      +- +-Richard Kelsey and Michael Sperber +- +-

      Status

      +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. It will +-remain in draft until 2002-10-20, or as amended. to provide input on +-this SRFI, please mail to +- +-srfi minus 35 at srfi dot schemers dot org. +-See +-instructions here to subscribe to the list. You can access +-the discussion via +- +-the archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. ++ ++ ++ ++ ++ ++ SRFI 35: Conditions ++ ++ ++ ++ ++ ++ ++

      SRFI 35: Conditions

      ++ ++

      by Richard Kelsey and Michael Sperber

      ++

      This copy of the SRFI 35 specification document ++is distributed as part of the Racket package ++srfi-doc.

      The canonical source of this document is ++https://srfi.schemers.org/srfi-35/srfi-35.html.

      ++ ++

      Status

      ++ ++

      This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-35@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

      + +
        +-
      • Draft: 2002/07/24-2002/10/20
      • +-
      • Revised: 2002/09/20
      • +-
      • Final: 2002/12/1
      • ++
      • Draft: 2002-07-24--2002-10-20
      • ++
      • Revised: 2002-09-20
      • ++
      • Final: 2002-12-01
      • +
      + +-

      Abstract

      +-

      The SRFI defines constructs for creating and inspecting condition +-types and values. A condition value encapsulates information about an +-exceptional situation, or exception. This SRFI also defines a few basic +-condition types.

      +-

      Rationale

      +-

      Conditions are values that communicate information about exceptional +-situations between parts of a program. Code that detects an exception +-may be in a different part of the program than the code that handles +-it. In fact, the former may have been written independently from the +-latter. Consequently, to facilitate effective handling of exceptions, +-conditions must communicate as much information as possible as +-accurately as possible, and still allow effective handling by code that +-did not precisely anticipate the nature of the exception that occurred.

      +-

      This SRFI provides two mechanisms to enable this kind of communication

      • subtyping among condition types allows handling code to determine the general +- nature of an exception even though it does not anticipate its exact +- nature,
      • +-
      • compound conditions allow an exceptional situation to be described in multiple ways.
      • ++

        Abstract

        ++

        The SRFI defines constructs for creating and inspecting condition types and values. A condition value encapsulates information about an exceptional situation, or exception. This SRFI also defines a few basic condition types.

        ++

        Rationale

        ++

        Conditions are values that communicate information about exceptional situations between parts of a program. Code that detects an exception may be in a different part of the program than the code that handles it. In fact, the former may have been written independently from the latter. Consequently, to facilitate effective handling of exceptions, conditions must communicate as much information as possible as accurately as possible, and still allow effective handling by code that did not precisely anticipate the nature of the exception that occurred.

        ++

        This SRFI provides two mechanisms to enable this kind of communication

        ++
          ++
        • ++ subtyping among condition types allows handling code to determine ++ the general nature of an exception even though it does ++ not anticipate its exact nature, ++
        • ++
        • ++ compound conditions allow an exceptional situation to be described ++ in multiple ways. ++
        • +
        +-

        +-

        Specification

        +-

        Conditions are records with named fields. Each condition belongs to one or more condition types. +-Each condition type specifies a set of field names. A condition +-belonging to a condition type includes a value for each of the type's +-field names. These values can be extracted from the condition by using +-the appropriate field name.

        ++ ++

        Specification

        ++

        Conditions are records with named fields. Each condition belongs to one or more condition types. Each condition type specifies a set of field names. A condition belonging to a condition type includes a value for each of the type's field names. These values can be extracted from the condition by using the appropriate field name.

        +

        There is a tree of condition types with the distinguished &condition + as its root. All other condition types have a parent condition type.

        +-

        A condition belonging to several condition types with a common +-supertype may have distinct values for the supertype's fields for each +-type. The type used to access a field determines which of the values is +-returned. The program can extract each of these field values separately.

        +-

        Procedures

        +-
        (make-condition-type id ++

        A condition belonging to several condition types with a common supertype may have distinct values for the supertype's fields for each type. The type used to access a field determines which of the values is returned. The program can extract each of these field values separately.

        ++

        Procedures

        ++
        ++
        (make-condition-type id + parent + field-names)
        +

        Make-condition-type +@@ -145,27 +147,28 @@ returns a condition of condition type condition-type + is a compound condition, extract-condition + extracts the field values from the subcondition belonging to condition-type + that appeared first in the call to make-compound-condition +- that created the condition. The returned condition may be newly created; it is possible for

        (let* ((&c (make-condition-type 'c &condition '()))
        ++ that created the the condition. The returned condition may be newly created; it is possible for
        ++

        ++
        (let* ((&c (make-condition-type 'c &condition '()))
        +        (c0 (make-condition &c))
        +        (c1 (make-compound-condition c0)))
        +   (eq? c0 (extract-condition c1 &c)))
        +-
        to return false.

        ++
        ++

        to return false.

        +
        +
        +-

        Macros

        +-
        (define-condition-type <condition-type> <supertype> <predicate> <field-spec> ...)
        ++ ++

        Macros

        ++
        ++
        (define-condition-type <condition-type> <supertype> <predicate> <field-spec> ...)
        +

        This defines a new condition type. <Condition-type>, <supertypes>, and <predicate> must all be identifiers. Define-condition-type +-defines an identifier <condition-type> to some value describing +-the condition type. <supertype> must be the name of a previously +-defined condition type.

        +-

        Define-condition-type also defines <predicate> to +-a predicate that identifies conditions associated with that type, or +-with any of its subtypes.

        ++ defines an identifier <condition-type> to some value describing the condition type. <supertype> must be the name of a previously defined condition type.

        ++

        Define-condition-type ++ also defines <predicate> to a predicate that identifies conditions associated with that type, or with any of its subtypes.

        +

        Each <field-spec> must be of the form ( + <field> <accessor>) + where both <field> and <accessor> must be identifiers. Define-condition-type +-defines each <accessor> to a procedure which extracts the value +-of the named field from a condition associated with this condition type.

        ++ defines each <accessor> to a procedure which extracts the value of the named field from a condition associated with this condition type.

        +
        +
        (condition <type-field-binding> ...)
        +

        This creates a condition value. Each <type-field-binding> must be of the form ( +@@ -173,9 +176,7 @@ of the named field from a condition associated with this condition type.

        + Each <field-binding> must be of the form ( + <field> <exp>) + where <field> is a field identifier from the definition of <condition-type>.

        +-

        The <exp> are evaluated in some unspecified order; their +-values can later be extracted from the condition object via the +-accessors of the associated condition types or their supertypes.

        ++

        The <exp> are evaluated in some unspecified order; their values can later be extracted from the condition object via the accessors of the associated condition types or their supertypes.

        +

        The condition returned by condition + is created by a call of form

        +
        (make-compound-condition
        +@@ -184,47 +185,47 @@ accessors of the associated condition types or their supertypes.

        +

        with the condition types retaining their order from thecondition + form. The field names and values are duplicated as necessary as described below.

        +

        Each <type-field-binding> must contain field bindings for all +-fields of <condition-type> without duplicates. There is an +-exception to this rule: if a field binding is missing, and the field +-belongs to a supertype shared with one of the other +-<type-field-binding> subforms, then the value defaults to that of +-the first such binding in the condition ++ fields of <condition-type> without duplicates. There is an exception to this rule: if a field binding is missing, and the field belongs to a supertype shared with one of the other <type-field-binding> subforms, then the value defaults to that of the first such binding in the condition + form.

        +
        +
        +-

        Standard Conditions

        +-
        &condition ++ ++

        Standard Conditions

        ++
        ++
        &condition +
        +

        This is the root of the entire condition type hierarchy. It has a no fields.

        +
        +
        &message +
        +-

        This condition type could be defined by

        (define-condition-type &message &condition
        ++

        This condition type could be defined by

        ++
        (define-condition-type &message &condition
        +   message-condition?
        +   (message condition-message))
        +-

        ++
        +

        It carries a message further describing the nature of the condition to humans.

        +
        +
        &serious +
        +-

        This condition type could be defined by

        (define-condition-type &serious &condition
        ++

        This condition type could be defined by

        ++
        (define-condition-type &serious &condition
        +   serious-condition?)
        +-

        +-

        This type describes conditions serious enough that they cannot +-safely be ignored. This condition type is primarily intended as a +-supertype of other condition types.

        +-
        &error ++
        ++

        This type describes conditions serious enough that they cannot safely be ignored. This condition type is primarily intended as a supertype of other condition types.

        ++
        ++
        &error +
        +-

        This condition type could be defined by

        (define-condition-type &error &serious
        ++

        This condition type could be defined by ++

        ++
        (define-condition-type &error &serious
        +   error?)
        +-

        +-

        This condition describes errors, typically caused by something that +-has gone wrong in the interaction of the program with the external +-world or the user.

        ++
        ++

        This condition describes errors, typically caused by something that has gone wrong in the interaction of the program with the external world or the user.

        +
        +- +
        +-

        Examples

        ++ ++ ++

        Examples

        +
        (define-condition-type &c &condition
        +   c?
        +   (x c-x))
        +@@ -284,10 +285,11 @@ world or the user.

        + (c-x v5) => "V2" + (c1-a v5) => "a3" + (c2-b v5) => "b2" +-

        Reference Implementation

        +-

        The reference implementation makes use of SRFI 1 +- ("List Library"), SRFI 9 +- ("Defining Record Types"), and SRFI 23 ++ ++

        Reference Implementation

        ++

        The reference implementation makes use of SRFI 1 ++ ("List Library"), SRFI 9 ++ ("Defining Record Types"), and SRFI 23 + ("Error reporting mechanism").

        +
        (define-record-type :condition-type
        +   (really-make-condition-type name supertype fields all-fields)
        +@@ -463,15 +465,16 @@ world or the user.

        + + (define-condition-type &error &serious + error?) +-

        References

        +-
        • SRFI 12: Exception Handling ++ ++

          References

          ++ + +-

          Copyright

          ++

          Copyright

          + +

          Copyright (C) Richard Kelsey, Michael Sperber (2002). All Rights + Reserved.

          +@@ -509,7 +512,6 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

          + +-
          ++
          +
          Editor: Francisco Solsona
          +- + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-38.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-38.html +index 378fbd2..535754c 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-38.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-38.html +@@ -1,61 +1,74 @@ +- +- ++ ++ + ++ ++ + SRFI 38: External Representation for Data With Shared Structure ++ ++ ++ + + + + +-

          Title

          ++

          SRFI 38: External Representation for Data With Shared Structure

          + +-External Representation for Data With Shared Structure ++

          by Ray Dillinger

          ++

          This copy of the SRFI 38 specification document ++is distributed as part of the Racket package ++srfi-doc.

          The canonical source of this document is ++https://srfi.schemers.org/srfi-38/srfi-38.html.

          + +-

          Author

          ++

          Status

          + +-Ray Dillinger ++

          This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-38@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

          ++
            ++
          • Draft: 2002-12-20--2003-04-02
          • ++
          • Final: 2003-04-02
          • ++
          + +-

          Status

          +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +-You can access +-the discussion via +- +-the archive of the mailing list. +- +-
            +-
          • Draft: 2002/12/20-2003/04/02
          • +-
          • Final: 2003/04/02
          • +-
          +- +-

          Abstract

          +-

          ++

          Abstract

          ++

          + This SRFI proposes (write-with-shared-structure) and + (read-with-shared-structure), procedures for writing + and reading external representations of data containing shared + structure. These procedures implement a proposed standard + external notation for data containing shared structure. +-

          +-

          ++

          ++

          + This SRFI permits but does not require replacing the standard + (write) and (read) functions. These functions + may be implemented without the overhead in time and space required + to detect and specify shared structure. +-

          +-

          ++

          ++

          + An implementation conforms to this SRFI if it provides procedures + named (write-with-shared-structure) and + (read-with-shared-structure), which produce and read + the same notation as produced by the reference implementation. + It may also provide (read/ss) and (write/ss), + equivalent functions with shorter names. +-

          ++

          + + +-

          Rationale

          ++

          Rationale

          + +-

          ++

          + + R5RS scheme and IEEE scheme provide the procedure (write), + which prints machine-readable representations of lists and other +@@ -65,8 +78,8 @@ case of self-referential objects the behavior of (write) + itself is undefined; it is permitted to go into an infinite loop or + invoke the dreaded curse of the nasal demons. + +-

          +-

          ++

          ++

          + + For example, it is possible to have a list within which two or more + members are the same string (in the sense of (eq?)), but when +@@ -75,17 +88,18 @@ representation to recover the (eq?) relationship. When the + list is read back in, there will be two or more copies of the string + which are (eqv?) but not (eq?). + +-

          +-

          ++

          ++

          + As an example of the second problem, The results of evaluating +-

          ++

          ++
          + (begin (define a (cons 'val1 'val2))
          +        (set-cdr! a a)
          +        (write a))
          +-
          ++
          + +-are undefined; in R5RS parlance, calling write on such a structure +-"is an error", but not one that is necessarily ++

          are undefined; in R5RS parlance, calling write on such a structure ++"is an error", but not one that is necessarily + signalled. The routine is permitted to print a nonstandard notation + such as the one proposed in this standard or a different one, fail + silently, signal an error, go into an infinite loop, or make demons +@@ -95,33 +109,34 @@ problem by providing a method of writing data which is guaranteed to + be well-behaved and predictable even on data containing shared + structures. + +-

          ++

          + +-

          ++

          + + The extended functionality described below in the implementation of + (write-with-shared-structure)is already present in the + (write) function of several major scheme implementations + (PLT, SISC, Chez, Bigloo, MIT scheme, and possibly others). + +-

          ++

          + +-

          Specification

          +-

          ++

          Specification

          + +

          Formal Grammar of the New External Representation

          ++

          + This SRFI creates an alternative external representation for data + written and read under (write/ss) and (read/ss). + It is identical to the grammar for external representation for data + written and read under (write) and (read) given in + section 7 of R5RS, except that the single production +-

          ++

          ++
          + 
          + <datum> --> <simple datum> | <compound datum> 
          + 
          +-
          +-Is replaced by the following five productions. +-
          ++
          ++

          Is replaced by the following five productions.

          ++
          + 
          + <datum> --> <defining datum> | <nondefining datum> | <defined datum>
          + 
          +@@ -132,26 +147,25 @@ Is replaced by the following five productions.
          + <nondefining datum> --> <simple datum> | <compound datum> 
          + 
          + <indexnum> --> <digit 10>+
          +-
          +-

          ++
          + +

          New Procedures

          +-

          +-

          + 
          +-[[library procedure]] (write-with-shared-structure obj)
          ++
          ++
          ++[[library procedure]] (write-with-shared-structure obj)
          + [[library procedure]] (write-with-shared-structure obj port)
          + [[library procedure]] (write-with-shared-structure obj port optarg)
          + 
          +-
          +- ++
          ++

          + Writes a written representation of obj to the given port. Strings that + appear in the written representation are enclosed in doublequotes, and + within those strings backslash and doublequote characters are escaped + by backslashes. Character objects are written using the #\ + notation. + +-

          ++

          + + Objects which denote locations rather than values (cons cells, + vectors, and non-zero-length strings in R5RS scheme; also mutable +@@ -164,15 +178,15 @@ If objects which denote locations occur only once in the structure, + then (write-with-shared-structure) must produce the same + external representation for those objects as (write). + +-

          ++

          + +-

          ++

          + + Write-with-shared-structure must terminate in finite time when writing + finite data. Write-with-shared-structure must produce a finite + representation when writing finite data. + +-

          ++

          + + Write-with-shared-structure returns an unspecified value. The port + argument may be omitted, in which case it defaults to the value +@@ -184,30 +198,29 @@ still write a representation that can be read by + use optarg to specify formatting conventions, numeric radixes, or + return values. The reference implementation ignores optarg. + +-

          +-

          ++

          ++

          + +-For example, the code +-

          ++For example, the code

          ++
          + 
          + (begin (define a (cons 'val1 'val2))
          +        (set-cdr! a a)
          +        (write-with-shared-structure a))
          + 
          +-
          ++
          + +-should produce the output #1=(val1 . #1#) . This shows a cons ++

          should produce the output #1=(val1 . #1#) . This shows a cons + cell whose cdr contains itself. ++

          + +-

          +- +-

          ++
          + 
          +-[[library procedure]] (read-with-shared-structure)
          ++[[library procedure]] (read-with-shared-structure)
          + [[library procedure]] (read-with-shared-structure  port)
          + 
          +-
          +- ++
          ++

          + (read-with-shared-structure) converts the external + representations of Scheme objects produced by + (write-with-shared-structure) into scheme objects. That is, +@@ -217,7 +230,7 @@ external representation grammar defined above. + from the given input port, updating port to point to the first + character past the end of the external representation of the object. + +-

          ++

          + + If an end-of-file is encountered in the input before any characters + are found that can begin an object, then an end-of-file object is +@@ -228,20 +241,20 @@ the beginning of an object's external representation, but the external + representation is incomplete and therefore not parsable, an error is + signalled. + +-

          ++

          + + The port argument may be omitted, in which case it defaults to the + value returned by (current-input-port). It is an error to + read from a closed port. + +-

          ++

          + + + + +-

          Implementation

          ++

          Implementation

          + +-

          ++

          + + The reference implementation of (write-with-shared-structure) + is based on an implementation provided by Al Petrofsky. If there are +@@ -251,17 +264,17 @@ for an optional port argument. The reference implementation of + provided by Al Petrofsky. Both are used here with his generous + permission. + +-

          ++

          + +-

          ++

          + + Note that portability forces the reference implementation of + (write-with-shared-structure) to be O(N^2) but that if an + implementor tracks objects through additional fields hidden from R5RS + scheme, a more efficient implementation can be provided. + +-

          +-

          ++

          ++

          + + If all the locations in your scheme are mutable and you don't do any + locking or multithreading, you can write an O(n) version that +@@ -273,10 +286,10 @@ does not give the programmer access to mutability information nor to + comparison of constant data's addresses, but both of these are trivial + operations if you have access to the system's internals. + +-

          ++

          + + +-
          ++
          + ;;; A printer that shows all sharing of substructures.  Uses the Common
          + ;;; Lisp print-circle notation: #n# refers to a previous substructure
          + ;;; labeled with #n=.   Takes O(n^2) time.
          +@@ -354,7 +367,7 @@ operations if you have access to the system's internals.
          +     (define (scan obj alist)
          +       (cond ((not (interesting? obj)) alist)
          + 	    ((assq obj alist)
          +-             => (lambda (p) (if (cdr p) alist (acons obj #t alist))))
          ++             => (lambda (p) (if (cdr p) alist (acons obj #t alist))))
          + 	    (else
          + 	     (let ((alist (acons obj #f alist)))
          + 	       (cond ((pair? obj) (scan (car obj) (scan (cdr obj) alist)))
          +@@ -406,7 +419,7 @@ operations if you have access to the system's internals.
          + 	(if (eof-object? c)
          + 	    (error "EOF inside a string")
          + 	    (case c
          +-	      ((#\") (list->string (reverse chars)))
          ++	      ((#\") (list->string (reverse chars)))
          + 	      ((#\\) (read-it (cons (read-char*) chars)))
          + 	      (else (read-it (cons c chars))))))))
          + 
          +@@ -415,7 +428,7 @@ operations if you have access to the system's internals.
          +     (let iter ((chars '()))
          +       (let ((c (peek-char*)))
          + 	(if (or (eof-object? c) (not (pred c)))
          +-	    (list->string (reverse chars))
          ++	    (list->string (reverse chars))
          + 	    (iter (cons (read-char*) chars))))))
          + 
          +   ;; reads a character after the #\ has been read.
          +@@ -433,11 +446,11 @@ operations if you have access to the system's internals.
          +   (define (read-number first-char)
          +     (let ((str (string-append (string first-char)
          + 			      (read-some-chars not-delimiter?))))
          +-      (or (string->number str)
          ++      (or (string->number str)
          + 	  (error "Malformed number: " str))))
          + 
          +   (define char-standard-case
          +-    (if (char=? #\a (string-ref (symbol->string 'a) 0))
          ++    (if (char=? #\a (string-ref (symbol->string 'a) 0))
          + 	char-downcase
          + 	char-upcase))
          + 
          +@@ -449,10 +462,10 @@ operations if you have access to the system's internals.
          + 	(string-set! new i (char-standard-case (string-ref str i))))))
          + 
          +   (define (read-identifier)
          +-    (string->symbol (string-standard-case (read-some-chars not-delimiter?))))
          ++    (string->symbol (string-standard-case (read-some-chars not-delimiter?))))
          + 
          +   (define (read-part-spec)
          +-    (let ((n (string->number (read-some-chars char-numeric?))))
          ++    (let ((n (string->number (read-some-chars char-numeric?))))
          +       (let ((c (read-char*)))
          + 	(case c
          + 	  ((#\=) (cons 'decl n))
          +@@ -525,8 +538,8 @@ operations if you have access to the system's internals.
          + 	(if (char? (car first-token))
          + 	    (case (car first-token)
          + 	      ((#\() (read-list-tail))
          +-	      ((#\#) (list->vector (read-list-tail)))
          +-	      ((#\. #\)) (error (string-append "Unexpected \"" first-token "\"")))
          ++	      ((#\#) (list->vector (read-list-tail)))
          ++	      ((#\. #\)) (error (string-append "Unexpected \"" (string (car first-token)) "\"")))
          + 	      (else
          + 	       (list (caadr (assv (car first-token)
          + 				  '((#\' 'x) (#\, ,x) (#\` `x) (#\@ ,@x))))
          +@@ -542,7 +555,7 @@ operations if you have access to the system's internals.
          + 			((use)
          + 			 ;; To use a part, it must have been
          + 			 ;; declared before this chain started.
          +-			 (cond ((assv n starting-alist) => cdr)
          ++			 (cond ((assv n starting-alist) => cdr)
          + 			       (else (error "Use of undeclared part " n))))
          + 			((decl)
          + 			 (if (assv n parts-alist)
          +@@ -596,10 +609,10 @@ operations if you have access to the system's internals.
          + 		       (fill-in-parts elt))))))))
          +     obj))
          + 
          +-
          ++
          + + +-

          Copyright

          ++

          Copyright

          +

          Copyright (C) Ray Dillinger 2003. All Rights Reserved.

          + +

          +@@ -625,13 +638,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

          + +-
          +-
          Editor: David Rush
          ++
          ++
          Editor: David Rush
          + + +-Last modified: Wed Apr 2 19:58:58 BST 2003 ++Last modified: Wed Jan 19 08:52:24 MET 2011 + + + +- +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-39.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-39.html +index efd33ed..792b2aa 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-39.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-39.html +@@ -1,69 +1,82 @@ +- +- ++ ++ + ++ ++ + SRFI 39: Parameter objects ++ ++ ++ + + + + +-

          Title

          ++

          SRFI 39: Parameter objects

          + +-SRFI 39: Parameter objects ++

          by Marc Feeley

          ++

          This copy of the SRFI 39 specification document ++is distributed as part of the Racket package ++srfi-doc.

          The canonical source of this document is ++https://srfi.schemers.org/srfi-39/srfi-39.html.

          + +-

          Author

          ++

          Status

          + +-Marc Feeley ++

          This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-39@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

          ++
            ++
          • Draft: 2002-12-21--2003-02-18
          • ++
          • Revised: 2003-05-15
          • ++
          • Final: 2003-06-30
          • ++
          + +-

          Status

          + +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +-You can access +-previous messages via +- +-the archive of the mailing list. ++

          Abstract

          + +-
            +-
          • Draft: 2002/12/21-2003/02/18
          • +-
          • Revised: 2003/5/15
          • +-
          • Final: 2003/6/30
          • +-
          +- +- +-

          Abstract

          +- +-

          +-This SRFI defines parameter objects, the procedure +-make-parameter to +-create parameter objects and the parameterize special ++

          ++This SRFI defines parameter objects, the procedure ++make-parameter to ++create parameter objects and the parameterize special + form to dynamically bind parameter objects. In the dynamic + environment, each parameter object is bound to a cell containing the + value of the parameter. When a procedure is called the called + procedure inherits the dynamic environment from the caller. The +-parameterize special form allows the binding of a ++parameterize special form allows the binding of a + parameter object to be changed for the dynamic extent of its body. +-

          ++

          + +-

          Rationale

          ++

          Rationale

          + +-

          +-The dynamic environment is the structure which allows ++

          ++The dynamic environment is the structure which allows + the system to find the value returned by the R5RS procedures +-current-input-port and current-output-port. +-The R5RS procedures with-input-from-file and +-with-output-to-file extend the dynamic environment to ++current-input-port and current-output-port. ++The R5RS procedures with-input-from-file and ++with-output-to-file extend the dynamic environment to + produce a new dynamic environment which is in effect for the dynamic + extent of the call to the thunk passed as their last argument. These + procedures are essentially special purpose dynamic binding operations +-on hidden dynamic variables (one for current-input-port +-and one for current-output-port). The purpose of this ++on hidden dynamic variables (one for current-input-port ++and one for current-output-port). The purpose of this + SRFI is to generalize this dynamic binding mechanism (which exists in + all R5RS compliant systems) to allow the user to introduce new dynamic + variables and dynamically bind them. +-

          ++

          + +-

          ++

          + General dynamic binding mechanisms exist in several implementations of + Scheme under various names, including "fluid" variables and parameter + objects. The parameter objects specified in this SRFI are compatible +@@ -72,9 +85,9 @@ currently support parameter objects (in the sense that it is possible + to implement this SRFI so that old code works the same as before). We + believe Chez-Scheme was the first implementation of Scheme to have + used parameter objects. +-

          ++

          + +-

          ++

          + In the presence of threads, the dynamic binding mechanism does not + behave the same way in all implementations of Scheme supporting + dynamic binding. The issue is the relationship between the dynamic +@@ -92,105 +105,105 @@ environment share the same cells (i.e. an assignment of a value to a + dynamic variable is visible in the other thread). Note that in the + absence of assignment to dynamic variables the MzScheme and Gambit-C + approaches are equivalent. +-

          ++

          + +-

          ++

          + Given that there are semantic differences in the presence of threads + and that there are valid reasons for choosing each semantics, this + SRFI does not specify the semantics of parameter objects in the + presence of threads. It is left to the implementation and other SRFIs + which extend this SRFI to specify the interaction between parameter + objects and threads. +-

          ++

          + +-

          Specification

          ++

          Specification

          + +-

          +-The dynamic environment is composed of two parts: the local +-dynamic environment and the global dynamic environment. ++

          ++The dynamic environment is composed of two parts: the local ++dynamic environment and the global dynamic environment. + The global dynamic environment is used to lookup parameter objects + that can't be found in the local dynamic environment. When parameter + objects are created, their initial binding is put in the global + dynamic environment (by mutation). The local dynamic environment is +-only extended by the parameterize form. +-

          +- +-

          +-Parameter objects are created with the +-make-parameter procedure which takes one or two +-arguments. The second argument is a one argument conversion +-procedure. If only one argument is passed to +-make-parameter the identity function is used as a ++only extended by the parameterize form. ++

          ++ ++

          ++Parameter objects are created with the ++make-parameter procedure which takes one or two ++arguments. The second argument is a one argument conversion ++procedure. If only one argument is passed to ++make-parameter the identity function is used as a + conversion procedure. The global dynamic environment is updated to + associate the parameter object to a new cell. The initial content of + the cell is the result of applying the conversion procedure to the +-first argument of make-parameter. +-

          ++first argument of make-parameter. ++

          + +-

          +-A parameter object is a procedure which accepts zero or one ++

          ++A parameter object is a procedure which accepts zero or one + argument. The cell bound to a particular parameter object in the + dynamic environment is accessed by calling the parameter object. When + no argument is passed, the content of the cell is returned. When one + argument is passed the content of the cell is updated with the result + of applying the parameter object's conversion procedure to the + argument. +-

          ++

          + +-

          +-The parameterize special form, when given a parameter ++

          ++The parameterize special form, when given a parameter + object and a value, binds for the dynamic extent of its body the + parameter object to a new cell. The initial content of the cell is + the result of applying the parameter object's conversion procedure to +-the value. The parameterize special form behaves +-analogously to let when binding more than one parameter ++the value. The parameterize special form behaves ++analogously to let when binding more than one parameter + object (that is the order of evaluation is unspecified and the new +-bindings are only visible in the body of the parameterize ++bindings are only visible in the body of the parameterize + special form). +-

          ++

          + +-

          ++

          + Note that the conversion procedure can be used for guaranteeing the + type of the parameter object's binding and/or to perform some + conversion of the value. +-

          ++

          + +-

          ++

          + Because it is possible to implement the R5RS procedures +-current-input-port and current-output-port ++current-input-port and current-output-port + as parameter objects and this offers added functionnality, it is + required by this SRFI that they be implemented as parameter objects +-created with make-parameter. +-

          ++created with make-parameter. ++

          + +-

          Procedures and syntax

          ++

          Procedures and syntax

          + +-
          ++
          + +-
          +-(make-parameter init [converter])                     ;procedure
          +-
          ++
          ++(make-parameter init [converter])                     ;procedure
          ++
          + +-

          ++

          + Returns a new parameter object which is bound in the global dynamic + environment to a cell containing the value returned by the call +-(converter init). If the conversion +-procedure converter is not specified the identity function is ++(converter init). If the conversion ++procedure converter is not specified the identity function is + used instead. +-

          ++

          + +-

          ++

          + The parameter object is a procedure which accepts zero or one + argument. When it is called with no argument, the content of the cell + bound to this parameter object in the current dynamic environment is + returned. When it is called with one argument, the content of the + cell bound to this parameter object in the current dynamic environment +-is set to the result of the call (converter +-arg), where arg is the argument passed to the ++is set to the result of the call (converter ++arg), where arg is the argument passed to the + parameter object, and an unspecified value is returned. +-

          ++

          + +-
          ++
          +     (define radix
          +       (make-parameter 10))
          + 
          +@@ -202,9 +215,9 @@ parameter object, and an unspecified value is returned.
          +               x
          +               (error "only booleans are accepted by write-shared")))))
          + 
          +-    (radix)           ==>  10
          ++    (radix)           ==>  10
          +     (radix 2)
          +-    (radix)           ==>  2
          ++    (radix)           ==>  2
          +     (write-shared 0)  gives an error
          + 
          +     (define prompt
          +@@ -215,58 +228,61 @@ parameter object, and an unspecified value is returned.
          +               x
          +               (with-output-to-string (lambda () (write x)))))))
          + 
          +-    (prompt)       ==>  "123"
          +-    (prompt ">")
          +-    (prompt)       ==>  ">"
          +-
          +- +-

          +-

          +-(parameterize ((expr1 expr2) ...) <body>)             ;syntax
          +-
          ++ (prompt) ==> "123" ++ (prompt ">") ++ (prompt) ==> ">" ++
          ++
          ++
          ++(parameterize ((expr1 expr2) ...) <body>)             ;syntax
          ++
          ++
          ++
          + +-

          +- The expressions expr1 and expr2 are evaluated in an +- unspecified order. The value of the expr1 expressions must +- be parameter objects. For each expr1 expression and in an ++

          ++ The expressions expr1 and expr2 are evaluated in an ++ unspecified order. The value of the expr1 expressions must ++ be parameter objects. For each expr1 expression and in an + unspecified order, the local dynamic environment is extended with +- a binding of the parameter object expr1 to a new cell whose +- content is the result of the call (converter +- val), where val is the value of expr2 +- and converter is the conversion procedure of the parameter ++ a binding of the parameter object expr1 to a new cell whose ++ content is the result of the call (converter ++ val), where val is the value of expr2 ++ and converter is the conversion procedure of the parameter + object. The resulting dynamic environment is then used for the +- evaluation of <body> (which refers to the R5RS grammar ++ evaluation of <body> (which refers to the R5RS grammar + nonterminal of that name). The result(s) of the +- parameterize form are the result(s) of the +- <body>. +-

          ++ parameterize form are the result(s) of the ++ <body>. ++

          + +-
          +-    (radix)                                              ==>  2
          +-    (parameterize ((radix 16)) (radix))                  ==>  16
          +-    (radix)                                              ==>  2
          ++
          ++    (radix)                                              ==>  2
          ++    (parameterize ((radix 16)) (radix))                  ==>  16
          ++    (radix)                                              ==>  2
          + 
          +-    (define (f n) (number->string n (radix)))
          ++    (define (f n) (number->string n (radix)))
          + 
          +-    (f 10)                                               ==>  "1010"
          +-    (parameterize ((radix 8)) (f 10))                    ==>  "12"
          +-    (parameterize ((radix 8) (prompt (f 10))) (prompt))  ==>  "1010"
          +-
          ++ (f 10) ==> "1010" ++ (parameterize ((radix 8)) (f 10)) ==> "12" ++ (parameterize ((radix 8) (prompt (f 10))) (prompt)) ==> "1010" ++
          ++
          ++
          + +-

          Implementation

          ++

          Implementation

          + +-

          ++

          + The following implementation uses association lists to represent local + dynamic environments. The global dynamic environment binding is + stored in the parameter object itself. Since we are assuming that + there is a single thread, the current local dynamic environment can be +-bound to a global variable, dynamic-env-local. Mutations +-of this variable are wrapped in a dynamic-wind so that ++bound to a global variable, dynamic-env-local. Mutations ++of this variable are wrapped in a dynamic-wind so that + the local dynamic environment returns to its previous value when +-control exits the body of the parameterize. +-

          ++control exits the body of the parameterize. ++

          + +-
          ++
          +     (define make-parameter
          +       (lambda (init . conv)
          +         (let ((converter
          +@@ -320,9 +336,9 @@ control exits the body of the parameterize.
          + 
          +     (define dynamic-env-local-set!
          +       (lambda (new-env) (set! dynamic-env-local new-env)))
          +-
          ++
          + +-

          Copyright

          ++

          Copyright

          +

          Copyright (C) Marc Feeley 2002. All Rights Reserved.

          + +

          +@@ -349,7 +365,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

          + + +-
          +-
          Editor: Mike Sperber
          ++
          ++
          Editor: Mike Sperber
          + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-4.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-4.html +index f48174f..d11a35a 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-4.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-4.html +@@ -1,34 +1,51 @@ +- +- ++ ++ + ++ ++ + SRFI 4: Homogeneous numeric vector datatypes ++ ++ ++ + + + + +-

          Title

          ++

          SRFI 4: Homogeneous numeric vector datatypes

          + +-SRFI-4: Homogeneous numeric vector datatypes ++

          by Marc Feeley

          ++

          This copy of the SRFI 4 specification document ++is distributed as part of the Racket package ++srfi-doc.

          The canonical source of this document is ++https://srfi.schemers.org/srfi-4/srfi-4.html.

          + +-

          Author

          ++

          Status

          + +-Marc Feeley +- +-

          Status

          +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +-You can access previous messages via the archive of the mailing list. +-

            +-
          • Received: 1998/1/11 +-
          • Draft: 1999/1/19-1999/03/19 +-
          • Revised: 1999/04/26 +-
          • Final: 1999/5/22 +-
          +- +-

          Abstract

          ++

          This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-4@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

          ++
            ++
          • Received: 1998-01-11
          • ++
          • Draft: 1999-01-19--1999-03-19
          • ++
          • Revised: 1999-04-26
          • ++
          • Final: 1999-05-22
          • ++
          + ++

          Abstract

          ++

          + This SRFI describes a set of datatypes for vectors whose elements are + of the same numeric type (signed or unsigned exact integer or inexact + real of a given precision). These datatypes support operations +@@ -37,9 +54,9 @@ An external representation is specified which must be supported by the + read and write procedures and by the program + parser (i.e. programs can contain references to literal homogeneous + vectors). +- +-

          Rationale

          +- ++

          ++

          Rationale

          ++

          + Like lists, Scheme vectors are a heterogeneous datatype which impose + no restriction on the type of the elements. This generality is not + needed for applications where all the elements are of the same type. +@@ -51,76 +68,74 @@ Moreover, homogeneous vectors are convenient for interfacing with + low-level libraries (e.g. binary block I/O) and to interface with + foreign languages which support homogeneous vectors. Finally, the use + of homogeneous vectors allows certain errors to be caught earlier. +- +-

          +- ++

          ++

          + This SRFI specifies a set of homogeneous vector datatypes which cover + the most practical case, that is where the type of the elements is + numeric (exact integer or inexact real) and the precision and + representation is efficiently implemented on the hardware of most + current computer architectures (8, 16, 32 and 64 bit integers, either + signed or unsigned, and 32 and 64 bit floating point numbers). ++

          + +-

          Specification

          +- ++

          Specification

          ++

          + There are 8 datatypes of exact integer homogeneous vectors (which will + be called integer vectors): ++

          ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
          datatype type of elements ++
          s8vector signed exact integer in the range -(2^7) to (2^7)-1 ++
          u8vector unsigned exact integer in the range 0 to (2^8)-1 ++
          s16vectorsigned exact integer in the range -(2^15) to (2^15)-1 ++
          u16vectorunsigned exact integer in the range 0 to (2^16)-1 ++
          s32vectorsigned exact integer in the range -(2^31) to (2^31)-1 ++
          u32vectorunsigned exact integer in the range 0 to (2^32)-1 ++
          s64vectorsigned exact integer in the range -(2^63) to (2^63)-1 ++
          u64vectorunsigned exact integer in the range 0 to (2^64)-1 ++
          + +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-
          datatype type of elements +-
          s8vector signed exact integer in the range -(2^7) to (2^7)-1 +-
          u8vector unsigned exact integer in the range 0 to (2^8)-1 +-
          s16vectorsigned exact integer in the range -(2^15) to (2^15)-1 +-
          u16vectorunsigned exact integer in the range 0 to (2^16)-1 +-
          s32vectorsigned exact integer in the range -(2^31) to (2^31)-1 +-
          u32vectorunsigned exact integer in the range 0 to (2^32)-1 +-
          s64vectorsigned exact integer in the range -(2^63) to (2^63)-1 +-
          u64vectorunsigned exact integer in the range 0 to (2^64)-1 +-
          +- +-

          +- ++

          + There are 2 datatypes of inexact real homogeneous vectors (which will + be called float vectors): ++

          + +- +- +- +- +- +- +- +-
          datatype type of elements +-
          f32vector inexact real +-
          f64vector inexact real +-
          +- +-

          ++ ++ ++ ++ ++ ++ ++ ++
          datatype type of elements ++
          f32vector inexact real ++
          f64vector inexact real ++
          + ++

          + The only difference between the two float vector types is that + f64vectors preserve at least as much precision as + f32vectors (see the implementation section for details). +- +-

          +- ++

          ++

          + A Scheme system that conforms to this SRFI does not have to support + all of these homogeneous vector datatypes. However, a Scheme system + must support f32vectors and f64vectors if it +@@ -138,17 +153,15 @@ the Scheme system supports by calling the + string->number procedure (e.g. + (string->number "0.0") returns #f if the + Scheme system does not support inexact reals). +- +-

          +- ++

          ++

          + Each homogeneous vector datatype has an external representation which + is supported by the read and write + procedures and by the program parser. Each datatype also has a set of + associated predefined procedures analogous to those available for + Scheme's heterogeneous vectors. +- +-

          +- ++

          ++

          + For each value of TAG in { + s8, u8, + s16, u16, +@@ -156,30 +169,27 @@ For each value of TAG in { + s64, u64, + f32, f64 + }, if the datatype TAGvector is supported, then ++

          + +-

          +- +-
            +- +-
          1. the external representation of instances of the datatype ++
              ++
            1. ++

              ++ the external representation of instances of the datatype + TAGvector is #TAG( ...elements... ). +- +-

              +- ++

              ++

              + For example, #u8(0 #e1e2 #xff) is an + u8vector of length 3 containing 0, 100 and 255; + #f64(-1.5) is an f64vector of length 1 + containing -1.5. +- +-

              +- ++

              ++

              + Note that the syntax for float vectors conflicts with Standard Scheme + which parses #f32() as 3 objects: #f, + 32 and (). For this reason, conformance to + this SRFI implies this minor nonconformance to Standard Scheme. +- +-

              +- ++

              ++

              + This external representation is also available in program source code. + For example, (set! x '#u8(1 2 3)) will set x + to the object #u8(1 2 3). Literal homogeneous vectors +@@ -189,22 +199,23 @@ vectors can appear in quasiquotations but must not contain + (i.e. `(,x #u8(1 2)) is legal but `#u8(1 ,x + 2) is not). This restriction is to accommodate the many Scheme + systems that use the read procedure to parse programs. +- +-

              +- +-
            2. the following predefined procedures are available: +- +-
                +-
              1. (TAGvector? obj) +-
              2. (make-TAGvector n [ TAGvalue ]) +-
              3. (TAGvector TAGvalue...) +-
              4. (TAGvector-length TAGvect) +-
              5. (TAGvector-ref TAGvect i) +-
              6. (TAGvector-set! TAGvect i TAGvalue) +-
              7. (TAGvector->list TAGvect) +-
              8. (list->TAGvector TAGlist) +-
              +- ++

              ++
            3. ++
            4. ++

              ++ the following predefined procedures are available: ++

              ++
                ++
              1. (TAGvector? obj)
              2. ++
              3. (make-TAGvector n [ TAGvalue ])
              4. ++
              5. (TAGvector TAGvalue...)
              6. ++
              7. (TAGvector-length TAGvect)
              8. ++
              9. (TAGvector-ref TAGvect i)
              10. ++
              11. (TAGvector-set! TAGvect i TAGvalue)
              12. ++
              13. (TAGvector->list TAGvect)
              14. ++
              15. (list->TAGvector TAGlist)
              16. ++
              ++

              + where obj is any Scheme object, n is a + nonnegative exact integer, i is a nonnegative exact + integer less than the length of the vector, TAGvect is an +@@ -213,41 +224,40 @@ is a number of the type acceptable for elements of the + TAGvector datatype, and TAGlist is a proper + list of numbers of the type acceptable for elements of the + TAGvector datatype. +- +-

              +- ++

              ++

              + It is an error if TAGvalue is not the same type as the + elements of the TAGvector datatype (for example if an + exact integer is passed to f64vector). If the fill + value is not specified, the content of the vector is unspecified + but individual elements of the vector are guaranteed to be in the + range of values permitted for that type of vector. ++

              ++
            5. ++
            + +-
          +- +-

          Implementation

          +- ++

          Implementation

          ++

          + The homogeneous vector datatypes described here suggest a concrete + implementation as a sequence of 8, 16, 32 or 64 bit elements, using + two's complement representation for the signed exact integers, and + single and double precision IEEE-754 floating point representation for + the inexact reals. Although this is a practical implementation on +-many modern byte addressed machines, a different implementation is ++many modern byte-addressed machines, a different implementation is + possible for machines which don't support these concrete numeric types + (the CRAY-T90 for example does not have a 32 bit floating point + representation and the 64 bit floating point representation does not + conform to IEEE-754, so both the f32vector and + f64vector datatypes could be represented the same way + with 64 bit floating point numbers). +- +-

          +- ++

          ++

          + A portable implementation of the homogeneous vector predefined + procedures can be based on Scheme's heterogeneous vectors. + Here is for example an implementation of s8vectors + which is exempt of error checking: +- +-

          ++

          ++
          + (define s8vector? #f)
          + (define make-s8vector #f)
          + (define s8vector #f)
          +@@ -318,10 +328,8 @@ which is exempt of error checking:
          +       (and (orig-vector? obj)
          +            (orig-not (and (orig-> (orig-vector-length obj) 0)
          +                           (orig-eq? (orig-vector-ref obj 0) tag)))))))
          +-
          +- +-

          +- ++
          ++

          + The Scheme system's read and write + procedures and the program parser also need to be extended to handle + the homogeneous vector external representations. The implementation +@@ -333,9 +341,12 @@ is the case, parse a symbol and check if it is t, + f, s8, f32, and so on, and in + the case of a homogeneous vector prefix, check if the next character + is an opening parenthesis). ++

          + +-

          Copyright

          ++

          Copyright

          ++

          + Copyright (C) Marc Feeley (1999). All Rights Reserved. ++

          +

          + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -360,8 +371,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

          + + +-
          +-
          Editor: ++
          ++
          Editor: + Shriram Krishnamurthi
          + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-40.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-40.html +index 7340781..0d0300c 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-40.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-40.html +@@ -1,46 +1,67 @@ +- +- ++ ++ + ++ ++ + SRFI 40: A Library of Streams ++ ++ ++ + + + + +-

          Title

          ++

          SRFI 40: A Library of Streams

          + +-SRFI 40: A Library of Streams ++

          by Philip L. Bewig

          ++

          This copy of the SRFI 40 specification document ++is distributed as part of the Racket package ++srfi-doc.

          The canonical source of this document is ++https://srfi.schemers.org/srfi-40/srfi-40.html.

          + +-

          Author

          ++

          Status

          + +-Philip L. Bewig ++

          This SRFI is currently in withdrawn status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-40@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

          ++ + +-

          Status

          + +-

          +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-To comments +-this SRFI, please mail to +- +-srfi-40@srfi.schemers.org. +-See +-instructions here to subscribe to the list. You can access +-the discussion via +- +-the archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +-

          +- +-
        • Received: 2003/02/03 +-
        • Draft: 2003/02/03-2003/04/03 +-
        • Revised: 2003/08/02 +-
        • Revised: 2003/12/23 +-
        • Final: 2004/08/22 +-
        +- +-

        Abstract

        ++

        Abstract

        + +

        + Along with higher-order functions, one of the hallmarks of functional +@@ -69,7 +90,7 @@ convenient processing of streams and shows several examples of their + use. +

        + +-

        Rationale

        ++

        Rationale

        + +

        + Two of the defining characteristics of functional programming +@@ -90,17 +111,16 @@ programming with streams. + +

        + Scheme has a long tradition of computing with streams. The great +-computer science textbook Structure and Interpretation ++computer science textbook Structure and Interpretation + of Computer Programs, uses streams extensively. +-The example given ++The example given + in R5RS makes use of streams to integrate systems of differential + equations using the method of Runge-Kutta. MIT Scheme, the original +-implementation of Scheme, provides streams natively. Scheme and the Art of Programming, ++implementation of Scheme, provides streams natively. Scheme and the Art of Programming, + discusses streams. + Some Scheme-like languages also have traditions of using streams: +-Winston and Horn, in their classic Lisp textbook, discuss streams, and +-so does Larry Paulson in his text on ++Winston and Horn, in their classic Lisp textbook, discuss streams, and ++so does Larry Paulson in his text on + ML. Streams are an important and useful data structure. +

        + +@@ -128,8 +148,7 @@ operational difference between the two types of streams. +

        + +

        +-Philip Wadler, Walid Taha, and David MacQueen, in their paper "How to add laziness to a strict language ++Philip Wadler, Walid Taha, and David MacQueen, in their paper "How to add laziness to a strict language + without even being odd", describe how they added streams to the + SML/NJ compiler. They discuss two kinds of streams: odd streams, as + in SICP et al, and even streams, as in Haskell; the names odd and even +@@ -180,7 +199,7 @@ Here are the first two figures from their paper, rewritten in Scheme: + (cutoff1 (- n 1) + (cdr1 strm)))))) + +- ++ +

        ;;; FIGURE 2 -- EVEN
        + 
        + (define nil2 (delay '()))
        +@@ -259,7 +278,7 @@ and even streams.  We expect the two constructors nil and
        + nil and cons return a strict list, but the
        + even nil and cons return promises.
        + Nil?, car and cdr change to
        +-accommodate the underlying representation differences.
        ++accomodate the underlying representation differences.
        + Cutoff is identical in the two versions, because it
        + doesn't return a stream.
        + 

        +@@ -587,7 +606,7 @@ stream-define are both library procedures, not fundamental to the use + of streams, and are thus excluded from this SRFI. +

        + +-

        Specification

        ++

        Specification

        + +

        A stream-pair is a data structure consisting of two fields called + the stream-car and stream-cdr. Stream-pairs are created +@@ -629,23 +648,25 @@ to detect and report errors. +

        + +
        +-
        +-stream-null (constant)
        ++
        ++stream-null (constant)
        +
        ++

        + Stream-null is the distinguished nil stream, a single + Scheme object distinguishable from all other objects. If the last + stream-pair in a stream contains stream-null in its cdr field, the + stream is finite and has a computable length. However, there is no + need for streams to terminate. +- ++

        +
        +-    stream-null                                 => (stream)
        ++    stream-null                                 => (stream)
        + 
        +
        + +-
        +-(stream-cons object stream) (syntax)
        ++
        ++(stream-cons object stream) (syntax)
        +
        ++

        + Stream-cons is the primitive constructor of streams, + returning a stream with the given object in its car field and the + given stream in its cdr field. The stream returned by +@@ -654,7 +675,7 @@ given stream in its cdr field. The stream returned by + of any type, and there is no requirement that successive elements of a + stream be of the same type, although it is common for them to be. It + is an error if the second argument of stream-cons is not a stream. +- ++

        +
            (stream-cons 'a stream-null)                => (stream 'a)
        +     (stream-cons 'a (stream 'b 'c 'd))          => (stream 'a 'b 'c 'd)
        +     (stream-cons "a" (stream 'b 'c))            => (stream "a" 'b 'c)
        +@@ -663,73 +684,78 @@ is an error if the second argument of stream-cons is not a stream.
        + 
        +
        + +-
        +-(stream? object) (function)
        ++
        ++(stream? object) (function)
        +
        ++

        + Stream? returns #t if the object is a stream, and otherwise returns #f. A stream + object may be either the null stream or a stream pair created by stream-cons. +- ++

        +
            (stream? stream-null)                       => #t
        +     (stream? (stream-cons 'a stream-null))      => #t
        +     (stream? 3)                                 => #f
        + 
        +
        + +-
        +-(stream-null? object) (function)
        ++
        ++(stream-null? object) (function)
        +
        ++

        + Stream-null? returns #t if the object is the distinguished nil stream, and +-otherwise returns #f#f. ++

        +
            (stream-null? stream-null)                  => #t
        +     (stream-null? (stream-cons 'a stream-null)) => #f
        +     (stream-null? 3)                            => #f
        + 
        +
        + +-
        +-(stream-pair? object) (function)
        ++
        ++(stream-pair? object) (function)
        +
        ++

        + Stream-pair? returns #t if the object is a stream pair created by stream-cons, and + otherwise returns #f. +- ++

        +
            (stream-pair? stream-null)                  => #f
        +     (stream-pair? (stream-cons 'a stream-null)) => #t
        +     (stream-pair? 3)                            => #f
        + 
        +
        + +-
        +-(stream-car stream) (function)
        ++
        ++(stream-car stream) (function)
        +
        ++

        + Stream-car returns the object in the stream-car field of + a stream-pair. It is an error to attempt to evaluate the stream-car + of stream-null. +- ++

        +
            (stream-car (stream 'a 'b 'c))              => a
        +     (stream-car stream-null)                    => error
        +     (stream-car 3)                              => error
        + 
        +
        + +-
        +-(stream-cdr stream) (function)
        ++
        ++(stream-cdr stream) (function)
        +
        ++

        + Stream-cdr returns the stream in the stream-cdr field of + a stream-pair. It is an error to attempt to evaluate the stream-cdr + of stream-null. +- +- ++

        +
            (stream-cdr (stream 'a 'b 'c))              => (stream 'b 'c)
        +     (stream-cdr stream-null)                    => error
        +     (stream-cdr 3)                              => error
        +-
        ++
        + 
        +
        + +-
        +-(stream-delay expression) (syntax)
        ++
        ++(stream-delay expression) (syntax)
        +
        ++

        + Stream-delay is the essential mechanism for operating on streams, taking an + expression and returning a delayed form of the expression that can be asked at + some future point to evaluate the expression and return the resulting value. The +@@ -737,7 +763,7 @@ action of stream-delay is analogous to the action of delay, but it is specific t + the stream data type, returning a stream instead of a promise; no corresponding + stream-force is required, because each of the stream functions performs the force + implicitly. +- ++

        +
            (define from0
        +       (let loop ((x 0))
        +         (stream-delay
        +@@ -746,26 +772,28 @@ implicitly.
        + 
        +
        + +-
        (stream object ...) (library function) ++
        (stream object ...) (library function)
        +
        ++

        + Stream returns a newly allocated finite stream of its arguments, in order. +- ++

        +
            (stream 'a (+ 3 4) 'c)                      => (stream 'a 7 'c)
        +     (stream)                                    => stream-null
        + 
        +
        + +
        +-(stream-unfoldn generator seed n) ++(stream-unfoldn generator seed n) + (function)
        +
        ++

        + Stream-unfoldn returns n streams whose contents are produced by successive calls + to generator, which takes the current seed as an arguments and returns n + 1 + values: +- ++

        +

        +-(proc seed) -> seed result0 ... resultN +- ++(proc seed) -> seed result0 ... resultN ++

        +

        + where resultI indicates how to produce the next element of the Ith result stream: +

        +@@ -806,8 +834,8 @@ multiple calls to generator. +
        + + +-
        +-(stream-map function stream ...) (library ++
        ++(stream-map function stream ...) (library + function)
        +
        + Stream-map creates a newly allocated stream built by +@@ -826,8 +854,8 @@ streams are infinite. The stream elements are evaluated in order. + +
        + +-
        +-(stream-for-each procedure stream ...) ++
        ++(stream-for-each procedure stream ...) + (library function)
        +
        + Stream-for-each applies procedure elementwise to the elements of the streams, +@@ -839,8 +867,8 @@ stream-for-each is unspecified. The stream elements are visited in order. + +
        + +-
        +-(stream-filter predicate? stream) (library function)
        ++
        ++(stream-filter predicate? stream) (library function)
        +
        + Stream-filter applies predicate? to each element + of stream and creates a newly allocated stream consisting of those +@@ -855,18 +883,16 @@ same order as they were in the input stream, and are tested by +
        +
        + +-

        Implementation

        ++

        Implementation

        + +

        A reference implementation of streams is shown below. It strongly + prefers simplicity and clarity to efficiency, and though a reasonable + attempt is made to be safe-for-space, no promises are made. The reference +-implementation relies on the mechanism for defining record types of SRFI-9, and the functions +-any and every from SRFI-1. The ++implementation relies on the mechanism for defining record types of SRFI-9, and the functions ++any and every from SRFI-1. The + stream-error function aborts by calling error as +-defined in SRFI 23. +- ++defined in SRFI 23. ++

        +
        ;;; PROMISES A LA SRFI-45:
        + 
        + ;;; A separate implementation is necessary to
        +@@ -1038,15 +1064,17 @@ defined in SRFI 23.
        +         ((not (stream? strm)) (stream-error "attempt to apply stream-filter to non-stream"))
        +         (else (stream-unfoldn
        +                 (lambda (s)
        +-                  (values
        +-                    (stream-cdr s)
        +-                    (cond ((stream-null? s) '())
        +-                          ((pred? (stream-car s)) (list (stream-car s)))
        +-                          (else #f))))
        ++		  (cond
        ++		   ((stream-null? s)
        ++		    (values stream-null '()))
        ++		   ((pred? (stream-car s))
        ++		    (values (stream-cdr s) (list (stream-car s))))
        ++		   (else
        ++		    (values (stream-cdr s) #f))))
        +                 strm
        +                 1))))
        + +-

        References

        ++

        References

        + +
          +
        • +@@ -1078,8 +1106,8 @@ Workshop on ML, pp. 24-30. + + Patrick H. Winston, Berthold K. Horn: Lisp, 3rd edition, + Addison Wesley, 1989. +-
        +-

        Copyright

        ++
      ++

      Copyright

      +

      Copyright (C) 2003 by Philip L. Bewig of Saint Louis, Missouri, United States of + America. All rights reserved.

      + +@@ -1106,11 +1134,11 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

      + +-
      +-
      Editor: Mike Sperber
      ++
      ++
      Editor: Mike Sperber
      + + +-Last modified: Sat Sep 11 12:40:31 MST 2004 ++Last modified: Fri Jan 25 11:19:45 CET 2008 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-41/srfi-41.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-41/srfi-41.html +index a937761..6604d2f 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-41/srfi-41.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-41/srfi-41.html +@@ -1,42 +1,55 @@ +- +-SRFI 41: Streams +- +-

      Title

      +- +-Streams +- +- +-

      Author

      +- +-Philip L. Bewig +- +-

      Status

      +- +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-To comment on this SRFI, please +-mailto:srfi minus 41 at srfi dot schemers dot org. +-See instructions +-here to subscribe to the list. You can access +-the discussion via +- +-the archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. ++ ++ ++ ++ ++ ++ SRFI 41: Streams ++ ++ ++ ++ ++ ++ ++ ++

      SRFI 41: Streams

      ++ ++

      by Philip L. Bewig

      ++

      This copy of the SRFI 41 specification document ++is distributed as part of the Racket package ++srfi-doc.

      The canonical source of this document is ++https://srfi.schemers.org/srfi-41/srfi-41.html.

      ++ ++

      Status

      ++ ++

      This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-41@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

      + + +- +-

      Abstract

      ++ ++

      Abstract

      + +

      Streams, sometimes + called lazy lists, are a sequential data structure containing elements +@@ -60,16 +73,16 @@ stream libraries, say:

      + +

      (import (streams))

      + +-

      Rationale

      ++

      Rationale

      + +

      Harold Abelson + and Gerald Jay Sussman discuss streams at length, giving a strong justification + for their use. The streams they provide are represented as a cons + pair with a promise to return a stream in its cdr; for instance, a stream with elements + the first three counting numbers is represented conceptually as (cons 1 (delay (cons 2 (delay (cons 3 (delay +-'())))))). Philip Wadler, Walid Taha and David +-MacQueen describe such streams as odd because, regardless of +-their length, the parity of the number of constructors (delay, cons, '()) ++'())))))). Philip Wadler, Walid Taha and David ++MacQueen describe such streams as odd because, regardless of ++their length, the parity of the number of constructors (delay, cons, '()) + in the stream is odd.

      + +

      The streams +@@ -105,7 +118,7 @@ of items as a whole, similar to a pipeline of unix commands.

      + +

      In addition + to improved modularity, streams permit a clear exposition of backtracking +-algorithms using the “stream of successes” technique, and they can ++algorithms using the “stream of successes” technique, and they can + be used to model generators and co-routines. The implicit memoization + of streams makes them useful for building persistent data structures, + and the laziness of streams permits some multi-pass algorithms to be +@@ -121,9 +134,9 @@ savings are needed, or when they offer a clearer exposition of the algorithms + that operate on the sequence.

      + + +-

      Specification

      ++

      Specification

      + +-

      The (streams primitive) library

      ++

      The (streams primitive) library

      + + The (streams primitive) + library provides two mutually-recursive abstract data types: An +@@ -132,12 +145,14 @@ when forced, is either stream-nullstream-pair abstract data type contains a stream-car + and a stream-cdr, which must be a stream. The essential feature of streams + is the systematic suspensions of the recursive promises between the +-two data types.

      ++two data types.
      + +-

      α stream
      ++

      ++α stream
      +   :: (promise stream-null)
      +-  |  (promise (α stream-pair))
      α stream-pair
      +-  :: (promise α) × (promise (α stream))

      ++ | (promise (α stream-pair))
      ++α stream-pair
      ++  :: (promise α) × (promise (α stream))

      + +

      The object + stored in the stream-car of a stream-pair is a promise that is forced the first +@@ -152,12 +167,12 @@ provides eight operators: constructors for stream- + the two kinds of streams, accessors for both fields of a stream-pair, + and a lambda that creates procedures that return streams.

      + +-

      constructor: stream-null
      ++

      constructor: stream-null
      + Stream-null is a promise that, when forced, is + a single object, distinguishable from all other objects, that represents + the null stream. Stream-null is immutable and unique.

      + +-

      constructor: (stream-cons object stream)
      ++

      constructor: (stream-cons object stream)
      + Stream-cons is a macro that accepts an object + and a stream and creates a newly-allocated stream containing a promise that, when forced, + is a stream-pair with the object in its stream-car +@@ -170,7 +185,7 @@ however, doing so will cause an error later when the stream-set-car! or stream-set-cdr! that modifies an existing stream-pair. + There is no dotted-pair or improper stream as with lists.

      + +-

      recognizer: (stream? object)
      ++

      recognizer: (stream? object)
      + Stream? is a procedure that takes an object + and returns #t + if the object is a stream and #f otherwise. If object +@@ -183,35 +198,35 @@ obj) is #f and (stream-pair? + obj) will be #f.

      + +-

      recognizer: (stream-null? object)
      ++

      recognizer: (stream-null? object)
      + Stream-null? is a procedure that takes an object + and returns #t + if the object is the distinguished null stream and #f + otherwise. If object is a stream, stream-null? must force its promise in order to + distinguish stream-null from stream-pair.

      + +-

      recognizer: (stream-pair? object)
      ++

      recognizer: (stream-pair? object)
      + Stream-pair? is a procedure that takes an object + and returns #t + if the object is a stream-pair constructed by stream-cons and #f otherwise. If object + is a stream, stream-pair? must force its promise in order to + distinguish stream-null from stream-pair.

      + +-

      accessor: (stream-car stream)
      ++

      accessor: (stream-car stream)
      + Stream-car is a procedure that takes a stream + and returns the object stored in the stream-car of the stream. Stream-car + signals an error if the object passed to it is not a stream-pair. Calling stream-car causes the object stored there to +-be evaluated if it has not yet been; the object’s value is cached ++be evaluated if it has not yet been; the object’s value is cached + in case it is needed again.

      + +-

      accessor: (stream-cdr stream)
      ++

      accessor: (stream-cdr stream)
      + Stream-cdr is a procedure that takes a stream + and returns the stream stored in the stream-cdr of the stream. Stream-cdr + signals an error if the object passed to it is not a stream-pair. Calling stream-cdr + does not force the promise containing the stream stored in the +-stream-cdr of the stream. ++stream-cdr of the stream.

      + +-

      lambda: (stream-lambda args body)
      ++

      lambda: (stream-lambda args body)
      + Stream-lambda creates a procedure that returns a + promise to evaluate the body of the procedure. The last + body expression to be evaluated must yield a stream. As with +@@ -222,178 +237,188 @@ which may be null if there are no arguments, proper if there are an + exact number of arguments, or dotted if a fixed number of arguments + is to be followed by zero or more arguments collected into a list. + Body must contain at least one expression, and may contain internal +-definitions preceding any expressions to be evaluated.

      ++definitions preceding any expressions to be evaluated.

      + +-

      (define strm123
      ++

      ++(define strm123
      +   (stream-cons 1
      +     (stream-cons 2
      +       (stream-cons 3
      +-        stream-null))))

      ++ stream-null))))

      + +-

      (stream-car strm123) +-1

      ++

      (stream-car strm123) ++1

      + +-

      (stream-car (stream-cdr +-strm123) +-2

      ++

      (stream-car (stream-cdr ++strm123) ++2

      + +-

      (stream-pair?
      ++

      ++(stream-pair?
      +   (stream-cdr
      +-    (stream-cons (/ 1 0) stream-null)))  #f

      ++ (stream-cons (/ 1 0) stream-null))) ⇒ #f

      + +-

      (stream? (list +-1 2 3)) +-#f

      ++

      (stream? (list ++1 2 3)) ++#f

      + +-

      (define iter
      ++

      ++(define iter
      +   (stream-lambda (f x)
      +-    (stream-cons x (iter f (f x)))))

      ++ (stream-cons x (iter f (f x)))))

      + +-

      (define nats (iter +-(lambda (x) (+ x 1)) 0))

      ++

      (define nats (iter ++(lambda (x) (+ x 1)) 0))

      + +-

      (stream-car (stream-cdr +-nats)) +-1

      ++

      (stream-car (stream-cdr ++nats)) ++1

      + +-

      (define stream-add
      ++

      ++(define stream-add
      +   (stream-lambda (s1 s2)
      +     (stream-cons
      +       (+ (stream-car s1) (stream-car s2))
      +       (stream-add (stream-cdr s1)
      +-                  (stream-cdr s2)))))

      ++ (stream-cdr s2)))))

      + +-

      (define evens (stream-add +-nats nats))

      ++

      (define evens (stream-add ++nats nats))

      + +-

      (stream-car evens) 0

      ++

      (stream-car evens) 0

      + +-

      (stream-car (stream-cdr +-evens)) +-2

      ++

      (stream-car (stream-cdr ++evens)) ++2

      + +-

      (stream-car (stream-cdr +-(stream-cdr evens))) 4

      ++

      (stream-car (stream-cdr ++(stream-cdr evens))) 4

      + +-

      The (streams derived) library

      ++

      The (streams derived) library

      + +-

      The (streams derived) ++

      The (streams derived) + library provides useful procedures and syntax that depend on the primitives + defined above. In the operator + templates given below, an ellipsis ... indicates zero or more repetitions +-of the preceding subexpression and square brackets […] indicate optional elements. +-In the type annotations given below, square brackets […] refer to lists, curly braces {…} +-refer to streams, and nat refers to exact non-negative integers.

      ++of the preceding subexpression and square brackets […] indicate optional elements. ++In the type annotations given below, square brackets […] refer to lists, curly braces {…} ++refer to streams, and nat refers to exact non-negative integers.

      + +-

      syntax: (define-stream +-(name args) body)
      ++

      syntax: (define-stream ++(name args) body)
      + Define-stream creates a procedure that returns a + stream, and may appear anywhere a normal define may appear, including as an internal + definition, and may have internal definitions of its own, including + other define-streams. The defined procedure takes + arguments in the same way as stream-lambda. Define-stream is syntactic sugar on stream-lambda; +-see also stream-let, which is also a sugaring of stream-lambda.

      ++see also stream-let, which is also a sugaring of stream-lambda.

      + +-

      A simple version of stream-map +- that takes only a single input stream calls itself recursively:

      ++

      A simple version of stream-map ++ that takes only a single input stream calls itself recursively:

      + +-

      (define-stream (stream-map proc strm)
      ++

      ++(define-stream (stream-map proc strm)
      +   (if (stream-null? strm)
      +       stream-null
      +       (stream-cons
      +         (proc (stream-car strm))
      +-        (stream-map proc (stream-cdr strm))))))

      ++ (stream-map proc (stream-cdr strm))))))

      + +-

      procedure: (list->stream list-of-objects)
      +-[α] → {α}
      ++

      procedure: (list->stream list-of-objects)
      ++[α] → {α}
      + List->stream takes a list of objects and returns + a newly-allocated stream containing in its elements the objects in the + list. Since the objects are given in a list, they are evaluated + when list->stream is called, before the stream is created. + If the list of objects is null, as in (list->stream +-'()), the null stream is +-returned. See also stream.

      ++'()), the null stream is ++returned. See also stream.

      + +-

      (define strm123 (list->stream '(1 2 3)))

      ++

      (define strm123 (list->stream '(1 2 3)))

      + +-

      ++

      +

      ; fails with divide-by-zero error
      +-(define s (list->stream (list 1 (/ 1 0) -1)))

      ++(define s (list->stream (list 1 (/ 1 0) -1)))

      + +-

      procedure: (port->stream +-[port])
      +-port → {char}
      ++

      procedure: (port->stream ++[port])
      ++port → {char}
      + Port->stream takes a port and returns a + newly-allocated stream containing in its elements the characters on + the port. If port is not given it defaults to the current + input port. The returned stream has finite length and is terminated +-by stream-null.

      +-

      It looks like +-one use of port->stream would be this:

      ++by stream-null.

      ++

      It looks like ++one use of port->stream would be this:

      + +-

      (define s ;wrong!
      ++

      ++(define s ;wrong!
      +   (with-input-from-file filename
      +-    (lambda () (port->stream))))

      ++ (lambda () (port->stream))))

      + +-

      But that fails, ++

      But that fails, + because with-input-from-file is eager, and closes the input port + prematurely, before the first character is read. To read a file +-into a stream, say:

      ++into a stream, say:

      + +-

      (define-stream (file->stream filename)
      ++

      ++(define-stream (file->stream filename)
      +   (let ((p (open-input-file filename)))
      +     (stream-let loop ((c (read-char p)))
      +       (if (eof-object? c)
      +           (begin (close-input-port p)
      +                  stream-null)
      +           (stream-cons c
      +-            (loop (read-char p)))))))

      ++ (loop (read-char p)))))))

      + +-

      syntax: (stream object ...)
      ++

      syntax: (stream object ...)
      + Stream is syntax that takes zero or more + objects and creates a newly-allocated stream containing in its elements + the objects, in order. Since stream is syntactic, the objects are + evaluated when they are accessed, not when the stream is created. + If no objects are given, as in (stream), the null stream is returned. +-See also list->stream.

      ++See also list->stream.

      + +-

      (define strm123 (stream 1 2 3))

      ++

      (define strm123 (stream 1 2 3))

      + +-

      ; (/ 1 0) not evaluated when stream is created
      +-(define s (stream 1 (/ 1 0) -1))

      ++

      ++; (/ 1 0) not evaluated when stream is created
      ++(define s (stream 1 (/ 1 0) -1))

      + +-

      procedure: (stream->list +-[n] stream)
      +-nat × {α} → [α]
      ++

      procedure: (stream->list ++[n] stream)
      ++nat × {α} → [α]
      + Stream->list takes a natural number n and + a stream and returns a newly-allocated list containing in its + elements the first n items in the stream. If the stream + has less than n items all the items in the stream will + be included in the returned list. If n is not given it + defaults to infinity, which means that unless stream is finite stream->list +-will never return.

      ++will never return.

      + +-

      (stream->list 10
      ++

      ++(stream->list 10
      +   (stream-map (lambda (x) (* x x))
      +     (stream-from 0)))
      +-   (0 1 4 9 16 25 36 49 64 81)

      ++ ⇒ (0 1 4 9 16 25 36 49 64 81)

      + +-

      procedure: +-(stream-append stream ...)
      +-{α} ... → {α}
      ++

      procedure: ++(stream-append stream ...)
      ++{α} ... → {α}
      + Stream-append returns a newly-allocated stream containing + in its elements those elements contained in its input streams, + in order of input. If any of the input streams is infinite, + no elements of any of the succeeding input streams will appear + in the output stream; thus, if x is infinite, (stream-append +-x y) ≡ x. See also stream-concat.

      ++x y) ≡ x. See also stream-concat.

      + +-

      Quicksort can ++

      Quicksort can + be used to sort a stream, using stream-append to build the output; the sort is lazy; + so if only the beginning of the output stream is needed, the end of +-the stream is never sorted.

      ++the stream is never sorted.

      + +-

      (define-stream (qsort lt? strm)
      ++

      ++(define-stream (qsort lt? strm)
      +   (if (stream-null? strm)
      +       stream-null
      +       (let ((x (stream-car strm))
      +@@ -407,9 +432,9 @@ the stream is never sorted.

      + (qsort lt? + (stream-filter + (lambda (u) (not (lt? u x))) +- xs))))))

      ++ xs))))))

      + +-

      Note also that, ++

      Note also that, + when used in tail position as in qsort, stream-append does not suffer the poor performance + of append + on lists. The list version of append requires re-traversal of all its list +@@ -419,29 +444,31 @@ the preceding elements of the result have already been traversed, so + tail-recursive loops that produce streams are efficient even when each + element is appended to the end of the result stream. This also + implies that during traversal of the result only one promise needs to +-be kept in memory at a time.

      ++be kept in memory at a time.

      + +-

      procedure: (stream-concat stream)
      +-{{α}} ... → {α}
      ++

      procedure: (stream-concat stream)
      ++{{α}} ... → {α}
      + Stream-concat takes a stream consisting of + one or more streams and returns a newly-allocated stream containing + all the elements of the input streams. If any of the streams in + the input stream is infinite, any remaining streams in the input +-stream will never appear in the output stream. See also stream-append.

      ++stream
      will never appear in the output stream. See also stream-append.

      + +-

      (stream->list
      ++

      ++(stream->list
      +   (stream-concat
      +     (stream
      +       (stream 1 2) (stream) (stream 3 2 1))))
      +-  ⇒ (1 2 3 2 1)

      ++ ⇒ (1 2 3 2 1)

      + +-

      The permutations ++

      The permutations + of a finite stream can be determined by interleaving each element of + the stream in all possible positions within each permutation of the + other elements of the stream. Interleave returns a stream of streams with +-x inserted in each possible position of yy:

      ++x inserted in each possible position of yy:

      + +-

      (define-stream (interleave x yy)
      ++

      ++(define-stream (interleave x yy)
      +   (stream-match yy
      +     (() (stream (stream x)))
      +     ((y . ys)
      +@@ -449,55 +476,58 @@ x inserted in each possible position of yy:

      + (stream (stream-cons x yy)) + (stream-map + (lambda (z) (stream-cons y z)) +- (interleave x ys))))))

      ++ (interleave x ys))))))

      + +-

      (define-stream (perms xs)
      ++

      ++(define-stream (perms xs)
      +   (if (stream-null? xs)
      +       (stream (stream))
      +       (stream-concat
      +         (stream-map
      +           (lambda (ys)
      +             (interleave (stream-car xs) ys))
      +-          (perms (stream-cdr xs))))))

      ++ (perms (stream-cdr xs))))))

      + +-

      procedure: (stream-constant object ...)
      +-α ... → {α}
      ++

      procedure: (stream-constant object ...)
      ++α ... → {α}
      + Stream-constant takes one or more objects and + returns a newly-allocated stream containing in its elements the objects, +-repeating the objects in succession forever.

      +-

      (stream-constant +-1) +-1 1 1 ...

      +-

      (stream-constant +-#t #f) +-#t #f #t #f #t #f ...

      +- +-

      procedure: (stream-drop n stream) procedure
      +-nat × {α} → {α}
      ++repeating the objects in succession forever.

      ++

      (stream-constant ++1) ++1 1 1 ...

      ++

      (stream-constant ++#t #f) ++#t #f #t #f #t #f ...

      ++ ++

      procedure: (stream-drop n stream) procedure
      ++nat × {α} → {α}
      + Stream-drop returns the suffix of the input + stream that starts at the next element after the first n + elements. The output stream shares structure with the input + stream; thus, promises forced in one instance of the stream are + also forced in the other instance of the stream. If the input + stream has less than n elements, stream-drop returns the null stream. See +-also stream-take.

      ++also stream-take.

      + +-

      (define (stream-split n strm)
      ++

      ++(define (stream-split n strm)
      +   (values (stream-take n strm)
      +-          (stream-drop n strm)))

      ++ (stream-drop n strm)))

      + +-

      procedure: (stream-drop-while pred? stream)
      +-(α → boolean) × {α} → {α}
      ++

      procedure: (stream-drop-while pred? stream)
      ++(α → boolean) × {α} → {α}
      + Stream-drop-while returns the suffix of the input + stream that starts at the first element x for which (pred? x) + is #f. + The output stream shares structure with the input stream. +-See also stream-take-while.

      ++See also stream-take-while.

      + +-

      Stream-unique creates a new stream that retains +-only the first of any sub-sequences of repeated elements.

      ++

      Stream-unique creates a new stream that retains ++only the first of any sub-sequences of repeated elements.

      + +-

      (define-stream (stream-unique eql? strm)
      ++

      ++(define-stream (stream-unique eql? strm)
      +   (if (stream-null? strm)
      +       stream-null
      +       (stream-cons (stream-car strm)
      +@@ -505,22 +535,23 @@ only the first of any sub-sequences of repeated elements.

      ++ strm)))))

      + +-

      procedure: +-(stream-filter pred? stream)
      +-(α → boolean) × {α} → {α}
      ++

      procedure: ++(stream-filter pred? stream)
      ++(α → boolean) × {α} → {α}
      + Stream-filter returns a newly-allocated stream that + contains only those elements x of the input stream for + which (pred? x) +-is non-#f.

      ++is non-#f.

      + +-

      (stream-filter odd? (stream-from 0))
      +-   ⇒ 1 3 5 7 9 ...

      ++

      ++(stream-filter odd? (stream-from 0))
      ++   ⇒ 1 3 5 7 9 ...

      + +-

      procedure: +-(stream-fold proc base stream)
      +-(α × β → α) × α × {β} → α
      ++

      procedure: ++(stream-fold proc base stream)
      ++(α × β → α) × α × {β} → α
      + Stream-fold applies a binary procedure + to base and the first element of stream to compute a new + base, then applies the procedure to the new base and +@@ -533,34 +564,38 @@ See also stream-scan, wh + For readers familiar with other functional languages, this is a left-fold; + there is no corresponding right-fold, since right-fold relies on finite + streams that are fully-evaluated, at which time they may as well be +-converted to a list.

      +-

      Stream-fold is often used to summarize a stream +-in a single value, for instance, to compute the maximum element of a stream.

      ++converted to a list.

      ++

      Stream-fold is often used to summarize a stream ++in a single value, for instance, to compute the maximum element of a stream.

      + +-

      (define (stream-maximum lt? strm)
      ++

      ++(define (stream-maximum lt? strm)
      +   (stream-fold
      +     (lambda (x y) (if (lt? x y) y x))
      +     (stream-car strm)
      +-    (stream-cdr strm)))

      ++ (stream-cdr strm)))

      + +-

      Sometimes, +-it is useful to have stream-fold defined only on non-null streams:

      ++

      Sometimes, ++it is useful to have stream-fold defined only on non-null streams:

      + +-

      (define (stream-fold-one proc strm)
      ++

      ++(define (stream-fold-one proc strm)
      +   (stream-fold proc
      +     (stream-car strm)
      +-    (stream-cdr strm)))

      ++ (stream-cdr strm)))

      + +-

      Stream-minimum can then be defined as:

      ++

      Stream-minimum can then be defined as:

      + +-

      (define (stream-minimum lt? strm)
      ++

      ++(define (stream-minimum lt? strm)
      +   (stream-fold-one
      +     (lambda (x y) (if (lt? x y) x y))
      +-    strm))

      ++ strm))

      + +-

      Stream-fold can also be used to build a stream:

      ++

      Stream-fold can also be used to build a stream:

      + +-

      (define-stream (isort lt? strm)
      ++

      ++(define-stream (isort lt? strm)
      +     (define-stream (insert strm x)
      +       (stream-match strm
      +         (() (stream x))
      +@@ -568,91 +603,95 @@ it is useful to have stream-fold

      ++ (stream-fold insert stream-null strm))

      + +-

      procedure: +-(stream-for-each proc stream ...)
      +-(α × β × ...) × {α} × {β} ...
      ++

      procedure: ++(stream-for-each proc stream ...)
      ++(α × β × ...) × {α} × {β} ...
      + Stream-for-each applies a procedure element-wise + to corresponding elements of the input streams for its side-effects; + it returns nothing. Stream-for-each stops as soon as any of its input +-streams is exhausted.

      +-

      The following +-procedure displays the contents of a file:

      +-

      (define (display-file filename)
      ++streams is exhausted.

      ++

      The following ++procedure displays the contents of a file:

      ++

      ++(define (display-file filename)
      +   (stream-for-each display
      +-    (file->stream filename)))

      ++ (file->stream filename)))

      + +-

      ++

      + procedure: + (stream-from first +-[step])
      +-number × number → {number}
      ++[
      step])
      ++number × number → {number}
      + Stream-from creates a newly-allocated stream that + contains first as its first element and increments each succeeding + element by step. If step is not given it defaults + to 1. + First and step may be of any numeric type. Stream-from + is frequently useful as a generator in stream-of expressions. See also stream-range +-for a similar procedure that creates finite streams.

      +-

      Stream-from could be implemented as (stream-iterate (lambda (x) (+ x step)) first).

      +-

      (define nats (stream-from +-0)) +-0 1 2 ...

      +-

      (define odds (stream-from +-1 2)) +-1 3 5 ...

      +- +-

      procedure: +-(stream-iterate proc base)
      +-(α → α) × α → {α}
      ++for a similar procedure that creates finite streams.

      ++

      Stream-from could be implemented as (stream-iterate (lambda (x) (+ x step)) first).

      ++

      (define nats (stream-from ++0)) ++0 1 2 ...

      ++

      (define odds (stream-from ++1 2)) ++1 3 5 ...

      ++ ++

      procedure: ++(stream-iterate proc base)
      ++(α → α) × α → {α}
      + Stream-iterate creates a newly-allocated stream containing + base in its first element and applies proc to each element + in turn to determine the succeeding element. See also stream-unfold +-and stream-unfolds.

      ++and stream-unfolds.

      + +-

      (stream-iterate (lambda (x) (+ x 1)) 0)
      +-  ⇒ 0 1 2 3 4 ...

      ++

      ++(stream-iterate (lambda (x) (+ x 1)) 0)
      ++  ⇒ 0 1 2 3 4 ...

      + +-

      (stream-iterate (lambda (x) (* x 2)) 1)
      +-  ⇒ 1 2 4 8 16 ...

      ++

      ++(stream-iterate (lambda (x) (* x 2)) 1)
      ++  ⇒ 1 2 4 8 16 ...

      + +-

      Given a ++

      Given a + seed between 0 and 232, exclusive, the following expression + creates a stream of pseudo-random integers between 0 and 232, exclusive, beginning with seed, +-using the method described by Stephen Park and Keith Miller:

      ++using the method described by Stephen Park and Keith Miller:

      + +-

      (stream-iterate
      ++

      
      ++(stream-iterate
      +   (lambda (x) (modulo (* x 16807) 2147483647))
      +-  seed)

      ++
      seed)

      + +-

      Successive values of the continued +-fraction shown below approach the value of the “golden ratio” φ +-≈ 1.618:

      ++

      Successive values of the continued ++fraction shown below approach the value of the “golden ratio” φ ++≈ 1.618:

      + +-

      Continued fraction

      ++

      Continued fraction

      + +-

      The fractions +-can be calculated by the stream

      ++

      The fractions ++can be calculated by the stream

      + +-

      (stream-iterate +-(lambda (x) (+ 1 (/ x))) 1)

      ++

      (stream-iterate ++(lambda (x) (+ 1 (/ x))) 1)

      + +-

      procedure: +-(stream-length stream)
      +-{α} → nat
      ++

      procedure: ++(stream-length stream)
      ++{α} → nat
      + Stream-length takes an input stream and returns + the number of elements in the stream; it does not evaluate its + elements. Stream-length may only be used on finite streams; +-it enters an infinite loop with infinite streams.

      ++it enters an infinite loop with infinite streams.

      + +-

      (stream-length +-strm123) +-3

      ++

      (stream-length ++strm123) ++3

      + +-

      syntax: ++

      syntax: + (stream-let tag +-((var expr) ...) body)
      ++((
      var expr) ...) body)
      + Stream-let creates a local scope that binds each + variable to the value of its corresponding expression. + It additionally binds tag to a procedure which takes the bound +@@ -662,52 +701,55 @@ body, and may be called recursively. When the expanded expression + defined by the stream-let is evaluated, stream-let evaluates the expressions in its + body in an environment containing the newly-bound variables, + returning the value of the last expression evaluated, which must yield +-a stream.

      ++a stream.

      + +-

      Stream-let provides syntactic sugar on stream-lambda, ++

      Stream-let provides syntactic sugar on stream-lambda, + in the same manner as normal let provides syntactic sugar on normal lambda. + However, unlike normal let, the tag is required, not optional, +-because unnamed stream-let is meaningless.

      ++because unnamed stream-let is meaningless.

      + +-

      Stream-member returns the first stream-pair of the ++

      Stream-member returns the first stream-pair of the + input strm +-with a stream-car x that satisfies (eql? obj x).

      ++with a stream-car x that satisfies (eql? obj x), ++or the null stream if x is not present in strm.

      + +-

      (define-stream (stream-member eql? obj strm)
      ++

      ++(define-stream (stream-member eql? obj strm)
      +   (stream-let loop ((strm strm))
      +-    (cond ((stream-null? strm) #f)
      ++    (cond ((stream-null? strm) strm)
      +           ((eql? obj (stream-car strm)) strm)
      +-          (else (loop (stream-cdr strm))))))

      ++ (else (loop (stream-cdr strm))))))

      + +-

      procedure: +-(stream-map proc stream ...)
      +-(α × β ... → ω) × {α} × {β} ... → {ω}
      ++

      procedure: ++(stream-map proc stream ...)
      ++(α × β ... → ω) × {α} × {β} ... → {ω}
      + Stream-map applies a procedure element-wise + to corresponding elements of the input streams, returning a newly-allocated + stream containing elements that are the results of those procedure + applications. The output stream has as many elements as the minimum-length +-input stream, and may be infinite.

      ++input stream, and may be infinite.

      + +-

      (define (square +-x) (* x x))

      ++

      (define (square ++x) (* x x))

      + +-

      (stream-map square +-(stream 9 3)) ⇒ 81 9

      ++

      (stream-map square ++(stream 9 3)) ⇒ 81 9

      + +-

      (define (sigma f m n)
      ++

      ++(define (sigma f m n)
      +   (stream-fold + 0
      +-    (stream-map f (stream-range m (+ n 1)))))

      ++ (stream-map f (stream-range m (+ n 1)))))

      + +-

      (sigma square 1 +-100) ⇒ 338350

      ++

      (sigma square 1 ++100) ⇒ 338350

      + +-

      In some functional ++

      In some functional + languages, stream-map takes only a single input stream, + and stream-zipwith provides a companion function that +-takes multiple input streams.

      ++takes multiple input streams.

      + +-

      syntax: +-(stream-match stream clause ...)
      ++

      syntax: ++(stream-match stream clause ...)
      + Stream-match provides the syntax of pattern-matching + for streams. The input stream is an expression that evaluates + to a stream. Clauses are of the form (pattern +@@ -715,66 +757,69 @@ to a stream. Clauses are of the form (pattern
      that matches a stream of a particular + shape, an optional fender that must succeed if the pattern is + to match, and an expression that is evaluated if the pattern +-matches. There are four types of patterns:

      ++matches. There are four types of patterns:

      + +-
        +-
      • () +- — Matches the null stream.
      • ++
          ++
        • () ++ — Matches the null stream.
        • +
        • (pat0 pat1 ...) +- — Matches a finite stream with length exactly equal to the number ++ — Matches a finite stream with length exactly equal to the number + of pattern elements.
        • +
        • (pat0 pat1 ... . patrest) +- — Matches an infinite stream, or a finite stream with length at least ++ — Matches an infinite stream, or a finite stream with length at least + as great as the number of pattern elements before the literal dot.
        • +-
        • pat — Matches ++
        • pat — Matches + an entire stream. Should always appear last in the list of clauses; +- it’s not an error to appear elsewhere, but subsequent clauses could ++ it’s not an error to appear elsewhere, but subsequent clauses could + never match.
        • +-
        ++
      + +-

      Each pattern +-element pati may be either:

      ++

      Each pattern ++element pati may be either:

      + +-
        +-
      • An identifier — ++
          ++
        • An identifier — + Matches any stream element. Additionally, the value of the stream + element is bound to the variable named by the identifier, which is in + scope in the fender and expression of the corresponding clause. + Each identifier in a single pattern must be unique.
        • +
        • A literal underscore +- — Matches any stream element, but creates no bindings.
        • +-
        ++ — Matches any stream element, but creates no bindings.
      • ++
      + +-

      The patterns ++

      The patterns + are tested in order, left-to-right, until a matching pattern is found; + if fender is present, it must evaluate as non-#f for the match to be successful. + Pattern variables are bound in the corresponding fender and + expression. Once the matching pattern is found, the corresponding + expression is evaluated and returned as the result of the match. +-An error is signaled if no pattern matches the input stream.

      ++An error is signaled if no pattern matches the input stream.

      + +-

      Stream-match is often used to distinguish null +-streams from non-null streams, binding head and tail:

      ++

      Stream-match is often used to distinguish null ++streams from non-null streams, binding head and tail:

      + +-

      (define (len strm)
      ++

      ++(define (len strm)
      +   (stream-match strm
      +     (() 0)
      +-    ((head . tail) (+ 1 (len tail)))))

      ++ ((head . tail) (+ 1 (len tail)))))

      + +-

      Fenders can ++

      Fenders can + test the common case where two stream elements must be identical; the else + pattern is an identifier bound to the entire stream, not a keyword as +-in cond.

      ++in cond.

      + +-

      (stream-match strm
      ++

      ++(stream-match strm
      +   ((x y . _) (equal? x y) 'ok)
      +-  (else 'error))

      ++ (else 'error))

      + +-

      A more complex ++

      A more complex + example uses two nested matchers to match two different stream arguments; (stream-merge lt? . strms) +-stably merges two or more streams ordered by the lt? predicate:

      ++stably merges two or more streams ordered by the lt? predicate:

      + +-

      (define-stream (stream-merge lt? . strms)
      ++

      ++(define-stream (stream-merge lt? . strms)
      +   (define-stream (merge xx yy)
      +     (stream-match xx (() yy) ((x . xs)
      +       (stream-match yy (() xx) ((y . ys)
      +@@ -786,34 +831,34 @@ stably merges two or more streams ordered by the l
      +           ((null? (cdr strms)) (car strms))
      +           (else (merge (car strms)
      +                        (apply stream-merge lt?
      +-                         (cdr strms)))))))

      ++ (cdr strms)))))))

      + +-

      syntax: +-(stream-of expr clause ...)
      ++

      syntax: ++(stream-of expr clause ...)
      + Stream-of provides the syntax of stream comprehensions, + which generate streams by means of looping expressions. The result + is a stream of objects of the type returned by expr. There +-are four types of clauses:

      ++are four types of clauses:

      + +-
        +-
      • (var in stream-expr) +- — Loop over the elements of stream-expr, in order from the ++
          ++
        • (var in stream-expr) ++ — Loop over the elements of stream-expr, in order from the + start of the stream, binding each element of the stream in turn to + var. Stream-from and stream-range are frequently useful as generators + for stream-expr.
        • +
        • (var is expr) +- — Bind var to the value obtained by evaluating expr.
        • ++ — Bind var to the value obtained by evaluating expr.
          +
        • (pred? expr) +- — Include in the output stream only those elements x for which (pred? x) ++ — Include in the output stream only those elements x for which (pred? x) + is non-#f.
        • +-
        ++
      + +-

      The scope of ++

      The scope of + variables bound in the stream comprehension is the clauses to the + right of the binding clause (but not the binding clause itself) plus +-the result expression.

      ++the result expression.

      + +-

      When two or ++

      When two or + more generators are present, the loops are processed as if they are + nested from left to right; that is, the rightmost generator varies fastest. + A consequence of this is that only the first generator may be infinite +@@ -821,27 +866,30 @@ and all subsequent generators must be finite. If no generators + are present, the result of a stream comprehension is a stream containing + the result expression; thus, (stream-of + 1) produces a finite stream +-containing only the element 1.

      ++containing only the element 1.

      + +-

      (stream-of (* x x)
      ++

      ++(stream-of (* x x)
      +   (x in (stream-range 0 10))
      +   (even? x))
      +-  ⇒ 0 4 16 36 64

      ++ ⇒ 0 4 16 36 64

      + +-

      (stream-of (list a b)
      ++

      ++(stream-of (list a b)
      +   (a in (stream-range 1 4))
      +   (b in (stream-range 1 3))) 
      +-  ⇒ (1 1) (1 2) (2 1) (2 2) (3 1) (3 2)

      ++ ⇒ (1 1) (1 2) (2 1) (2 2) (3 1) (3 2)

      + +-

      (stream-of (list i j)
      ++

      ++(stream-of (list i j)
      +   (i in (stream-range 1 5))
      +   (j in (stream-range (+ i 1) 5)))
      +-  ⇒ (1 2) (1 3) (1 4) (2 3) (2 4) (3 4)

      ++ ⇒ (1 2) (1 3) (1 4) (2 3) (2 4) (3 4)

      + +-

      procedure: ++

      procedure: + (stream-range first past +-[step])
      +-number × number × number → {number}
      ++[
      step])
      ++number × number × number → {number}
      + Stream-range creates a newly-allocated stream that + contains first as its first element and increments each succeeding + element by step. The stream is finite and ends before +@@ -852,170 +900,179 @@ otherwise. First, past and step may be of + any numeric type. Stream-range is frequently useful as a generator + in stream-of + expressions. See also stream-from for a similar procedure that creates +-infinite streams.

      ++infinite streams.

      + +-

      (stream-range 0 +-10) ⇒ 0 1 2 3 4 5 6 7 8 9

      ++

      (stream-range 0 ++10) ⇒ 0 1 2 3 4 5 6 7 8 9

      + +-

      (stream-range 0 +-10 2) → 0 2 4 6 8

      ++

      (stream-range 0 ++10 2) → 0 2 4 6 8

      + +-

      Successive ++

      Successive + elements of the stream are calculated by adding step to first, + so if any of first, past or step are inexact, the + length of the output stream may differ from (ceiling +-(- (/ (- past first) step) 1).

      ++(- (/ (- past first) step) 1).

      + +-

      procedure: +-(stream-ref stream n)
      +-{α} × nat → α
      ++

      procedure: ++(stream-ref stream n)
      ++{α} × nat → α
      + Stream-ref returns the nth element of + stream, counting from zero. An error is signaled if n +-is greater than or equal to the length of stream.

      ++is greater than or equal to the length of stream.

      + +-

      (define (fact n)
      ++

      ++(define (fact n)
      +   (stream-ref
      +     (stream-scan * 1 (stream-from 1))
      +-    n))

      ++ n))

      + +-

      procedure: +-(stream-reverse stream)
      +-{α} → {α}
      ++

      procedure: ++(stream-reverse stream)
      ++{α} → {α}
      + Stream-reverse returns a newly-allocated stream containing + the elements of the input stream but in reverse order. Stream-reverse + may only be used with finite streams; it enters an infinite loop with + infinite streams. Stream-reverse does not force evaluation of the elements +-of the stream.

      ++of the stream.

      + +-

      > (define s (stream 1 (/ 1 0) -1))
      ++

      ++> (define s (stream 1 (/ 1 0) -1))
      + > (define r (stream-reverse s))
      + > (stream-ref r 0)
      + > (stream-ref r 2)
      + 1
      + > (stream-ref r 1)
      +-error: division by zero

      ++error: division by zero

      + +-

      procedure: +-(stream-scan proc base stream)
      +-(α × β → α) × α × {β} → {α}
      ++

      procedure: ++(stream-scan proc base stream)
      ++(α × β → α) × α × {β} → {α}
      + Stream-scan accumulates the partial folds of an + input stream into a newly-allocated output stream. The + output stream is the base followed by (stream-fold + proc base (stream-take i stream)) +-for each of the first i elements of stream.

      ++for each of the first i elements of stream.

      + +-

      (stream-scan + 0 (stream-from 1))
      +-  ⇒ (stream 0 1 3 6 10 15 ...)

      ++

      ++(stream-scan + 0 (stream-from 1))
      ++  ⇒ (stream 0 1 3 6 10 15 ...)

      + +-

      (stream-scan * 1 (stream-from 1))
      +-  ⇒ (stream 1 1 2 6 24 120 ...)

      ++

      ++(stream-scan * 1 (stream-from 1))
      ++  ⇒ (stream 1 1 2 6 24 120 ...)

      + +-

      procedure: +-(stream-take n stream)
      +-nat × {α} → {α}
      ++

      procedure: ++(stream-take n stream)
      ++nat × {α} → {α}
      + Stream-take takes a non-negative integer n + and a stream and returns a newly-allocated stream containing + the first n elements of the input stream. If the + input stream has less than n elements, so does the output +-stream. See also stream-drop.

      ++stream. See also stream-drop.

      + +-

      Mergesort splits ++

      Mergesort splits + a stream into two equal-length pieces, sorts them recursively and merges +-the results:

      ++the results:

      + +-

      (define-stream (msort lt? strm)
      ++

      ++(define-stream (msort lt? strm)
      +   (let* ((n (quotient (stream-length strm) 2))
      +          (ts (stream-take n strm))
      +          (ds (stream-drop n strm)))
      +     (if (zero? n)
      +         strm
      +         (stream-merge lt?
      +-          (msort < ts) (msort < ds)))))

      ++ (msort < ts) (msort < ds)))))

      + +-

      procedure: +-(stream-take-while pred? stream)
      +-(α → boolean) × {α} → {α}
      ++

      procedure: ++(stream-take-while pred? stream)
      ++(α → boolean) × {α} → {α}
      + Stream-take-while takes a predicate and a stream + and returns a newly-allocated stream containing those elements x + that form the maximal prefix of the input stream for which (pred? x) + is non-#f. +-See also stream-drop-while.

      ++See also stream-drop-while.

      + +-

      (stream-car
      ++

      ++(stream-car
      +   (stream-reverse
      +     (stream-take-while
      +       (lambda (x) (< x 1000))
      +-        primes))) ⇒ 997

      ++ primes))) ⇒ 997

      + +-

      procedure: +-(stream-unfold map pred? gen base)
      +-(α → β) × (α → boolean) × (α → α) × α → {β}
      ++

      procedure: ++(stream-unfold map pred? gen base)
      ++(α → β) × (α → boolean) × (α → α) × α → {β}
      + Stream-unfold is the fundamental recursive stream + constructor. It constructs a stream by repeatedly applying + gen to successive values of base, in the manner of stream-iterate, + then applying map to each of the values so generated, appending + each of the mapped values to the output stream as long as (pred? base) + is non-#f. +-See also stream-iterate and stream-unfolds.

      ++See also stream-iterate and stream-unfolds.

      + +-

      The expression ++

      The expression + below creates the finite stream 0 1 4 9 16 25 36 49 64 81. Initially the base is 0, which is less than 10, so map squares the base + and the mapped value becomes the first element of the output stream. + Then gen increments the base by 1, so it becomes 1; this is less than 10, so map squares the new base + and 1 + becomes the second element of the output stream. And so on, until + the base becomes 10, when pred? stops the recursion +-and stream-null ends the output stream.

      ++and stream-null ends the output stream.

      + +-

      (stream-unfold
      ++

      ++(stream-unfold
      +   (lambda (x) (expt x 2)) ; map
      +   (lambda (x) (< x 10))   ; pred?
      +   (lambda (x) (+ x 1))    ; gen
      +-  0)                      ; base

      ++ 0) ; base

      + +-

      procedure: +-(stream-unfolds proc seed)
      +-(α → (values α × β ...)) × α → (values {β} ...)
      ++

      procedure: ++(stream-unfolds proc seed)
      ++(α → (values α × β ...)) × α → (values {β} ...)
      + Stream-unfolds returns n newly-allocated streams + containing those elements produced by successive calls to the generator + proc, which takes the current seed as its argument and returns + n+1 +-values

      ++values

      + +-

      (proc seedseed result0 ... resultn-1

      ++

      (proc seedseed result0 ... resultn-1

      + +-

      where the returned ++

      where the returned + seed is the input seed to the next call to the generator + and resulti indicates how to produce the next +-element of the ith result stream:

      ++element of the ith result stream:

      + +-
        +-
      • (value) +- — value is the next car of the result stream
      • ++
          ++
        • (value) ++ — value is the next car of the result stream
        • +
        • #f +- — no value produced by this iteration of the generator proc ++ — no value produced by this iteration of the generator proc + for the result stream
        • +
        • () +- — the end of the result stream
        • +-
        ++ — the end of the result stream ++
      + +-

      It may require ++

      It may require + multiple calls of proc to produce the next element of any particular +-result stream. See also stream-iterate and stream-unfold.

      ++result stream. See also stream-iterate and stream-unfold.

      + +-

      Stream-unfolds is especially useful when writing ++

      Stream-unfolds is especially useful when writing + expressions that return multiple streams. For instance, (stream-partition pred? strm) +-is equivalent to

      ++is equivalent to

      + +-

      (values
      ++

      
      ++(values
      +   (stream-filter pred? strm)
      +   (stream-filter
      +-    (lambda (x) (not (pred? x))) strm))

      ++ (lambda (x) (not (
      pred? x))) strm))

      + +-

      but only tests +-pred? once for each element of strm.

      ++

      but only tests ++pred? once for each element of strm.

      + +-

      (define (stream-partition pred? strm)
      ++

      ++(define (stream-partition pred? strm)
      +   (stream-unfolds
      +     (lambda (s)
      +       (if (stream-null? s)
      +@@ -1025,95 +1082,102 @@ pred? once for each element of strm.

      + (if (pred? a) + (values d (list a) #f) + (values d #f (list a)))))) +- strm))

      ++ strm))

      + +-

      (call-with-values
      ++

      ++(call-with-values
      +   (lambda ()
      +     (stream-partition odd?
      +       (stream-range 1 6)))
      +   (lambda (odds evens)
      +     (list (stream->list odds)
      +           (stream->list evens))))
      +-  ⇒ ((1 3 5) (2 4))

      ++ ⇒ ((1 3 5) (2 4))

      + +-

      procedure: +-(stream-zip stream ...)
      +-{α} × {β} × ... → {[α β ...]}
      ++

      procedure: ++(stream-zip stream ...)
      ++{α} × {β} × ... → {[α β ...]}
      + Stream-zip takes one or more input streams + and returns a newly-allocated stream in which each element is a list + (not a stream) of the corresponding elements of the input streams. + The output stream is as long as the shortest input stream, if + any of the input streams is finite, or is infinite if all the +-input streams are infinite.

      ++input streams are infinite.

      + +-

      A common use ++

      A common use + of stream-zip + is to add an index to a stream, as in (stream-finds eql? obj strm), which returns all the zero-based + indices in strm at which obj appears; (stream-find eql? obj strm) returns the first such index, or #f +-if obj is not in strm.

      ++if obj is not in strm.

      + +-

      (define-stream (stream-finds eql? obj strm)
      ++

      ++(define-stream (stream-finds eql? obj strm)
      +   (stream-of (car x)
      +     (x in (stream-zip (stream-from 0) strm))
      +-    (eql? obj (cadr x))))

      ++ (eql? obj (cadr x))))

      + +-

      (define (stream-find eql? obj strm)
      ++

      ++(define (stream-find eql? obj strm)
      +   (stream-car
      +     (stream-append
      +       (stream-finds eql? obj strm)
      +-      (stream #f))))

      ++ (stream #f))))

      + +-

      (stream-find char=? #\l
      ++

      ++(stream-find char=? #\l
      +   (list->stream
      +-    (string->list "hello"))) ⇒ 2

      ++ (string->list "hello"))) ⇒ 2

      + +-

      (stream-find char=? #\l
      ++

      ++(stream-find char=? #\l
      +   (list->stream
      +-    (string->list "goodbye"))) ⇒ #f

      ++ (string->list "goodbye"))) ⇒ #f

      + +-

      Stream-find is not as inefficient as it looks; ++

      Stream-find is not as inefficient as it looks; + although it calls stream-finds, which finds all matching indices, + the matches are computed lazily, and only the first match is needed +-for stream-find.

      ++for stream-find.

      + +-

      Utilities

      ++

      Utilities

      + +-

      Streams, being ++

      Streams, being + the signature structured data type of functional programming languages, + find useful expression in conjunction with higher-order functions. + Some of these higher-order functions, and their relationship to streams, +-are described below.

      ++are described below.

      + +-

      The identity ++

      The identity + and constant procedures are frequently useful as the recursive base + for maps and folds; (identity obj) always returns obj, and (const obj) + creates a procedure that takes any number of arguments and always returns +-the same obj, no matter its arguments:

      ++the same obj, no matter its arguments:

      + +-

      (define (identity +-obj) obj)

      ++

      (define (identity ++obj) obj)

      + +-

      (define (const +-obj) (lambda x obj))

      ++

      (define (const ++obj) (lambda x obj))

      + +-

      Many of the ++

      Many of the + stream procedures take a unary predicate that accepts an element of + a stream and returns a boolean. Procedure (negate pred?) takes a unary predicate and returns + a new unary predicate that, when called, returns the opposite boolean +-value as the original predicate.

      ++value as the original predicate.

      + +-

      (define (negate pred?)
      +-  (lambda (x) (not (pred? x))))

      ++

      ++(define (negate pred?)
      ++  (lambda (x) (not (pred? x))))

      + +-

      Negate is useful for procedures like stream-take-while ++

      Negate is useful for procedures like stream-take-while + that take a predicate, allowing them to be used in the opposite direction + from which they were written; for instance, with the predicate reversed, stream-take-while +-becomes stream-take-until. Stream-remove is the opposite of stream-filter:

      ++becomes stream-take-until. Stream-remove is the opposite of stream-filter:

      + +-

      (define-stream (stream-remove pred? strm)
      +-  (stream-filter (negate pred?) strm))

      ++

      ++(define-stream (stream-remove pred? strm)
      ++  (stream-filter (negate pred?) strm))

      + +-

      A section is ++

      A section is + a procedure which has been partially applied to some of its arguments; + for instance, (double x), which returns twice its argument, + is a partial application of the multiply operator to the number 2. +@@ -1125,34 +1189,37 @@ and some prefix of its arguments and returns a new procedure in which + those arguments are partially applied. Procedure (rsec proc args + ...) takes a procedure + and some reversed suffix of its arguments and returns a new procedure +-in which those arguments are partially applied.

      ++in which those arguments are partially applied.

      + +-

      (define (lsec proc . args)
      +-  (lambda x (apply proc (append args x))))

      ++

      ++(define (lsec proc . args)
      ++  (lambda x (apply proc (append args x))))

      + +-

      (define (rsec proc . args)
      ++

      ++(define (rsec proc . args)
      +   (lambda x (apply proc (reverse
      +-    (append (reverse args) (reverse x))))))

      ++ (append (reverse args) (reverse x))))))

      + +-

      Since most ++

      Since most + of the stream procedures take a stream as their last (right-most) argument, +-left sections are particularly useful in conjunction with streams.

      ++left sections are particularly useful in conjunction with streams.

      + +-

      (define stream-sum +-(lsec stream-fold + 0))

      ++

      (define stream-sum ++(lsec stream-fold + 0))

      + +-

      Function composition ++

      Function composition + creates a new function by partially applying multiple functions, one + after the other. In the simplest case there are only two functions, f + and g, +-composed as ((compose f g) ≡ x)); ++composed as ((compose f g) ≡ x)); + the composition can be bound to create a new function, as in (define fg (compose f g)). + Procedure (compose proc + ...) takes one or more + procedures and returns a new procedure that performs the same action +-as the individual procedures would if called in succession.

      ++as the individual procedures would if called in succession.

      + +-

      (define (compose . fns)
      ++

      ++(define (compose . fns)
      +   (let comp ((fns fns))
      +     (cond
      +       ((null? fns) 'error)
      +@@ -1164,107 +1231,114 @@ as the individual procedures would if called in succession.
      +               (apply
      +                 (comp (cdr fns))
      +                 args))
      +-            (car fns)))))))

      ++ (car fns)))))))

      + +-

      Compose works with sections to create succinct ++

      Compose works with sections to create succinct + but highly expressive procedure definitions. The expression to + compute the squares of the integers from 1 to 10 given above at stream-unfold could be written by composing stream-map, stream-take-while, +-and stream-iterate:

      ++and stream-iterate:

      + +-

      ((compose
      ++

      ++((compose
      +   (lsec stream-map (rsec expt 2))
      +   (lsec stream-take-while (negate (rsec > 10)))
      +   (lsec stream-iterate (rsec + 1)))
      +- 1)

      ++ 1)

      + +-

      Examples

      ++

      Examples

      + +-

      The examples ++

      The examples + below show a few of the myriad ways streams can be exploited, as well + as a few ways they can trip the unwary user. All the examples + are drawn from published sources; it is instructive to compare the Scheme +-versions to the originals in other languages.

      ++versions to the originals in other languages.

      + +-

      Infinite streams

      ++

      Infinite streams

      + +-

      As a simple ++

      As a simple + illustration of infinite streams, consider this definition of the natural +-numbers:

      ++numbers:

      + +-

      (define nats
      ++

      ++(define nats
      +   (stream-cons 0
      +-    (stream-map add1 nats)))

      ++ (stream-map add1 nats)))

      + +-

      The recursion ++

      The recursion + works because it is offset by one from the initial stream-cons. Another sequence that uses +-the offset trick is this definition of the fibonacci numbers:

      ++the offset trick is this definition of the fibonacci numbers:

      + +-

      (define fibs
      ++

      ++(define fibs
      +   (stream-cons 1
      +     (stream-cons 1
      +       (stream-map +
      +         fibs
      +-        (stream-cdr fibs)))))

      ++ (stream-cdr fibs)))))

      + +-

      Yet another ++

      Yet another + sequence that uses the same offset trick is the Hamming numbers, named + for the mathematician and computer scientist Richard Hamming, defined + as all numbers that have no prime factors greater than 5; in other words, +-Hamming numbers are all numbers expressible as 2i·3j·5k, ++Hamming numbers are all numbers expressible as 2i·3j·5k, + where i, j and k are non-negative integers. The + Hamming sequence starts with 1 + 2 3 4 5 6 8 9 10 12 and + is computed starting with 1, taking 2, 3 and 5 times all the previous elements with stream-map, +-then merging sub-streams and eliminating duplicates.

      ++then merging sub-streams and eliminating duplicates.

      + +-

      (define hamming
      ++

      ++(define hamming
      +   (stream-cons 1
      +     (stream-unique =
      +       (stream-merge <
      +         (stream-map (lsec * 2) hamming)
      +         (stream-map (lsec * 3) hamming)
      +-        (stream-map (lsec * 5) hamming)))))

      ++ (stream-map (lsec * 5) hamming)))))

      + +-

      It is possible ++

      It is possible + to have an infinite stream of infinite streams. Consider the definition +-of power-table:

      ++of power-table:

      + +-

      (define power-table
      ++

      ++(define power-table
      +   (stream-of
      +     (stream-of (expt m n)
      +       (m in (stream-from 1)))
      +-      (n in (stream-from 2))))

      ++ (n in (stream-from 2))))

      + +-

      which evaluates +-to an infinite stream of infinite streams:

      ++

      which evaluates ++to an infinite stream of infinite streams:

      + +-

      ++

      + (stream
      +   (stream 1 4 9 16 25 ...)
      +   (stream 1 8 27 64 125 ...)
      +   (stream 1 16 81 256 625 ...)
      +-  ...)

      ++ ...)

      + +-

      But even though ++

      But even though + it is impossible to display power-table in its entirety, it is possible to +-select just part of it:

      ++select just part of it:

      + +-

      (stream->list 10 (stream-ref power-table 1))
      +-  ⇒ (1 8 27 64 125 216 343 512 729 1000)

      ++

      ++(stream->list 10 (stream-ref power-table 1))
      ++  ⇒ (1 8 27 64 125 216 343 512 729 1000)

      + +-

      This example ++

      This example + clearly shows that the elements of a stream are computed lazily, as + they are needed; (stream-ref + power-table 0) is not computed, + even when its successor is displayed, since computing it would enter +-an infinite loop.

      ++an infinite loop.

      + +-

      Chris Reade ++

      Chris Reade + shows how to calculate the stream of prime numbers according to the + sieve of Eratosthenes, using a method that eliminates multiples of the +-sifting base with addition rather than division:

      ++sifting base with addition rather than division:

      + +-

      (define primes (let ()
      ++

      ++(define primes (let ()
      +   (define-stream (next base mult strm)
      +     (let ((first (stream-car strm))
      +           (rest (stream-cdr strm)))
      +@@ -1282,32 +1356,33 @@ sifting base with addition rather than division:

      + (rest (stream-cdr strm))) + (stream-cons first + (sieve (sift first rest))))) +- (sieve (stream-from 2))))

      ++ (sieve (stream-from 2))))

      + +-

      A final example ++

      A final example + of infinite streams is a functional pearl from Jeremy Gibbons, David + Lester and Richard Bird that enumerates the positive rational numbers +-without duplicates:

      ++without duplicates:

      + +-

      (define rats
      ++

      ++(define rats
      +   (stream-iterate
      +     (lambda (x)
      +       (let* ((n (floor x)) (y (- x n)))
      +         (/ (- n -1 y))))
      +-    1))

      ++ 1))

      + +-

      Backtracking via the stream of successes

      ++

      Backtracking via the stream of successes

      + +-

      Philip Wadler ++

      Philip Wadler + describes the stream of successes technique that uses streams + to perform backtracking search. The basic idea is that each procedure + returns a stream of possible results, so that its caller can decide + which result it wants; an empty stream signals failure, and causes backtracking + to a previous choice point. The stream of successes technique + is useful because the program is written as if to simply enumerate all +-possible solutions; no backtracking is explicit in the code.

      ++possible solutions; no backtracking is explicit in the code.

      + +-

      The Eight Queens ++

      The Eight Queens + puzzle, which asks for a placement of eight queens on a chessboard so + that none of them attack any other, is an example of a problem that + can be solved using the stream of successes technique. The algorithm +@@ -1318,45 +1393,48 @@ Then a queen is placed in the third column, in any position not held + in check by the queens in the first two columns. And so on, until + all eight queens have been placed. If at any point there is no + legal placement for the next queen, backtrack to a different legal position +-for the previous queens, and try again.

      ++for the previous queens, and try again.

      + +-

      The chessboard ++

      The chessboard + is represented as a stream of length m, where there are queens + in the first m columns, each position in the stream representing + the rank on which the queen appears in that column. For example, + stream 4 6 1 5 2 8 3 7 +-represents the following chessboard:

      ++represents the following chessboard:

      + +-

      Chessboard

      ++

      Chessboard

      + +-

      Two queens ++

      Two queens + at column i row j and column m row n check + each other if their columns i and m are the same, or if + their rows j and n are the same, or if they are on the + same diagonal with i + j = m + n or i +-– j = mn. There is no need to test ++– j = mn. There is no need to test + the columns, because the placement algorithm enforces that they differ, + so the check? +-procedure tests if two queens hold each other in check.

      ++procedure tests if two queens hold each other in check.

      + +-

      (define (check? i j m n)
      ++

      ++(define (check? i j m n)
      +   (or (= j n)
      +       (= (+ i j) (+ m n))
      +-      (= (- i j) (- m n))))

      ++ (= (- i j) (- m n))))

      + +-

      The algorithm ++

      The algorithm + walks through the columns, extending position p by adding a new + queen in row n with (stream-append p + (stream n)). Safe? +-tests if it is safe to do so, using the utility procedure stream-and.

      ++tests if it is safe to do so, using the utility procedure stream-and.

      + +-

      (define (stream-and strm)
      ++

      ++(define (stream-and strm)
      +   (let loop ((strm strm))
      +     (cond ((stream-null? strm) #t)
      +           ((not (stream-car strm)) #f)
      +-          (else (loop (stream-cdr strm))))))

      ++ (else (loop (stream-cdr strm))))))

      + +-

      (define (safe? p n)
      ++

      ++(define (safe? p n)
      +   (let* ((len (stream-length p))
      +          (m (+ len 1)))
      +     (stream-and
      +@@ -1364,86 +1442,91 @@ tests if it is safe to do so, using the utility procedure Procedure (queens m) 
      ++

      Procedure (queens m) + returns all the ways that queens can safely be placed in the first +-m columns.

      ++m
      columns.

      + +-

      (define (queens m)
      ++

      ++(define (queens m)
      +   (if (zero? m)
      +       (stream (stream))
      +       (stream-of (stream-append p (stream n))
      +         (p in (queens (- m 1)))
      +         (n in (stream-range 1 9))
      +-        (safe? p n))))

      ++ (safe? p n))))

      + +-

      To see the +-first solution to the Eight Queens problem, say

      +-

      (stream->list +-(stream-car (queens 8)))

      ++

      To see the ++first solution to the Eight Queens problem, say

      ++

      (stream->list ++(stream-car (queens 8)))

      + +-

      To see all +-92 solutions, say

      ++

      To see all ++92 solutions, say

      + +-

      (stream->list
      ++

      ++(stream->list
      +   (stream-map stream->list
      +-    (queens 8)))

      ++ (queens 8)))

      + +-

      There is no ++

      There is no + explicit backtracking in the code. The stream-of expression in queens returns all possible streams that + satisfy safe?; +-implicit backtracking occurs in the recursive call to queens.

      ++implicit backtracking occurs in the recursive call to
      queens.

      + +-

      Generators and co-routines

      ++

      Generators and co-routines

      + +-

      It is possible ++

      It is possible + to model generators and co-routines using streams. Consider the task, + due to Carl Hewitt, of determining if two trees have the same sequence +-of leaves:

      ++of leaves:

      + +-

      (same-fringe? = +-'(1 (2 3)) '((1 2) 3)) ⇒ #t

      ++

      (same-fringe? = ++'(1 (2 3)) '((1 2) 3)) ⇒ #t

      + +-

      (same-fringe? = +-'(1 2 3) '(1 (3 2))) ⇒ #f

      ++

      (same-fringe? = ++'(1 2 3) '(1 (3 2))) ⇒ #f

      + +-

      The simplest +-solution is to flatten both trees into lists and compare them element-by-element:

      ++

      The simplest ++solution is to flatten both trees into lists and compare them element-by-element:

      + +-

      (define (flatten tree)
      ++

      ++(define (flatten tree)
      +   (cond ((null? tree) '())
      +         ((pair? (car tree))
      +           (append (flatten (car tree))
      +                   (flatten (cdr tree))))
      +         (else (cons (car tree)
      +-                    (flatten (cdr tree))))))

      ++ (flatten (cdr tree))))))

      + +-

      (define (same-fringe? eql? tree1 tree2)
      ++

      ++(define (same-fringe? eql? tree1 tree2)
      +   (let loop ((t1 (flatten tree1))
      +              (t2 (flatten tree2)))
      +     (cond ((and (null? t1) (null? t2)) #t)
      +           ((or (null? t1) (null? t2)) #f)
      +           ((not (eql? (car t1) (car t2))) #f)
      +-          (else (loop (cdr t1) (cdr t2))))))

      ++ (else (loop (cdr t1) (cdr t2))))))

      + +-

      That works, ++

      That works, + but requires time to flatten both trees and space to store the flattened + versions; if the trees are large, that can be a lot of time and space, +-and if the fringes differ, much of that time and space is wasted.

      +-

      Hewitt used ++and if the fringes differ, much of that time and space is wasted.

      ++

      Hewitt used + a generator to flatten the trees one element at a time, storing only + the current elements of the trees and the machines needed to continue + flattening them, so same-fringe? could stop early if the trees differ. + Dorai Sitaram presents both the generator solution and a co-routine +-solution, which both involve tricky calls to call-with-current-continuation and careful coding to keep them synchronized.

      ++solution, which both involve tricky calls to call-with-current-continuation and careful coding to keep them synchronized.

      + +-

      An alternate ++

      An alternate + solution flattens the two trees to streams instead of lists, which accomplishes + the same savings of time and space, and involves code that looks little +-different than the list solution presented above:

      ++different than the list solution presented above:

      + +-

      (define-stream (flatten tree)
      ++

      ++(define-stream (flatten tree)
      +   (cond ((null? tree) stream-null)
      +         ((pair? (car tree))
      +           (stream-append
      +@@ -1451,9 +1534,10 @@ different than the list solution presented above:

      + (flatten (cdr tree)))) + (else (stream-cons + (car tree) +- (flatten (cdr tree))))))

      ++ (flatten (cdr tree))))))

      + +-

      (define (same-fringe? eql? tree1 tree2)
      ++

      ++(define (same-fringe? eql? tree1 tree2)
      +   (let loop ((t1 (flatten tree1))
      +              (t2 (flatten tree2)))
      +     (cond ((and (stream-null? t1)
      +@@ -1463,128 +1547,146 @@ different than the list solution presented above:

      + ((not (eql? (stream-car t1) + (stream-car t2))) #f) + (else (loop (stream-cdr t1) +- (stream-cdr t2))))))

      ++ (stream-cdr t2))))))

      + +-

      Note that streams, ++

      Note that streams, + a data structure, replace generators or co-routines, which are control +-structures, providing a fine example of how lazy streams enhance modularity.

      ++structures, providing a fine example of how lazy streams enhance modularity.

      + +-

      A pipeline of procedures

      ++

      A pipeline of procedures

      + +-

      Another way ++

      Another way + in which streams promote modularity is enabling the use of many small + procedures that are easily composed into larger programs, in the style + of unix pipelines, where streams are important because they allow a + large dataset to be processed one item at a time. Bird and Wadler +-provide the example of a text formatter. Their example uses right-folds:

      ++provide the example of a text formatter. Their example uses right-folds:

      + +-

      (define (stream-fold-right f base strm) 
      ++

      ++(define (stream-fold-right f base strm) 
      +   (if (stream-null? strm)
      +       base
      +       (f (stream-car strm)
      +          (stream-fold-right f base
      +-           (stream-cdr strm)))))

      ++ (stream-cdr strm)))))

      + +-

      (define (stream-fold-right-one f strm)
      ++

      ++(define (stream-fold-right-one f strm)
      +   (stream-match strm
      +   ((x) x)
      +   ((x . xs)
      +-    (f x (stream-fold-right-one f xs)))))

      ++ (f x (stream-fold-right-one f xs)))))

      + +-

      Bird and Wadler ++

      Bird and Wadler + define text as a stream of characters, and develop a standard package + for operating on text, which they derive mathematically (this assumes +-the line-separator character is a single #\newline):

      ++the line-separator character is a single #\newline):

      + +-

      (define (breakon a)
      ++

      ++(define (breakon a)
      +   (stream-lambda (x xss)
      +     (if (equal? a x)
      +         (stream-append (stream (stream)) xss)
      +         (stream-append
      +           (stream (stream-append
      +               (stream x) (stream-car xss)))
      +-          (stream-cdr xss)))))

      ++ (stream-cdr xss)))))

      + +-

      (define-stream (lines strm) 
      ++

      ++(define-stream (lines strm) 
      +   (stream-fold-right
      +     (breakon #\newline)
      +     (stream (stream))
      +-    strm))

      ++ strm))

      + +-

      (define-stream (words strm)
      ++

      ++(define-stream (words strm)
      +   (stream-filter stream-pair?
      +     (stream-fold-right
      +       (breakon #\space)
      +       (stream (stream))
      +-      strm)))

      ++ strm)))

      + +-

      (define-stream (paras strm)
      ++

      ++(define-stream (paras strm)
      +   (stream-filter stream-pair?
      +     (stream-fold-right
      +       (breakon stream-null)
      +       (stream (stream))
      +-      strm)))

      ++ strm)))

      + +-

      (define (insert a)
      ++

      ++(define (insert a)
      +   (stream-lambda (xs ys)
      +-    (stream-append xs (stream a) ys)))

      ++ (stream-append xs (stream a) ys)))

      + +-

      (define unlines
      ++

      ++(define unlines
      +   (lsec stream-fold-right-one
      +-    (insert #\newline)))

      ++ (insert #\newline)))

      + +-

      (define unwords
      ++

      ++(define unwords
      +   (lsec stream-fold-right-one
      +-    (insert #\space)))

      ++ (insert #\space)))

      + +-

      (define unparas
      ++

      ++(define unparas
      +   (lsec stream-fold-right-one
      +-    (insert stream-null)))

      ++ (insert stream-null)))

      + +-

      These versatile ++

      These versatile + procedures can be composed to count words, lines and paragraphs; the normalize +-procedure squeezes out multiple spaces and blank lines:

      ++procedure squeezes out multiple spaces and blank lines:

      + +-

      (define countlines
      +-  (compose stream-length lines))

      ++

      ++(define countlines
      ++  (compose stream-length lines))

      + +-

      (define countwords
      ++

      ++(define countwords
      +   (compose stream-length
      +            stream-concat
      +            (lsec stream-map words)
      +-           lines))

      ++ lines))

      + +-

      (define countparas
      +-  (compose stream-length paras lines))

      ++

      ++(define countparas
      ++  (compose stream-length paras lines))

      + +-

      (define parse
      ++

      ++(define parse
      +   (compose (lsec stream-map
      +              (lsec stream-map words))
      +            paras
      +-           lines))

      ++ lines))

      + +-

      (define unparse
      ++

      ++(define unparse
      +   (compose unlines
      +            unparas
      +            (lsec stream-map
      +-             (lsec stream-map unwords))))

      ++ (lsec stream-map unwords))))

      + +-

      (define normalize (compose unparse parse))

      ++

      ++(define normalize (compose unparse parse))

      + +-

      More useful ++

      More useful + than normalization is text-filling, which packs as many words onto each +-line as will fit.

      ++line as will fit.

      + +-

      (define (greedy m ws)
      ++

      ++(define (greedy m ws)
      +   (- (stream-length
      +        (stream-take-while (rsec <= m)
      +          (stream-scan
      +            (lambda (n word)
      +              (+ n (stream-length word) 1))
      +            -1
      +-           ws))) 1))

      ++ ws))) 1))

      + +-

      (define-stream (fill m ws)
      ++

      ++(define-stream (fill m ws)
      +   (if (stream-null? ws)
      +       stream-null
      +       (let* ((n (greedy m ws))
      +@@ -1592,115 +1694,130 @@ line as will fit.

      + (rstwrds (stream-drop n ws))) + (stream-append + (stream fstline) +- (fill m rstwrds)))))

      ++ (fill m rstwrds)))))

      + +-

      (define linewords
      ++

      ++(define linewords
      +   (compose stream-concat
      +-           (lsec stream-map words)))

      ++ (lsec stream-map words)))

      + +-

      (define textparas
      ++

      ++(define textparas
      +   (compose (lsec stream-map linewords)
      +            paras
      +-           lines))

      ++ lines))

      + +-

      (define (filltext m strm)
      +-  (unparse (stream-map (lsec fill m) (textparas strm))))

      ++

      ++(define (filltext m strm)
      ++  (unparse (stream-map (lsec fill m) (textparas strm))))

      + +-

      To display +-filename in lines of n characters, say:

      ++

      To display ++filename in lines of n characters, say:

      + +-

      (stream-for-each display
      +-  (filltext n (file->stream filename)))

      ++

      
      ++(stream-for-each display
      ++  (filltext n (file->stream filename)))

      + +-

      Though each ++

      Though each + operator performs only a single task, they can be composed powerfully + and expressively. The alternative is to build a single monolithic + procedure for each task, which would be harder and involve repetitive +-code. Streams ensure procedures are called as needed.

      ++code. Streams ensure procedures are called as needed.

      + +-

      Persistent data

      ++

      Persistent data

      + +-

      Queues are ++

      Queues are + one of the fundamental data structures of computer science. In + functional languages, queues are commonly implemented using two lists, + with the front half of the queue in one list, where the head of the + queue can be accessed easily, and the rear half of the queue in reverse + order in another list, where new items can easily be added to the end + of a queue. The standard form of such a queue holds that the front +-list can only be null if the rear list is also null:

      ++list can only be null if the rear list is also null:

      + +-

      (define queue-null (cons '() '())

      ++

      (define queue-null (cons '() '())

      + +-

      (define (queue-null? obj)
      +-  (and (pair? obj) (null? (car obj))))

      ++

      ++(define (queue-null? obj)
      ++  (and (pair? obj) (null? (car obj))))

      + +-

      (define (queue-check f r)
      ++

      ++(define (queue-check f r)
      +   (if (null? f)
      +       (cons (reverse r) '())
      +-      (cons f r)))

      ++ (cons f r)))

      + +-

      (define (queue-snoc q x)
      +-  (queue-check (car q) (cons x (cdr q))))

      ++

      ++(define (queue-snoc q x)
      ++  (queue-check (car q) (cons x (cdr q))))

      + +-

      (define (queue-head q)
      ++

      ++(define (queue-head q)
      +   (if (null? (car q))
      +       (error "empty queue: head")
      +-      (car (car q))))

      ++ (car (car q))))

      + +-

      (define (queue-tail q)
      ++

      ++(define (queue-tail q)
      +   (if (null? (car q))
      +       (error "empty-head: tail")
      +-      (queue-check (cdr (car q)) (cdr q))))

      ++ (queue-check (cdr (car q)) (cdr q))))

      + +-

      This queue ++

      This queue + operates in amortized constant time per operation, with two conses per + element, one when it is added to the rear list, and another when the + rear list is reversed to become the front list. Queue-snoc and queue-head operate in constant time; queue-tail +-operates in worst-case linear time when the front list is empty.

      ++operates in worst-case linear time when the front list is empty.

      + +-

      Chris Okasaki ++

      Chris Okasaki + points out that, if the queue is used persistently, its time-complexity + rises from linear to quadratic since each persistent copy of the queue + requires its own linear-time access. The problem can be fixed + by implementing the front and rear parts of the queue as streams, rather + than lists, and rotating one element from rear to front whenever the +-rear list is larger than the front list:

      ++rear list is larger than the front list:

      + +-

      (define queue-null
      +-  (cons stream-null stream-null))

      ++

      ++(define queue-null
      ++  (cons stream-null stream-null))

      + +-

      (define (queue-null? x)
      +-  (and (pair? x) (stream-null (car x))))

      ++

      ++(define (queue-null? x)
      ++  (and (pair? x) (stream-null (car x))))

      + +-

      (define (queue-check f r)
      ++

      ++(define (queue-check f r)
      +   (if (< (stream-length r) (stream-length f))
      +       (cons f r)
      +       (cons (stream-append f (stream-reverse r))
      +-            stream-null)))

      ++ stream-null)))

      + +-

      (define (queue-snoc q x)
      +-  (queue-check (car q) (stream-cons x (cdr q))))

      ++

      ++(define (queue-snoc q x)
      ++  (queue-check (car q) (stream-cons x (cdr q))))

      + +-

      (define (queue-head q)
      ++

      ++(define (queue-head q)
      +   (if (stream-null? (car q))
      +       (error "empty queue: head")
      +-      (stream-car (car q))))

      ++ (stream-car (car q))))

      + +-

      (define (queue-tail q)
      ++

      ++(define (queue-tail q)
      +   (if (stream-null? (car q))
      +       (error "empty queue: tail")
      +       (queue-check (stream-cdr (car q))
      +-                   (cdr q))))

      ++ (cdr q))))

      + +-

      Memoization ++

      Memoization + solves the persistence problem; once a queue element has moved from + rear to front, it need never be moved again in subsequent traversals + of the queue. Thus, the linear time-complexity to access all elements +-in the queue, persistently, is restored.

      ++in the queue, persistently, is restored.

      + +-

      Reducing two passes to one

      ++

      Reducing two passes to one

      + +-

      The final example ++

      The final example + is a lazy dictionary, where definitions and uses may occur in any order; + in particular, uses may precede their corresponding definitions. + This is a common problem. Many programming languages allow procedures +@@ -1710,9 +1827,10 @@ to know the address that a linker will subsequently give to variables. + The usual method is to make two passes over the data, collecting the + definitions on the first pass and emitting the uses on the second pass. + But Chris Reade shows how streams allow the dictionary to be built lazily, +-so that only a single pass is needed. Consider a stream of requests:

      ++so that only a single pass is needed. Consider a stream of requests:

      + +-

      (define requests
      ++

      ++(define requests
      +   (stream
      +     '(get 3)
      +     '(put 1 "a")    ; use follows definition
      +@@ -1720,118 +1838,128 @@ so that only a single pass is needed.  Consider a stream of requests:

      ++ '(put 4 "d"))) ; unused definition

      + +-

      We want a procedure ++

      We want a procedure + that will display cab, which is the result of (get 3), (get 1), + and (get 2), + in order. We first separate the request stream into gets +-and puts:

      ++and puts:

      + +-

      (define (get? obj) (eq? (car obj) 'get))

      ++

      ++(define (get? obj) (eq? (car obj) 'get))

      + +-

      (define-stream (gets strm)
      +-  (stream-map cadr (stream-filter get? strm)))

      ++

      ++(define-stream (gets strm)
      ++  (stream-map cadr (stream-filter get? strm)))

      + +-

      (define-stream (puts strm)
      +-  (stream-map cdr  (stream-remove get? strm)))

      ++

      ++(define-stream (puts strm)
      ++  (stream-map cdr  (stream-remove get? strm)))

      + +-

      Now, run-dict ++

      Now, run-dict + inserts each element of the puts stream into a lazy dictionary, represented + as a stream of key/value pairs (an association stream), then looks up +-each element of the gets stream with stream-assoc:

      ++each element of the gets stream with stream-assoc:

      + +-

      (define-stream (run-dict requests)
      ++

      ++(define-stream (run-dict requests)
      +   (let ((dict (build-dict (puts requests))))
      +     (stream-map (rsec stream-assoc dict)
      +-      (gets requests))))

      ++ (gets requests))))

      + +-

      (define (stream-assoc key dict)
      ++

      ++(define (stream-assoc key dict)
      +     (cond ((stream-null? dict) #f)
      +           ((equal? key (car (stream-car dict)))
      +             (stream-car dict))
      +           (else (stream-assoc key
      +-                  (stream-cdr dict)))))

      ++ (stream-cdr dict)))))

      + +-

      Dict is created in the let, but nothing is initially added to ++

      Dict is created in the let, but nothing is initially added to + it. Each time stream-assoc performs a lookup, enough of dict + is built to satisfy the lookup, but no more. We are assuming that + each item is defined once and only once. All that is left is to +-define the procedure that inserts new items into the dictionary, lazily:

      ++define the procedure that inserts new items into the dictionary, lazily:

      + +-

      (define-stream (build-dict puts)
      ++

      ++(define-stream (build-dict puts)
      +   (if (stream-null? puts)
      +       stream-null
      +       (stream-cons
      +         (stream-car puts)
      +-        (build-dict (stream-cdr puts)))))

      ++ (build-dict (stream-cdr puts)))))

      + +-

      Now we can +-run the requests and print the result:

      ++

      Now we can ++run the requests and print the result:

      + +-

      (stream-for-each display
      +-  (stream-map cadr (run-dict requests)))

      ++

      ++(stream-for-each display
      ++  (stream-map cadr (run-dict requests)))

      + +-

      The (put 4 "d") +-definition is never added to the dictionary because it is never needed.

      ++

      The (put 4 "d") ++definition is never added to the dictionary because it is never needed.

      + +-

      Pitfalls

      ++

      Pitfalls

      + +-

      Programming ++

      Programming + with streams, or any lazy evaluator, can be tricky, even for programmers + experienced in the genre. Programming with streams is even worse + in Scheme than in a purely functional language, because, though the + streams are lazy, the surrounding Scheme expressions in which they are + embedded are eager. The impedance between lazy and eager can occasionally + lead to astonishing results. Thirty-two years ago, William Burge +-warned:

      ++warned:

      + +-

        Some care ++

        Some care + must be taken when a stream is produced to make sure that its elements + are not really a list in disguise, in other words, to make sure that +-the stream elements are not materialized too soon.

      ++the stream elements are not materialized too soon.

      + +-

      For example, ++

      For example, + a simple version of stream-map that returns a stream built by applying + a unary procedure to the elements of an input stream could be defined +-like this:

      ++like this:

      + +-

      (define-stream (stream-map proc strm) ;wrong!
      ++

      ++(define-stream (stream-map proc strm) ;wrong!
      +   (let loop ((strm strm))
      +     (if (stream-null? strm)
      +         stream-null
      +         (stream-cons
      +           (proc (stream-car strm))
      +-          (loop (stream-cdr strm))))))

      ++ (loop (stream-cdr strm))))))

      + +-

      That looks ++

      That looks + right. It properly wraps the procedure in stream-lambda, and the two legs of the if + both return streams, so it type-checks. But it fails because the + named let + binds loop + to a procedure using normal lambda rather than stream-lambda, so even though the first element + of the result stream is lazy, subsequent elements are eager. Stream-map +-can be written using stream-let:

      ++can be written using stream-let:

      + +-

      (define-stream (stream-map proc strm)
      ++

      ++(define-stream (stream-map proc strm)
      +   (stream-let loop ((strm strm))
      +     (if (stream-null? strm)
      +         stream-null
      +         (stream-cons
      +           (proc (stream-car strm))
      +-          (loop (stream-cdr strm))))))

      ++ (loop (stream-cdr strm))))))

      + +-

      Here, stream-let ++

      Here, stream-let + assures that each element of the result stream is properly delayed, + because each is subject to the stream-lambda that is implicit in stream-let, so the result is truly a stream, +-not a “list in disguise.” Another version of this procedure +-was given previously at the description of define-stream.

      ++not a “list in disguise.” Another version of this procedure ++was given previously at the description of define-stream.

      + +-

      Another common ++

      Another common + problem occurs when a stream-valued procedure requires the next stream +-element in its definition. Consider this definition of stream-unique:

      ++element in its definition. Consider this definition of stream-unique:

      + +-

      (define-stream (stream-unique eql? strm) ;wrong!
      ++

      ++(define-stream (stream-unique eql? strm) ;wrong!
      +   (stream-match strm
      +     (() strm)
      +     ((_) strm)
      +@@ -1841,49 +1969,51 @@ element in its definition.  Consider this definition of The (a b . _) 
      ++

      The (a b . _) + pattern requires the value of the next stream element after the one + being considered. Thus, to compute the nth element + of the stream, one must know the n+1st element, and + to compute the n+1st element, one must know the +-n+2nd element, and to compute…. The correct version, +-given above in the description of stream-drop-while, only needs the current stream element.

      ++n+2nd element, and to compute…. The correct version, ++given above in the description of
      stream-drop-while, only needs the current stream element.

      + +-

      A similar problem ++

      A similar problem + occurs when the stream expression uses the previous element to compute +-the current element:

      ++the current element:

      + +-

      (define (nat n)
      ++

      ++(define (nat n)
      +   (stream-ref
      +     (stream-let loop ((s (stream 0)))
      +       (stream-cons (stream-car s)
      +         (loop (stream (add1 (stream-car s))))))
      +-    n))

      ++ n))

      + +-

      This program ++

      This program + traverses the stream of natural numbers, building the stream as it goes. + The definition is correct; (nat + 15) evaluates to 15. + But it needlessly uses unbounded space because each stream element holds +-the value of the prior stream element in the binding to s.

      ++the value of the prior stream element in the binding to
      s.

      + +-

      When traversing ++

      When traversing + a stream, it is easy to write the expression in such a way that evaluation + requires unbounded space, even when that is not strictly necessary. + During the discussion of SRFI-40, Joe Marshall created this infamous +-procedure:

      ++procedure:

      + +-

      (define (times3 n)
      ++

      ++(define (times3 n)
      +   (stream-ref
      +     (stream-filter
      +       (lambda (x)
      +         (zero? (modulo x n)))
      +       (stream-from 0))
      +-    3))

      ++ 3))

      + +-

      (times3 5) evaluates to 15 and (times3 ++

      (times3 5) evaluates to 15 and (times3 + #e1e9) evaluates to three + billion, though it takes a while. In either case, times3 + should operate in bounded space, since each iteration mutates the promise +@@ -1895,18 +2025,19 @@ the stream, so it holds the head of the stream, which holds the second + element, and so on. In addition to testing the programmer, this + procedure tests the stream primitives (it caught several errors during + development) and also tests the underlying Scheme system (it found a +-bug in one implementation).

      ++bug in one implementation).

      + +-

      Laziness is ++

      Laziness is + no defense against an infinite loop; for instance, the expression below + never returns, because the odd? predicate never finds an odd stream +-element.

      ++element.

      + +-

      (stream-null?
      ++

      ++(stream-null?
      +   (stream-filter odd?
      +-    (stream-from 0 2)))

      ++ (stream-from 0 2)))

      + +-

      Ultimately, ++

      Ultimately, + streams are defined as promises, which are implemented as thunks (lambda + with no arguments). Since a stream is a procedure, comparisons + such as eq?, eqv? +@@ -1919,9 +2050,10 @@ s) is #t is #f. + To determine if two streams are equal, it is necessary to evaluate the + elements in their common prefixes, reporting #f if two elements ever differ and #t +-if both streams are exhausted at the same time.

      ++if both streams are exhausted at the same time.

      + +-

      (define (stream-equal? eql? xs ys)
      ++

      ++(define (stream-equal? eql? xs ys)
      +   (cond ((and (stream-null? xs)
      +               (stream-null? ys)) #t)
      +         ((or (stream-null? xs)
      +@@ -1930,109 +2062,117 @@ if both streams are exhausted at the same time.

      + (stream-car ys))) #f) + (else (stream-equal? eql? + (stream-cdr xs) +- (stream-cdr ys)))))

      ++ (stream-cdr ys)))))

      + +-

      It is generally ++

      It is generally + not a good idea to mix lazy streams with eager side-effects, because + the order in which stream elements are evaluated determines the order + in which the side-effects occur. For a simple example, consider +-this side-effecting version of strm123:

      ++this side-effecting version of strm123:

      + +-

      (define strm123-with-side-effects
      ++

      ++(define strm123-with-side-effects
      +   (stream-cons (begin (display "one") 1)
      +     (stream-cons (begin (display "two") 2)
      +       (stream-cons (begin (display "three") 3)
      +-        stream-null))))

      ++ stream-null))))

      + +-

      The stream ++

      The stream + has elements 1 2 3. + But depending on the order in which stream elements are accessed, "one", "two" +-and "three" could be printed in any order.

      ++and "three" could be printed in any order.

      + +-

      Since the performance ++

      Since the performance + of streams can be very poor, normal (eager) lists should be preferred + to streams unless there is some compelling reason to the contrary. +-For instance, computing pythagorean triples with streams

      ++For instance, computing pythagorean triples with streams

      + +-

      (stream-ref
      ++

      ++(stream-ref
      +   (stream-of (list a b c)
      +     (n in (stream-from 1))
      +     (a in (stream-range 1 n))
      +     (b in (stream-range a n))
      +     (c is (- n a b))
      +     (= (+ (* a a) (* b b)) (* c c)))
      +-  50)

      ++ 50)

      + +-

      is about two +-orders of magnitude slower than the equivalent expression using loops.

      ++

      is about two ++orders of magnitude slower than the equivalent expression using loops.

      + +-

      (do ((n 1 (+ n 1))) ((> n 228))
      ++

      ++(do ((n 1 (+ n 1))) ((> n 228))
      +   (do ((a 1 (+ a 1))) ((> a n))
      +     (do ((b a (+ b 1))) ((> b n))
      +       (let ((c (- n a b)))
      +         (if (= (+ (* a a) (* b b)) (* c c))
      +-            (display (list a b c)))))))

      ++ (display (list a b c)))))))

      + +-

      Implementation

      ++

      Implementation

      + +-

      Bird and Wadler +-describe streams as either null or a pair with a stream in the tail:

      ++

      Bird and Wadler ++describe streams as either null or a pair with a stream in the tail:

      + +-

      +-α list :: null | α * α list

      ++

      ++α list :: null | α * α list

      + +-

      That works ++

      That works + in a purely functional language such as Miranda + or Haskell because the entire language is lazy. In +-an eager language like ML or Scheme, of course, it’s just a normal, +-eager list.

      ++an eager language like ML or Scheme, of course, it’s just a normal, ++eager list.

      + +-

      Using ML, Wadler, +-Taha and MacQueen give the type of even streams as:

      ++

      Using ML, Wadler, ++Taha and MacQueen give the type of even streams as:

      + +-

      datatype 'a stream_
      ++

      ++datatype 'a stream_
      +   = Nil_
      +   | Cons_ of 'a * 'a stream
      + withtype 'a stream
      +-  = 'a stream_ susp;

      ++ = 'a stream_ susp;

      + +-

      Their susp +-type is similar to Scheme’s promise type. Since Scheme conflates ++

      Their susp ++type is similar to Scheme’s promise type. Since Scheme conflates + the notions of record and type (the only way to create a new type disjoint + from all other types is to create a record), it is necessary to distribute +-the suspension through the two constructors of the stream data type:

      ++the suspension through the two constructors of the stream data type:

      + +-

      α stream
      ++

      ++α stream
      +   :: (promise stream-null)
      +-  |  (promise (α stream-pair))

      ++ | (promise (α stream-pair))

      + +-

      α stream-pair
      +-  :: α × (α stream)

      ++

      ++α stream-pair
      ++  :: α × (α stream)

      + +-

      That type captures ++

      That type captures + the systematic suspension of recursive promises that is the essence +-of “streamness.” But it doesn’t quite work, because Scheme ++of “streamness.” But it doesn’t quite work, because Scheme + is eager rather than lazy, and both the car and the cdr of the stream + are evaluated too early. So the final type of streams delays both +-the car and the cdr of the stream-pair:

      ++the car and the cdr of the stream-pair:

      + +-

      α stream
      ++

      ++α stream
      +   :: (promise stream-null)
      +-  |  (promise (α stream-pair))

      ++ | (promise (α stream-pair))

      + +-

      α stream-pair
      +-  :: (promise α) × (promise (α stream))

      ++

      ++α stream-pair
      ++  :: (promise α) × (promise (α stream))

      + +-

      The two outer ++

      The two outer + promises, in the stream type, provide streams without memoization. + The two inner promises, in the stream-pair type, add the memoization that is +-characteristic of streams in modern functional languages.

      ++characteristic of streams in modern functional languages.

      + +-

      Lists provide ++

      Lists provide + seven primitive operations: the two constructors '() and cons, the type predicates list?, null? and pair?, and the accessors car and cdr for pairs. All other list operations +-can be derived from those primitives.

      ++can be derived from those primitives.

      + +-

      It would seem ++

      It would seem + that the same set of primitives could apply to streams, but in fact + one additional primitive is required. André van Tonder describes + the reason in his discussion of the promise data type. The promises +@@ -2042,44 +2182,44 @@ closure that defines the new promise (so the old promise can be forced + later, if requested). However, in the case of iteration, the old + promise becomes unreachable, so instead of creating a new promise that + binds the old promise within, it is better to mutate the promise; that +-way, no space is wasted by the old promise.

      ++way, no space is wasted by the old promise.

      + +-

      Van Tonder ++

      Van Tonder + describes this new promise type, and provides a recipe for its use: + all constructors are wrapped with delay, all accessors are wrapped with force, + and all function bodies are wrapped with lazy. Given the seven primitives +-above, the first two parts of van Tonder’s recipe are simple: the ++above, the first two parts of van Tonder’s recipe are simple: the + two constructors stream-null and stream-pair hide delay, and the two accessors stream-car + and stream-cdr + hide force + (stream-null? + and stream-pair? also hide force, so they can distinguish the two constructors +-of the stream type).

      ++of the stream type).

      + +-

      Although the ++

      Although the + new promise type prevents a space leak, it creates a new problem: there +-is no place to hide the lazy that is the third part of van Tonder’s ++is no place to hide the lazy that is the third part of van Tonder’s + recipe. SRFI-40 solved this problem by exposing it (actually, + it exposed delay, which was incorrect). But that + violates good software engineering by preventing the stream + data type from being fully abstract. The solution of SRFI-41 is +-to create a new primitive, stream-lambda, that returns a function that hides lazy.

      ++to create a new primitive, stream-lambda, that returns a function that hides lazy.

      + +-

      Besides hiding lazy ++

      Besides hiding lazy + and making the types work out correctly, stream-lambda is obvious and easy-to-use for competent + Scheme programmers, especially when augmented with the syntactic sugar + of define-stream and named stream-let. The alternative of exposing stream-lazy +-would be less clear and harder to use.

      ++would be less clear and harder to use.

      + +-

      One of the ++

      One of the + hardest tasks when writing any program library is to decide what to + include and, more importantly, what to exclude. One important + guideline is minimalism, since once an operator enters a library it + must remain forever: Il semble que la perfection soit atteinte non +-quand il n’y a plus rien à ajouter, mais quand il n’y a plus rien +-à retrancher.

      ++quand il n’y a plus rien à ajouter, mais quand il n’y a plus rien ++à retrancher.

      + +-

      Since streams ++

      Since streams + are substantially slower than lists (the stream primitives require numerous + type conversions, and list operations in most Scheme implementations + are heavily optimized), most programmers will use streams only when +@@ -2088,36 +2228,43 @@ or when there is some clear advantage of laziness (such as reducing + the number of passes though a large data set). Thus, the library + is biased toward functions that work with infinite streams left-to-right. + In particular, there is no right-fold; if you need to materialize an entire stream, +-it’s best to use a list.

      ++it’s best to use a list.

      + +-

      Implementation of (streams primitive)

      ++

      Implementation of (streams primitive)

      + +-

      (library (streams primitive)

      ++

      (library (streams primitive)

      + +-

        (export stream-null stream-cons stream? stream-null? stream-pair?
      +-          stream-car stream-cdr stream-lambda)

      ++

      ++  (export stream-null stream-cons stream? stream-null? stream-pair?
      ++          stream-car stream-cdr stream-lambda)

      + +-

        (import (rnrs) (rnrs mutable-pairs))

      ++

      ++  (import (rnrs) (rnrs mutable-pairs))

      + +-

        (define-record-type (stream-type make-stream stream?)
      +-    (fields (mutable box stream-promise stream-promise!)))

      ++

      ++  (define-record-type (stream-type make-stream stream?)
      ++    (fields (mutable box stream-promise stream-promise!)))

      + +-

        (define-syntax stream-lazy
      ++

      ++  (define-syntax stream-lazy
      +     (syntax-rules ()
      +       ((stream-lazy expr)
      +         (make-stream
      +-          (cons 'lazy (lambda () expr))))))

      ++ (cons 'lazy (lambda () expr))))))

      + +-

        (define (stream-eager expr)
      ++

      ++  (define (stream-eager expr)
      +     (make-stream
      +-      (cons 'eager expr)))

      ++ (cons 'eager expr)))

      + +-

        (define-syntax stream-delay
      ++

      ++  (define-syntax stream-delay
      +     (syntax-rules ()
      +       ((stream-delay expr)
      +-        (stream-lazy (stream-eager expr)))))

      ++ (stream-lazy (stream-eager expr)))))

      + +-

        (define (stream-force promise)
      ++

      ++  (define (stream-force promise)
      +     (let ((content (stream-promise promise)))
      +       (case (car content)
      +         ((eager) (cdr content))
      +@@ -2127,61 +2274,73 @@ it’s best to use a list.

      + (begin (set-car! content (car (stream-promise promise*))) + (set-cdr! content (cdr (stream-promise promise*))) + (stream-promise! promise* content))) +- (stream-force promise))))))

      ++ (stream-force promise))))))

      + +-

        (define stream-null (stream-delay (cons 'stream 'null)))

      ++

      ++  (define stream-null (stream-delay (cons 'stream 'null)))

      + +-

        (define-record-type (stream-pare-type make-stream-pare stream-pare?)
      +-    (fields (immutable kar stream-kar) (immutable kdr stream-kdr)))

      ++

      ++  (define-record-type (stream-pare-type make-stream-pare stream-pare?)
      ++    (fields (immutable kar stream-kar) (immutable kdr stream-kdr)))

      + +-

        (define (stream-pair? obj)
      +-    (and (stream? obj) (stream-pare? (stream-force obj))))

      ++

      ++  (define (stream-pair? obj)
      ++    (and (stream? obj) (stream-pare? (stream-force obj))))

      + +-

        (define (stream-null? obj)
      ++

      ++  (define (stream-null? obj)
      +     (and (stream? obj)
      +          (eqv? (stream-force obj)
      +-               (stream-force stream-null))))

      ++ (stream-force stream-null))))

      + +-

        (define-syntax stream-cons
      ++

      ++  (define-syntax stream-cons
      +     (syntax-rules ()
      +       ((stream-cons obj strm)
      +-        (stream-eager (make-stream-pare (stream-delay obj) (stream-lazy strm))))))

      ++ (stream-eager (make-stream-pare (stream-delay obj) (stream-lazy strm))))))

      + +-

        (define (stream-car strm)
      ++

      ++  (define (stream-car strm)
      +     (cond ((not (stream? strm)) (error 'stream-car "non-stream"))
      +           ((stream-null? strm) (error 'stream-car "null stream"))
      +-          (else (stream-force (stream-kar (stream-force strm))))))

      ++ (else (stream-force (stream-kar (stream-force strm))))))

      + +-

        (define (stream-cdr strm)
      ++

      ++  (define (stream-cdr strm)
      +     (cond ((not (stream? strm)) (error 'stream-cdr "non-stream"))
      +           ((stream-null? strm) (error 'stream-cdr "null stream"))
      +-          (else (stream-kdr (stream-force strm)))))

      ++ (else (stream-kdr (stream-force strm)))))

      + +-

        (define-syntax stream-lambda
      ++

      ++  (define-syntax stream-lambda
      +     (syntax-rules ()
      +       ((stream-lambda formals body0 body1 ...)
      +-        (lambda formals (stream-lazy (let () body0 body1 ...)))))))

      ++ (lambda formals (stream-lazy (let () body0 body1 ...)))))))

      + +-

      Implementation of (streams derived)

      ++

      Implementation of (streams derived)

      + +-

      (library (streams derived)

      ++

      (library (streams derived)

      + +-

        (export stream-null stream-cons stream? stream-null? stream-pair? stream-car
      ++

      ++  (export stream-null stream-cons stream? stream-null? stream-pair? stream-car
      +           stream-cdr stream-lambda define-stream list->stream port->stream stream
      +           stream->list stream-append stream-concat stream-constant stream-drop
      +           stream-drop-while stream-filter stream-fold stream-for-each stream-from
      +           stream-iterate stream-length stream-let stream-map stream-match _
      +           stream-of stream-range stream-ref stream-reverse stream-scan stream-take
      +-          stream-take-while stream-unfold stream-unfolds stream-zip)

      ++ stream-take-while stream-unfold stream-unfolds stream-zip)

      + +-

        (import (rnrs) (streams primitive))

      ++

      ++  (import (rnrs) (streams primitive))

      + +-

        (define-syntax define-stream
      ++

      ++  (define-syntax define-stream
      +     (syntax-rules ()
      +       ((define-stream (name . formal) body0 body1 ...)
      +-        (define name (stream-lambda formal body0 body1 ...)))))

      ++ (define name (stream-lambda formal body0 body1 ...)))))

      + +-

        (define (list->stream objs)
      ++

      ++  (define (list->stream objs)
      +     (define list->stream
      +       (stream-lambda (objs)
      +         (if (null? objs)
      +@@ -2189,9 +2348,10 @@ it’s best to use a list.

      + (stream-cons (car objs) (list->stream (cdr objs)))))) + (if (not (list? objs)) + (error 'list->stream "non-list argument") +- (list->stream objs)))

      ++ (list->stream objs)))

      + +-

        (define (port->stream . port)
      ++

      ++  (define (port->stream . port)
      +     (define port->stream
      +       (stream-lambda (p)
      +         (let ((c (read-char p)))
      +@@ -2201,14 +2361,16 @@ it’s best to use a list.

      + (let ((p (if (null? port) (current-input-port) (car port)))) + (if (not (input-port? p)) + (error 'port->stream "non-input-port argument") +- (port->stream p))))

      ++ (port->stream p))))

      + +-

        (define-syntax stream
      ++

      ++  (define-syntax stream
      +     (syntax-rules ()
      +       ((stream) stream-null)
      +-      ((stream x y ...) (stream-cons x (stream y ...)))))

      ++ ((stream x y ...) (stream-cons x (stream y ...)))))

      + +-

        (define (stream->list . args)
      ++

      ++  (define (stream->list . args)
      +     (let ((n (if (= 1 (length args)) #f (car args)))
      +           (strm (if (= 1 (length args)) (car args) (cadr args))))
      +       (cond ((not (stream? strm)) (error 'stream->list "non-stream argument"))
      +@@ -2217,9 +2379,10 @@ it’s best to use a list.

      + (else (let loop ((n (if n n -1)) (strm strm)) + (if (or (zero? n) (stream-null? strm)) + '() +- (cons (stream-car strm) (loop (- n 1) (stream-cdr strm)))))))))

      ++ (cons (stream-car strm) (loop (- n 1) (stream-cdr strm)))))))))

      + +-

        (define (stream-append . strms)
      ++

      ++  (define (stream-append . strms)
      +     (define stream-append
      +       (stream-lambda (strms)
      +         (cond ((null? (cdr strms)) (car strms))
      +@@ -2229,9 +2392,10 @@ it’s best to use a list.

      + (cond ((null? strms) stream-null) + ((exists (lambda (x) (not (stream? x))) strms) + (error 'stream-append "non-stream argument")) +- (else (stream-append strms))))

      +- +-

        (define (stream-concat strms)
      ++          (else (stream-append strms))))

      ++ ++

      ++  (define (stream-concat strms)
      +     (define stream-concat
      +       (stream-lambda (strms)
      +         (cond ((stream-null? strms) stream-null)
      +@@ -2245,16 +2409,18 @@ it’s best to use a list.

      + (stream-cons (stream-cdr (stream-car strms)) (stream-cdr strms)))))))) + (if (not (stream? strms)) + (error 'stream-concat "non-stream argument") +- (stream-concat strms)))

      ++ (stream-concat strms)))

      + +-

        (define stream-constant
      ++

      ++  (define stream-constant
      +     (stream-lambda objs
      +       (cond ((null? objs) stream-null)
      +             ((null? (cdr objs)) (stream-cons (car objs) (stream-constant (car objs))))
      +             (else (stream-cons (car objs)
      +-                               (apply stream-constant (append (cdr objs) (list (car objs)))))))))

      ++ (apply stream-constant (append (cdr objs) (list (car objs)))))))))

      + +-

        (define (stream-drop n strm)
      ++

      ++  (define (stream-drop n strm)
      +     (define stream-drop
      +       (stream-lambda (n strm)
      +         (if (or (zero? n) (stream-null? strm))
      +@@ -2263,9 +2429,10 @@ it’s best to use a list.

      + (cond ((not (integer? n)) (error 'stream-drop "non-integer argument")) + ((negative? n) (error 'stream-drop "negative argument")) + ((not (stream? strm)) (error 'stream-drop "non-stream argument")) +- (else (stream-drop n strm))))

      ++ (else (stream-drop n strm))))

      + +-

        (define (stream-drop-while pred? strm)
      ++

      ++  (define (stream-drop-while pred? strm)
      +     (define stream-drop-while
      +       (stream-lambda (strm)
      +         (if (and (stream-pair? strm) (pred? (stream-car strm)))
      +@@ -2273,9 +2440,10 @@ it’s best to use a list.

      + strm))) + (cond ((not (procedure? pred?)) (error 'stream-drop-while "non-procedural argument")) + ((not (stream? strm)) (error 'stream-drop-while "non-stream argument")) +- (else (stream-drop-while strm))))

      ++ (else (stream-drop-while strm))))

      + +-

        (define (stream-filter pred? strm)
      ++

      ++  (define (stream-filter pred? strm)
      +     (define stream-filter
      +       (stream-lambda (strm)
      +         (cond ((stream-null? strm) stream-null)
      +@@ -2284,17 +2452,19 @@ it’s best to use a list.

      + (else (stream-filter (stream-cdr strm)))))) + (cond ((not (procedure? pred?)) (error 'stream-filter "non-procedural argument")) + ((not (stream? strm)) (error 'stream-filter "non-stream argument")) +- (else (stream-filter strm))))

      ++ (else (stream-filter strm))))

      + +-

        (define (stream-fold proc base strm)
      ++

      ++  (define (stream-fold proc base strm)
      +     (cond ((not (procedure? proc)) (error 'stream-fold "non-procedural argument"))
      +           ((not (stream? strm)) (error 'stream-fold "non-stream argument"))
      +           (else (let loop ((base base) (strm strm))
      +                   (if (stream-null? strm)
      +                       base
      +-                      (loop (proc base (stream-car strm)) (stream-cdr strm)))))))

      ++ (loop (proc base (stream-car strm)) (stream-cdr strm)))))))

      + +-

        (define (stream-for-each proc . strms)
      ++

      ++  (define (stream-for-each proc . strms)
      +     (define (stream-for-each strms)
      +       (if (not (exists stream-null? strms))
      +           (begin (apply proc (map stream-car strms))
      +@@ -2303,39 +2473,44 @@ it’s best to use a list.

      + ((null? strms) (error 'stream-for-each "no stream arguments")) + ((exists (lambda (x) (not (stream? x))) strms) + (error 'stream-for-each "non-stream argument")) +- (else (stream-for-each strms))))

      ++ (else (stream-for-each strms))))

      + +-

        (define (stream-from first . step)
      ++

      ++  (define (stream-from first . step)
      +     (define stream-from
      +       (stream-lambda (first delta)
      +         (stream-cons first (stream-from (+ first delta) delta))))
      +     (let ((delta (if (null? step) 1 (car step))))
      +       (cond ((not (number? first)) (error 'stream-from "non-numeric starting number"))
      +             ((not (number? delta)) (error 'stream-from "non-numeric step size"))
      +-            (else (stream-from first delta)))))

      ++ (else (stream-from first delta)))))

      + +-

        (define (stream-iterate proc base)
      ++

      ++  (define (stream-iterate proc base)
      +     (define stream-iterate
      +       (stream-lambda (base)
      +         (stream-cons base (stream-iterate (proc base)))))
      +     (if (not (procedure? proc))
      +         (error 'stream-iterate "non-procedural argument")
      +-        (stream-iterate base)))

      ++ (stream-iterate base)))

      + +-

        (define (stream-length strm)
      ++

      ++  (define (stream-length strm)
      +     (if (not (stream? strm))
      +         (error 'stream-length "non-stream argument")
      +         (let loop ((len 0) (strm strm))
      +           (if (stream-null? strm)
      +               len
      +-              (loop (+ len 1) (stream-cdr strm))))))

      ++ (loop (+ len 1) (stream-cdr strm))))))

      + +-

        (define-syntax stream-let
      ++

      ++  (define-syntax stream-let
      +     (syntax-rules ()
      +       ((stream-let tag ((name val) ...) body1 body2 ...)
      +-       ((letrec ((tag (stream-lambda (name ...) body1 body2 ...))) tag) val ...))))

      ++ ((letrec ((tag (stream-lambda (name ...) body1 body2 ...))) tag) val ...))))

      + +-

        (define (stream-map proc . strms)
      ++

      ++  (define (stream-map proc . strms)
      +     (define stream-map
      +       (stream-lambda (strms)
      +         (if (exists stream-null? strms)
      +@@ -2346,25 +2521,28 @@ it’s best to use a list.

      + ((null? strms) (error 'stream-map "no stream arguments")) + ((exists (lambda (x) (not (stream? x))) strms) + (error 'stream-map "non-stream argument")) +- (else (stream-map strms))))

      +- +-

        (define-syntax stream-match
      ++          (else (stream-map strms))))

      ++ ++

      ++  (define-syntax stream-match
      +     (syntax-rules ()
      +       ((stream-match strm-expr clause ...)
      +         (let ((strm strm-expr))
      +           (cond
      +             ((not (stream? strm)) (error 'stream-match "non-stream argument"))
      +             ((stream-match-test strm clause) => car) ...
      +-            (else (error 'stream-match "pattern failure")))))))

      +- +-

        (define-syntax stream-match-test
      ++            (else (error 'stream-match "pattern failure")))))))

      ++ ++

      ++  (define-syntax stream-match-test
      +     (syntax-rules ()
      +       ((stream-match-test strm (pattern fender expr))
      +         (stream-match-pattern strm pattern () (and fender (list expr))))
      +       ((stream-match-test strm (pattern expr))
      +-        (stream-match-pattern strm pattern () (list expr)))))

      +- +-

        (define-syntax stream-match-pattern 
      ++        (stream-match-pattern strm pattern () (list expr)))))

      ++ ++

      ++  (define-syntax stream-match-pattern 
      +     (lambda (x)
      +       (define (wildcard? x)
      +         (and (identifier? x)
      +@@ -2385,14 +2563,16 @@ it’s best to use a list.

      + (wildcard? #'w?) + (syntax (let (binding ...) body))) + ((stream-match-pattern strm var (binding ...) body) +- (syntax (let ((var strm) binding ...) body))))))

      +- +-

        (define-syntax stream-of
      ++          (syntax (let ((var strm) binding ...) body))))))

      ++ ++

      ++  (define-syntax stream-of
      +     (syntax-rules ()
      +       ((_ expr rest ...)
      +-        (stream-of-aux expr stream-null rest ...))))

      ++ (stream-of-aux expr stream-null rest ...))))

      + +-

        (define-syntax stream-of-aux
      ++

      ++  (define-syntax stream-of-aux
      +     (syntax-rules (in is)
      +       ((stream-of-aux expr base)
      +         (stream-cons expr base))
      +@@ -2405,9 +2585,10 @@ it’s best to use a list.

      + ((stream-of-aux expr base (var is exp) rest ...) + (let ((var exp)) (stream-of-aux expr base rest ...))) + ((stream-of-aux expr base pred? rest ...) +- (if pred? (stream-of-aux expr base rest ...) base))))

      ++ (if pred? (stream-of-aux expr base rest ...) base))))

      + +-

        (define (stream-range first past . step)
      ++

      ++  (define (stream-range first past . step)
      +     (define stream-range
      +       (stream-lambda (first past delta lt?)
      +         (if (lt? first past)
      +@@ -2419,18 +2600,20 @@ it’s best to use a list.

      + (if (not (number? delta)) + (error 'stream-range "non-numeric step size") + (let ((lt? (if (< 0 delta) < >))) +- (stream-range first past delta lt?)))))))

      ++ (stream-range first past delta lt?)))))))

      + +-

        (define (stream-ref strm n)
      ++

      ++  (define (stream-ref strm n)
      +     (cond ((not (stream? strm)) (error 'stream-ref "non-stream argument"))
      +           ((not (integer? n)) (error 'stream-ref "non-integer argument"))
      +           ((negative? n) (error 'stream-ref "negative argument"))
      +           (else (let loop ((strm strm) (n n))
      +                   (cond ((stream-null? strm) (error 'stream-ref "beyond end of stream"))
      +                         ((zero? n) (stream-car strm))
      +-                        (else (loop (stream-cdr strm) (- n 1))))))))

      ++ (else (loop (stream-cdr strm) (- n 1))))))))

      + +-

        (define (stream-reverse strm)
      ++

      ++  (define (stream-reverse strm)
      +     (define stream-reverse
      +       (stream-lambda (strm rev)
      +         (if (stream-null? strm)
      +@@ -2438,9 +2621,10 @@ it’s best to use a list.

      + (stream-reverse (stream-cdr strm) (stream-cons (stream-car strm) rev))))) + (if (not (stream? strm)) + (error 'stream-reverse "non-stream argument") +- (stream-reverse strm stream-null)))

      ++ (stream-reverse strm stream-null)))

      + +-

        (define (stream-scan proc base strm)
      ++

      ++  (define (stream-scan proc base strm)
      +     (define stream-scan
      +       (stream-lambda (base strm)
      +         (if (stream-null? strm)
      +@@ -2448,9 +2632,10 @@ it’s best to use a list.

      + (stream-cons base (stream-scan (proc base (stream-car strm)) (stream-cdr strm)))))) + (cond ((not (procedure? proc)) (error 'stream-scan "non-procedural argument")) + ((not (stream? strm)) (error 'stream-scan "non-stream argument")) +- (else (stream-scan base strm))))

      ++ (else (stream-scan base strm))))

      + +-

        (define (stream-take n strm)
      ++

      ++  (define (stream-take n strm)
      +     (define stream-take
      +       (stream-lambda (n strm)
      +         (if (or (stream-null? strm) (zero? n))
      +@@ -2459,9 +2644,10 @@ it’s best to use a list.

      + (cond ((not (stream? strm)) (error 'stream-take "non-stream argument")) + ((not (integer? n)) (error 'stream-take "non-integer argument")) + ((negative? n) (error 'stream-take "negative argument")) +- (else (stream-take n strm))))

      ++ (else (stream-take n strm))))

      + +-

        (define (stream-take-while pred? strm)
      ++

      ++  (define (stream-take-while pred? strm)
      +     (define stream-take-while
      +       (stream-lambda (strm)
      +         (cond ((stream-null? strm) stream-null)
      +@@ -2470,9 +2656,10 @@ it’s best to use a list.

      + (else stream-null)))) + (cond ((not (stream? strm)) (error 'stream-take-while "non-stream argument")) + ((not (procedure? pred?)) (error 'stream-take-while "non-procedural argument")) +- (else (stream-take-while strm))))

      ++ (else (stream-take-while strm))))

      + +-

        (define (stream-unfold mapper pred? generator base)
      ++

      ++  (define (stream-unfold mapper pred? generator base)
      +     (define stream-unfold
      +       (stream-lambda (base)
      +         (if (pred? base)
      +@@ -2481,9 +2668,10 @@ it’s best to use a list.

      + (cond ((not (procedure? mapper)) (error 'stream-unfold "non-procedural mapper")) + ((not (procedure? pred?)) (error 'stream-unfold "non-procedural pred?")) + ((not (procedure? generator)) (error 'stream-unfold "non-procedural generator")) +- (else (stream-unfold base))))

      ++ (else (stream-unfold base))))

      + +-

        (define (stream-unfolds gen seed)
      ++

      ++  (define (stream-unfolds gen seed)
      +     (define (len-values gen seed)
      +       (call-with-values
      +         (lambda () (gen seed))
      +@@ -2512,9 +2700,10 @@ it’s best to use a list.

      + (loop (- i 1) (cons (result-stream->output-stream result-stream i) outputs))))) + (if (not (procedure? gen)) + (error 'stream-unfolds "non-procedural argument") +- (result-stream->output-streams (unfold-result-stream gen seed))))

      ++ (result-stream->output-streams (unfold-result-stream gen seed))))

      + +-

        (define (stream-zip . strms)
      ++

      ++  (define (stream-zip . strms)
      +     (define stream-zip
      +       (stream-lambda (strms)
      +         (if (exists stream-null? strms)
      +@@ -2523,190 +2712,193 @@ it’s best to use a list.

      + (cond ((null? strms) (error 'stream-zip "no stream arguments")) + ((exists (lambda (x) (not (stream? x))) strms) + (error 'stream-zip "non-stream argument")) +- (else (stream-zip strms)))))

      ++ (else (stream-zip strms)))))

      + +-

      Implementation of (streams)

      ++

      Implementation of (streams)

      + +-

      (library (streams)

      ++

      (library (streams)

      + +-

        (export stream-null stream-cons stream? stream-null? stream-pair? stream-car
      ++

      ++  (export stream-null stream-cons stream? stream-null? stream-pair? stream-car
      +           stream-cdr stream-lambda define-stream list->stream port->stream stream
      +           stream->list stream-append stream-concat stream-constant stream-drop
      +           stream-drop-while stream-filter stream-fold stream-for-each stream-from
      +           stream-iterate stream-length stream-let stream-map stream-match _
      +           stream-of stream-range stream-ref stream-reverse stream-scan stream-take
      +-          stream-take-while stream-unfold stream-unfolds stream-zip)

      ++ stream-take-while stream-unfold stream-unfolds stream-zip)

      + +-

        (import (streams primitive) (streams derived)))

      ++

      ++  (import (streams primitive) (streams derived)))

      + +-

      Acknowledgements

      ++

      Acknowledgements

      + +-

      Jos Koot sharpened ++

      Jos Koot sharpened + my thinking during many e-mail discussions, suggested several discussion + points in the text, and contributed the final version of stream-match. +-Michael Sperber and Abdulaziz Ghuloum gave advice on R6RS.

      ++Michael Sperber and Abdulaziz Ghuloum gave advice on R6RS.

      + +-

      References

      ++

      References

      + +-

      Harold Abelson ++

      Harold Abelson + and Gerald Jay Sussman with Julie Sussman. Structure and Interpretation + of Computer Programs. MIT Press, Cambridge, Massachusetts. + Second edition, 1996. mitpress.mit.edu/sicp. The classic text on computer +-science. Section 3.5 includes extensive discussion of odd streams.

      ++science. Section 3.5 includes extensive discussion of odd streams.

      + +-

      Anne L. Bewig. +-“Golden Ratio” (personal communication). Homework for the ++

      Anne L. Bewig. ++“Golden Ratio” (personal communication). Homework for the + high school course Calculus. Teaching my daughter how to + calculate the 200th element of a continued fraction was a +-moment of sheer joy in the development of the stream libraries.

      ++moment of sheer joy in the development of the stream libraries.

      + +-

      Philip L. Bewig. ++

      Philip L. Bewig. + Scheme Request for Implementation 40: +-A Library of Streams. August, 2004. srfi.schemers.org/srfi-40. Describes an implementation ++A Library of Streams. August, 2004. srfi.schemers.org/srfi-40. Describes an implementation + of the stream +-data type.

      ++data type.

      + +-

      Richard Bird ++

      Richard Bird + and Philip Wadler. Introduction to Functional Programming. + Prentice Hall, 1988. The classic text on functional programming. +-Even streams are discussed in the context of purely functional programming.

      ++Even streams are discussed in the context of purely functional programming.

      + +-

      William H. ++

      William H. + Burge. Recursive Programming Techniques. Addison-Wesley, + 1975. An early text on functional programming, and still one of + the best, though the terminology is dated. Discusses even streams +-in Section 3.10.

      ++in Section 3.10.

      + +-

      Jeremy Gibbons, +-David Lester and Richard Bird, “Functional Pearl: Enumerating the +-Rationals,” under consideration for publication in Journal of Functional +-Programming. http://web.comlab.ox.ac.uk/oucl/work/jeremy.gibbons/publications/rationals.pdf. Discusses a series of expressions +-that enumerate the rational numbers without duplicates.

      ++

      Jeremy Gibbons, ++David Lester and Richard Bird, “Functional Pearl: Enumerating the ++Rationals,” under consideration for publication in Journal of Functional ++Programming. http://web.comlab.ox.ac.uk/oucl/work/jeremy.gibbons/publications/rationals.pdf. Discusses a series of expressions ++that enumerate the rational numbers without duplicates.

      + +-

      Carl Hewitt. +-“Viewing control structures as patterns of passing messages,” in ++

      Carl Hewitt. ++“Viewing control structures as patterns of passing messages,” in + Journal of Artificial Intelligence, Volume 8, Number 3 (June, 1977), + pp 323-364. Also published as Artificial Intelligence Memo 410 +-by the Massachusetts Institute of Technology, ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-410.pdf. Describes the Actor message-passing +-system; one of the examples used is the same-fringe? problem.

      ++by the Massachusetts Institute of Technology, ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-410.pdf. Describes the Actor message-passing ++system; one of the examples used is the same-fringe? problem.

      + +-

      Peter J. Landin. +-“A correspondence between ALGOL 60 and Church’s lambda-notation: +-Part I,” Communications of the ACM, Volume 8, Number +-2, February 1965., pages 89–101. The seminal description of +-streams.

      ++

      Peter J. Landin. ++“A correspondence between ALGOL 60 and Church’s lambda-notation: ++Part I,” Communications of the ACM, Volume 8, Number ++2, February 1965., pages 89–101. The seminal description of ++streams.

      + +-

      Joe Marshall. +-“Stream problem redux”, from Usenet +-comp.lang.scheme, June 28, 2002. groups.google.com/group/comp.lang.scheme/msg/db4b4a1f33e3eea8. The original post on comp.lang.scheme +-that describes the times3 problem.

      ++

      Joe Marshall. ++“Stream problem redux”, from Usenet ++comp.lang.scheme, June 28, 2002. groups.google.com/group/comp.lang.scheme/msg/db4b4a1f33e3eea8. The original post on comp.lang.scheme ++that describes the times3 problem.

      + +-

      Chris Okasaki. ++

      Chris Okasaki. + Purely Functional Data Structures. Cambridge University Press, +-2003. Revised version of Okasaki’s thesis Purely Functional +-Data Structures, Carnegie-Mellon University, 1996, www.cs.cmu.edu/~rwh/theses/okasaki.pdf. Provides a strong defense of ++2003. Revised version of Okasaki’s thesis Purely Functional ++Data Structures, Carnegie-Mellon University, 1996, www.cs.cmu.edu/~rwh/theses/okasaki.pdf. Provides a strong defense of + laziness, and describes several data structures that exploit laziness, +-including streams and queues.

      ++including streams and queues.

      + +-

      Stephen K. +-Park and Keith W. Miller. “Random number generators: good ones +-are hard to find,” Communications of the ACM, Volume 31, Issue +-10 (October 1988), pages 1192–1201. Describes a minimal standard +-random number generator.

      ++

      Stephen K. ++Park and Keith W. Miller. “Random number generators: good ones ++are hard to find,” Communications of the ACM, Volume 31, Issue ++10 (October 1988), pages 1192–1201. Describes a minimal standard ++random number generator.

      + +-

      Simon Peyton-Jones, ++

      Simon Peyton-Jones, + et al, editors. Haskell 98: Haskell 98 Language and Libraries: + The Revised Report. December 2002. www.haskell.org/onlinereport. Haskell is the prototypical + purely functional language, and includes even streams, which it calls +-lists, as its fundamental structured data type.

      ++lists, as its fundamental structured data type.

      + +-

      Chris Reade. ++

      Chris Reade. + Elements of Functional Programming. Addison-Wesley, April +-1989. A textbook on functional programming.

      ++1989. A textbook on functional programming.

      + +-

      Antoine de +-Saint-Exupéry. Chapter III “L’Avion” of Terre des Hommes. +-1939. “Perfection is achieved, not when there is nothing more +-to add, but when there is nothing left to take away.”

      ++

      Antoine de ++Saint-Exupéry. Chapter III “L’Avion” of Terre des Hommes. ++1939. “Perfection is achieved, not when there is nothing more ++to add, but when there is nothing left to take away.”

      + +-

      Dorai Sitaram. +-Teach Yourself Scheme in Fixnum Days. www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html. A useful introduction to Scheme; +-includes generator and co-routine solutions to the same-fringe? problem.

      ++

      Dorai Sitaram. ++Teach Yourself Scheme in Fixnum Days. www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html. A useful introduction to Scheme; ++includes generator and co-routine solutions to the same-fringe? problem.

      + +-

      Michael Sperber, ++

      Michael Sperber, + R. Kent Dybvig, Matthew Flatt, and Anton von Straaten, editors. + + Revised6 Report on the Algorithmic Language +-Scheme. September 26, 2007. www.r6rs.org. The standard definition of +-the Scheme programming language.

      ++Scheme
      . September 26, 2007. www.r6rs.org. The standard definition of ++the Scheme programming language.

      + +-

      André van ++

      André van + Tonder. Scheme Request for Implementation 45: +-Primitives for Expressing Iterative Lazy Algorithms. srfi.schemers.org/srfi-45. ++Primitives for Expressing Iterative Lazy Algorithms. srfi.schemers.org/srfi-45. + April, 2004. Describes the problems inherent in the promise + data type of R5RS (also present in R6RS), and provides the alternate promise +-data type used in the stream primitives.

      ++data type used in the stream primitives.

      + +-

      Philip Wadler. +-“How to replace failure by a list of successes,” in Proceedings ++

      Philip Wadler. ++“How to replace failure by a list of successes,” in Proceedings + of the conference on functional programming languages and computer architecture, +-Nancy, France, 1985, pages 113–128. Describes the “list of +-successes” technique for implementing backtracking algorithms using +-streams.

      ++Nancy, France, 1985, pages 113–128. Describes the “list of ++successes” technique for implementing backtracking algorithms using ++streams.

      + +-

      Philip Wadler, +-Walid Taha, and David MacQueen, “How to add laziness to a strict language +-without even being odd.” 1998 ACM SIGPLAN Workshop on ML, pp. 24ff. homepages.inf.ed.ac.uk/wadler/papers/lazyinstrict/lazyinstrict.ps. Describes odd and even styles ++

      Philip Wadler, ++Walid Taha, and David MacQueen, “How to add laziness to a strict language ++without even being odd.” 1998 ACM SIGPLAN Workshop on ML, pp. 24ff. homepages.inf.ed.ac.uk/wadler/papers/lazyinstrict/lazyinstrict.ps. Describes odd and even styles + of lazy evaluation, and shows how to add lazy evaluation to the strict +-functional language SML.

      ++functional language SML.

      + +-

      All cited web +-pages visited during September 2007.

      ++

      All cited web ++pages visited during September 2007.

      + +-

      Copyright

      ++

      Copyright

      + +-

      +-Copyright (C) Philip L. Bewig (2007). All Rights Reserved.

      ++

      ++Copyright (C) Philip L. Bewig (2007). All Rights Reserved.

      + +

      +-Permission is hereby granted, free of charge, to any person obtaining a ++Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the +-Software is furnished to do so, subject to the following conditions:

      ++Software is furnished to do so, subject to the following conditions:

      + +

      +-The above copyright notice and this permission notice shall be included in +-all copies or substantial portions of the Software.

      ++The above copyright notice and this permission notice shall be included in ++all copies or substantial portions of the Software.

      + +

      +-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +-DEALINGS IN THE SOFTWARE.

      ++DEALINGS IN THE SOFTWARE.

      + +-

      Several files related to this document are ++

      Several files related to this document are + available from + srfi.schemers.org/srfi-41: + A version of this document suitable for printing is available at +-streams.pdf. ++streams.pdf. + The complete source corresponding to the three Appendices is available in files +-streams.ss, +-primitive.ss, and +-derived.ss. ++streams.ss, ++primitive.ss, and ++derived.ss. + Samples from the text are available at +-samples.ss, ++samples.ss, + and a test suite is available at +-r6rs-test.ss. ++r6rs-test.ss. + Source code and tests for R5RS are available at +-r5rs.ss, +-and r5rs-test.ss.

      ++r5rs.ss, ++and r5rs-test.ss.

      + +-
      +-
      Editor: Michael Sperber
      ++
      ++
      Editor: Michael Sperber
      + +- ++ ++ +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-42.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-42.html +index a3cb664..69f4f79 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-42.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-42.html +@@ -1,48 +1,52 @@ +- +- ++ ++ + ++ ++ + SRFI 42: Eager Comprehensions ++ ++ ++ + + + + +-

      Title

      +- +-SRFI 42: Eager Comprehensions +- +-

      Author

      +- +-Sebastian Egner +- +-

      Status

      +- +-

      This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +-To comments +-this SRFI, please mail to +- +-srfi-42@srfi.schemers.org. +-See +-instructions here to subscribe to the list. You can access +-the discussion via +- +-the archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +-

      +-
        +-
      • Received: 2003/02/20 +-
      • Draft: 2003/02/20-2003/04/20 +-
      • Revised: 2003/07/07 +-
      • Final: 2003/07/07 +-
      +- +-

      Abstract

      +- +-This SRFI defines a modular and portable mechanism for ++

      SRFI 42: Eager Comprehensions

      ++ ++

      by Sebastian Egner

      ++

      This copy of the SRFI 42 specification document ++is distributed as part of the Racket package ++srfi-doc.

      The canonical source of this document is ++https://srfi.schemers.org/srfi-42/srfi-42.html.

      ++ ++

      Status

      ++ ++

      This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-42@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

      ++
        ++
      • Received: 2003-02-20 ++
      • Draft: 2003-02-20--2003-04-20 ++
      • Revised: 2003-07-07 ++
      • Final: 2003-07-07 ++
      ++ ++

      Abstract

      ++

      ++This SRFI defines a modular and portable mechanism for + eager comprehensions extending the algorithmic language Scheme + [R5RS]. + An eager comprehension is a convenient notation +@@ -50,108 +54,108 @@ for one or more nested or parallel loops generating + a sequence of values, and accumulating this sequence into a result. + In its most simple form, a comprehension according to this SRFI + looks like this: +- +-

      (list-ec (: i 5) (* i i)) => (0 1 4 9 16).
      +- +-Here, i is a local variable that is sequentially +-bound to the values 0, 1, ..., 4, and the squares of these ++

      ++
      (list-ec (: i 5) (* i i)) => (0 1 4 9 16).
      ++

      ++Here, i is a local variable that is sequentially ++bound to the values 0, 1, ..., 4, and the squares of these + numbers are collected in a list. + The following example illustrates most conventions of this SRFI + with respect to nesting and syntax: +- +-

      (list-ec (: n 1 4) (: i n) (list n i)) => ((1 0) (2 0) (2 1) (3 0) (3 1) (3 2)).
      +- ++

      ++
      (list-ec (: n 1 4) (: i n) (list n i)) => ((1 0) (2 0) (2 1) (3 0) (3 1) (3 2)).
      ++

      + In the example, the variable n is first bound to 1 +-then to 2 and finally to 3, and for each binding of n +-the variable i is bound to the values ++then to 2 and finally to 3, and for each binding of n ++the variable i is bound to the values + 0, 1, ..., n-1 in turn. + The expression (list n i) constructs a two-element list for + each bindings, and the comprehension list-ec collects +-all these results in a list.

      +- ++all these results in a list. ++

      ++

      + The mechanism defined in this SRFI has the following properties: ++

      ++
        + +-
          +- +-
        • +-The set of comprehensions defined for this SRFI is inspired by ++
        • ++The set of comprehensions defined for this SRFI is inspired by + those procedures and macros of [R5RS, 6.] + leading to natural comprehensions such as + list-ec, + append-ec, + sum-ec, + min-ec, +-every?-ec, ++every?-ec, + do-ec, and others. +-Some other natural comprehensions (e.g. gcd-ec) have +-not been included into this SRFI due to their low significance ++Some other natural comprehensions (e.g. gcd-ec) have ++not been included into this SRFI due to their low significance + for most applications. +-On the other hand, a few comprehensions ++On the other hand, a few comprehensions + (fold-ec, + fold3-ec) +-not inspired by [R5RS] have been ++not inspired by [R5RS] have been + included due to their broad applicability. +-
        • ++ + +-
        • +-There are typed generators +-(:list, :string, ...) ++
        • ++There are typed generators ++(:list, :string, ...) + expecting certain types of objects for their arguments. + These generators usually produce code as efficient as + hand coded do-loops. +-
        • ++ + +-
        • +-There is also the special generator : +-(read 'run through') ++
        • ++There is also the special generator : ++(read 'run through') + dispatching on the value of its argument list at runtime. + In the examples above, one or two integers were used to define a range. + The convenience of omitting the type comes at a certain + performance penalty, both per iteration and during startup of the loop. +-
        • +- +-
        • +-Generators can be nested depth-first (as in the example above), +-run in parallel (with an optional index variable +-or more generally with :parallel), +-and can be stopped early before (:while) +-or after (:until) ++
        • ++ ++
        • ++Generators can be nested depth-first (as in the example above), ++run in parallel (with an optional index variable ++or more generally with :parallel), ++and can be stopped early before (:while) ++or after (:until) + producing the current value. +-
        • ++ + +-
        • +-The sequence of values can be filtered ++
        • ++The sequence of values can be filtered + (if, not, + and, or), + intermediate commands can be evaluated between + generators (begin), and +-intermediate variables can be introduced (:let). +-
        • +-
        • ++intermediate variables can be introduced (:let). ++
        • ++
        • + The mechanism is fully modular. +-This means that no existing macro or procedure needs ++This means that no existing macro or procedure needs + to be modified when adding + application-specific comprehensions, +-application-specific typed generators, +-or application-specific dispatching generators. +-
        • +- +-
        • +-Syntactically, this SRFI uses the +-[outer .. inner | expr] convention, +-meaning that the most right generator (inner) spins fastest ++application-specific typed generators, ++or application-specific dispatching generators. ++
        • ++ ++
        • ++Syntactically, this SRFI uses the ++[outer .. inner | expr] convention, ++meaning that the most right generator (inner) spins fastest + and is followed by the result expression over which the +-comprehension ranges (expr). ++comprehension ranges (expr). + Refer to the Section "Design Rationale". + Moreover, the syntax is strictly prefix and the naming +-convention my-comprehension-ec, ++convention my-comprehension-ec, + :my-generator is used systematically. +-
        • ++ + +-
        +- +-

        ++

      + ++

      + The remainder of this document is organized as follows. + In section Rationale a brief + introduction is given what the motivation is for this SRFI. +@@ -170,28 +174,29 @@ Finally, the section Reference + Implementation gives source code for a reference + implementation together with a collection of runnable + examples and a few examples on extensions. ++

      + +- +-

      Rationale

      +- ++

      Rationale

      ++

      + The purpose of this SRFI is to provide a compact notation +-for many common cases of loops, in particular those ++for many common cases of loops, in particular those + constructing values for further computation. + The origin of this SRFI is my frustration that + there is no simple for the list of integers +-from 0 to n-1. ++from 0 to n-1. + With this SRFI it is (list-ec (: i n) i). +-Refer to the collection of examples for the ++Refer to the collection of examples for the + reference implementation + what it can be used for, and what it should not be used for. +-To give a practically useful example, ++To give a practically useful example, + the following procedure computes the sorted + list of all prime numbers below a certain bound + (you may want to run it yourself to get an idea of + its efficiency): ++

      + +
      
      +-(define (eratosthenes n)          ; primes in {2..n-1} for n >= 1
      ++(define (eratosthenes n)          ; primes in {2..n-1} for n >= 1
      +   (let ((p? (make-string n #\1)))
      +     (do-ec (:range k 2 n)
      +            (if (char=? (string-ref p? k) #\1))
      +@@ -199,24 +204,25 @@ its efficiency):
      +            (string-set! p? i #\0) )
      +     (list-ec (:range k 2 n) (if (char=? (string-ref p? k) #\1)) k) ))
      + +- +-Apart from make simple things simple, ++

      ++Apart from make simple things simple, + there is no other paradigm involved for this SRFI. + In particular, it is not the ambition to implement the +-powerful lazy list comprehensions of other functional ++powerful lazy list comprehensions of other functional + programming languages in Scheme. + If you are looking for that you may want to refer to + [SRFI 40]. + (The usual definition of the stream of all primes does +-in fact also use Eratosthenes' sieve method. +-It is instructive to compare.)

      +- +-The main focus of the design of this SRFI is portability under ++in fact also use Eratosthenes' sieve method. ++It is instructive to compare.) ++

      ++

      ++The main focus of the design of this SRFI is portability under + [R5RS] and modularity for extension. + Portability is achieved by limiting the features included. + Modularity for generators is achieved by a special +-implementation technique using Continuation +-Passing Style for macros (which I learned from ++implementation technique using Continuation ++Passing Style for macros (which I learned from + Richard Kelsey's implementation of "Macros for writing loops", + [MWL]) and by limiting the + expressive power of generators. +@@ -224,193 +230,199 @@ Modularity for comprehensions requires no additional effort. + As modularity was a major design goal, I hope many people will + find it easy to define their own comprehensions and generators. + As a starting point for doing so, I have included several +-suggestions for extensions.

      +- ++suggestions for extensions. ++

      ++

      + For a detailed motivation of the design decisions, +-please refer to the Section "Design Rationale".

      ++please refer to the Section "Design Rationale". ++

      + +-

      Specification

      ++

      Specification

      + +-A comprehensions is a hygienic referentially transparent macro ++

      ++A comprehension is a hygienic, referentially transparent macro + in the sense of [R5RS, 4.3.]. +-The macros extend the <expression>-syntax ++The macros extend the <expression>-syntax + defined in [R5RS, 7.1.3.]. +-The main syntactic pattern used for defining a comprehension is ++The main syntactic pattern used for defining a comprehension is + <qualifier>, representing a generator or a filter. +-It is defined in Section "Qualifiers".

      +- ++It is defined in Section "Qualifiers".

      ++

      ++

      + The most important instances of <qualifier> are generators. + These are defined in Section "Generators". + Generators come in three flavors, +-as typed generators +-(:list, +-:range etc.), +-as the dispatching generator : ++as typed generators ++(:list, ++:range etc.), ++as the dispatching generator : + (pronounced as 'run through'), +-and as combined and modified generators +-(:parallel, +-:while, +-:until). +-Most generators in this SRFI also support an optional ++and as combined and modified generators ++(:parallel, ++:while, ++:until). ++Most generators in this SRFI also support an optional + index variable counting the +-values being generated.

      +- +-Finally, it is explained how to add a new ++values being generated. ++

      ++

      ++Finally, it is explained how to add a new + application-specific comprehension, +-how to add a new application-specific typed generator, ++how to add a new application-specific typed generator, + and how to add a new +-application-specific dispatching generator. ++application-specific dispatching generator. + As this concerns code unknown at the time this is being written, + the explanation should not be taken as +-a specification in the literal sense. ++a specification in the literal sense. + It rather suggests a convention to follow in order to + ensure new comprehensions and generators blend seamlessly with +-the ones defined in this SRFI.

      ++the ones defined in this SRFI. ++

      + + +-

      Comprehensions

      ++

      Comprehensions

      + +-
      +-
      ++
      ++
      + (do-ec <qualifier>* <command>) +-
      ++
      + +-
      +-Evaluates the <command> exactly once ++
      ++Evaluates the <command> exactly once + for each binding in the sequence defined by the qualifiers. + If there are no qualifiers <command> + is evaluated exactly once. + The expression is evaluated for its side-effects only. + The result of the comprehension is unspecified. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (list-ec <qualifier>* <expression>) +-
      ++
      + +-
      ++
      + The list of values obtained by evaluating +-<expression> once for each binding in the sequence ++<expression> once for each binding in the sequence + defined by the qualifiers. + If there are no qualifiers the result is the list with +-the value of <expression>. +-
      +-
      ++the value of <expression>. ++ ++ + +-
      +-
      ++
      ++
      + (append-ec <qualifier>* <expression>) +-
      ++
      + +-
      ++
      + The list obtained by appending all values of <expression>, +-which must all be lists.
      ++which must all be lists.
      + Think of it as + (apply append (list-ec <qualifier>* <expression>)). +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (string-ec <qualifier>* <expression>) +-
      ++
      + +-
      +-The string of all values of <expression>.
      ++
      ++The string of all values of <expression>.
      + Think of it as +-(list->string (list-ec <qualifier>* <expression>)). +-
      +-
      ++(list->string (list-ec <qualifier>* <expression>)). ++ ++ + +-
      +-
      ++
      ++
      + (string-append-ec <qualifier>* <expression>) +-
      ++
      + +-
      ++
      + The string obtained by appending all values of <expression>, +-which must all be strings.
      ++which must all be strings.
      + Think of it as + (apply string-append (list-ec <qualifier>* <expression>)). +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (vector-ec <qualifier>* <expression>) +-
      ++
      + +-
      +-The vector of all values of <expression>.
      ++
      ++The vector of all values of <expression>.
      + Think of it as +-(list->vector (list-ec <qualifier>* <expression>)). +-
      +-
      ++(list->vector (list-ec <qualifier>* <expression>)). ++ ++ + +-
      +-
      ++
      ++
      + (vector-of-length-ec <k> <qualifier>* <expression>) +-
      ++
      + +-
      ++
      + The vector of all values of <expression>, + of which there must be exactly <k>. + This comprehension behaves like vector-ec + but can be implemented more efficiently. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (sum-ec <qualifier>* <expression>) +-
      ++
      + +-
      +-The sum of all values of <expression>.
      ++
      ++The sum of all values of <expression>.
      + Think of it as + (apply + (list-ec <qualifier>* <expression>)). +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (product-ec <qualifier>* <expression>) +-
      ++
      + +-
      +-The product of all values of <expression>.
      ++
      ++The product of all values of <expression>.
      + Think of it as + (apply * (list-ec <qualifier>* <expression>)). +-
      +-
      ++ ++ + +-
      +-
      +-(min-ec <qualifier>* <expression>)
      ++
      ++
      ++(min-ec <qualifier>* <expression>)
      + (max-ec <qualifier>* <expression>) +-
      ++
      + +-
      ++
      ++

      + The minimum and maximum of all values of <expression>. + The sequence of values must be non-empty. +-Think of these as
      +-(apply min (list-ec <qualifier>* <expression>))
      +-(apply max (list-ec <qualifier>* <expression>)).

      +- ++Think of these as
      ++(apply min (list-ec <qualifier>* <expression>))
      ++(apply max (list-ec <qualifier>* <expression>)). ++

      ++

      + If you want to return a default value in case the sequence is empty +-you may want to consider
      ++you may want to consider
      + (fold3-ec 'infinity <qualifier>* <expression> min min). +-

      +-
      +- +-
      +-
      ++

      ++ ++
      + (any?-ec <qualifier>* <test>) +-
      ++ + +-
      ++
      + Tests whether any value of <test> in the sequence + of bindings specified by the qualifiers is non-#f. + If this is the case, #t is returned, otherwise #f. +@@ -418,106 +430,113 @@ If there are no bindings in the sequence specified by the qualifiers + at all then the result is #f. + The enumeration of values stops after the first non-#f + encountered. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (every?-ec <qualifier>* <test>) +-
      ++
      + +-
      +-Tests whether all values of <test> are non-#f. ++
      ++Tests whether all values of <test> are non-#f. + If this is the case, #t is returned, otherwise #f. + If the sequence is empty the result is #t. + Enumeration stops after the first #f. +-
      +-
      ++ ++ + +-
      +-
      +-(first-ec <default> <qualifier>* <expression>)
      ++
      ++
      ++(first-ec <default> <qualifier>* <expression>)
      + (last-ec  <default> <qualifier>
      * <expression>) +-
      ++
      + +-
      +-The first or last value of <expression> ++
      ++The first or last value of <expression> + in the sequence of bindings specified by the qualifiers. + Before enumeration, the result is initialized + with the value of <default>; + so this will be the result if the sequence is empty. +-Enumeration is terminated in first-ec ++Enumeration is terminated in first-ec + when the first value has been computed. +-
      +-
      ++ ++ + +-
      +-
      +-(fold-ec  <x0> <qualifier>* <expression> <f2>)
      ++
      ++
      ++(fold-ec  <x0> <qualifier>* <expression> <f2>)
      + (fold3-ec <x0> <qualifier>
      * <expression> <f1> <f2>) +-
      ++
      + +-
      +-Reduces the sequence x[0], x[1], ..., x[n-1] ++
      ++

      ++Reduces the sequence x[0], x[1], ..., x[n-1] + of values obtained by evaluating <expression> once + for each binding as specified by <qualifier>*. +-The arguments <x0>, <f2>, ++The arguments <x0>, <f2>, + and <f1>, all syntactically equivalent to +-<expression>, specify the reduction process.

      +- ++<expression>, specify the reduction process. ++

      ++

      + The reduction process for fold-ec is defined as follows. +-A reduction variable x is initialized to the value ++A reduction variable x is initialized to the value + of <x0>, +-and for each k in {0, ..., n-1} the command +-(set! x (<f2> x[k] x)) +-is evaluated. +-Finally, x is returned as the value of the comprehension.

      +- ++and for each k in {0, ..., n-1} the command ++(set! x (<f2> x[k] x)) ++is evaluated. ++Finally, x is returned as the value of the comprehension. ++

      ++

      + The reduction process for fold3-ec is different. +-If and only if n = 0, i.e. the sequence is empty, then +-<x0> is evaluated and returned as the value ++If and only if n = 0, i.e. the sequence is empty, then ++<x0> is evaluated and returned as the value + of the comprehension. + Otherwise, a reduction variable x is initialized +-to the value of (<f1> x[0]), +-and for each k in {1, ..., n-1} the command +-(set! x (<f2> x[k] x)) +-is evaluated. +-Finally, x is returned as the value of the comprehension.

      +- ++to the value of (<f1> x[0]), ++and for each k in {1, ..., n-1} the command ++(set! x (<f2> x[k] x)) ++is evaluated. ++Finally, x is returned as the value of the comprehension. ++

      ++

      + As the order of the arguments suggests, + <x0> is evaluated outside the scope of the + qualifiers, whereas the reduction expressions involving +-<f1> and <f2> are ++<f1> and <f2> are + inside the scope of the qualifiers (so they may depend on + any variable introduced by the qualifiers). + Note that <f2> is evaluated repeatedly, +-with any side-effect or overhead this might have.

      +- +-The main purpose of these comprehensions is ++with any side-effect or overhead this might have. ++

      ++

      ++The main purpose of these comprehensions is + implementing other comprehensions as special cases. + They are generalizations of the procedures + fold and reduce in the sense of +-[SRFI 1]. +-(Concerning naming and argument order, please refer to ++[SRFI 1]. ++(Concerning naming and argument order, please refer to + the discussion archive of SRFI 1, in particular + the posting [Folds].) + Note that fold3-ec is defined such that +-<x0> is only evaluated in case the ++<x0> is only evaluated in case the + sequence is empty. +-This allows raising an error for the empty sequence, ++This allows raising an error for the empty sequence, + as in the example definition of min-ec below. +-

      +-
      ++

      ++ ++ + +-
      +-
      ++
      ++
      + <application-specific comprehension> +-
      ++
      + +-
      +-An important aspect of this SRFI is a modular mechanism ++
      ++

      ++An important aspect of this SRFI is a modular mechanism + to define application-specific comprehensions. +-To create a new comprehension a hygienic macro ++To create a new comprehension a hygienic macro + of this name is defined. + The macro transforms the new comprehension patterns + into instances of do-ec, which is the most +@@ -528,7 +547,7 @@ For example, the following code defines + min-ec + in terms of fold-ec + and fold3-ec: +- ++

      +
      
      + (define-syntax list-ec
      +   (syntax-rules ()
      +@@ -539,23 +558,22 @@ and fold3-ec:
      +   (syntax-rules ()
      +     ((min-ec etc1 etc ...)
      +      (fold3-ec (min) etc1 etc ... min min) )))
      +- ++

      + Note that the pattern etc1 etc ... matches + the syntax <qualifier>* <expression> +-without separate access to <qualifier>* ++without separate access to <qualifier>* + and <expression>. + In order to define a comprehension that does need explicit +-access to the <expression>-part, ++access to the <expression>-part, + the following method is used. +-First, all qualifiers are collected into a ++First, all qualifiers are collected into a + nested-qualifier, and then the + 'exactly one qualifier'-case is implemented. + For illustration, the following code defines +-fold3-ec in terms of ++fold3-ec in terms of + do-ec: +- +- +-

      
      ++

      ++
      + (define-syntax fold3-ec
      +   (syntax-rules (nested)
      +     ((fold3-ec x0 (nested q1 ...) q etc1 etc2 etc3 etc ...)
      +@@ -573,421 +591,441 @@ For illustration, the following code defines
      +                     (begin (set! result (f1 value))
      +                            (set! empty #f) )
      +                     (set! result (f2 value result)) )))
      +-       (if empty x0 result) ))))
      +- ++ (if empty x0 result) ))))
      ++

      + Finally, observe that the newly defined fold3-ec + comprehension inherits all types of qualifiers supported by + do-ec, including all application-specific generators; + no further definitions are necessary. +-

      +-
      ++

      ++ ++ + + +-

      Qualifiers

      ++

      Qualifiers

      + ++

      + This section defines the syntax <qualifier>. + The nesting of qualifiers is from left (outer) to right (inner). + In other words, the rightmost generator spins fastest. + The nesting also defines the scope of the variables introduced +-by the generators. ++by the generators. + This implies that inner generators may depend on the variables + of outer generators. +-The sequence of enumeration of values is strictly depth first. +-These conventions are illustrated by the +-first example.

      +- +-The syntax <qualifier> consists of the following alternatives:

      ++The sequence of enumeration of values is strictly depth first. ++These conventions are illustrated by the ++first example. ++

      ++

      ++The syntax <qualifier> consists of the following alternatives: ++

      + + +-
      +-
      ++
      ++
      + <generator> +-
      ++
      + +-
      ++
      + Enumerates a sequence of bindings of one or more variables. + The scope of the variables starts at the generator and extends + over all subsequent qualifiers and expressions in the comprehension. +-The <generator>-syntax is defined in ++The <generator>-syntax is defined in + Section "Generators". +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (if <test>) +-
      ++
      + +-
      ++
      + Filters the sequence of bindings by testing if + <test> evaluates to non-#f. + Only for those bindings for which this is the case, + the subsequent qualifiers of the comprehension are evaluated. +-
      +-
      ++ ++ + +-
      +-
      +-(not <test>)
      +-(and <test>
      *)
      ++
      ++
      ++(not <test>)
      ++(and <test>
      *)
      + (or  <test>
      *) +-
      ++
      + +-
      ++
      + Abbreviated notations for filters of the form + (if (not <test>)), + (if (and <test>*)), and + (if (or <test>*)). + These represent frequent cases of filters. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (begin <sequence>) +-
      ++
      + +-
      ++
      + Evaluate <sequence>, consisting of + <command>* <expression>, +-once for each binding of the variables defined by the ++once for each binding of the variables defined by the + previous qualifiers in the comprehension. + Using this qualifier, side effects can be inserted + into the body of a comprehension. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (nested <qualifier>*) +-
      ++
      + +-
      ++
      + A syntactic construct to group qualifiers. +-The meaning of a qualifier according to the +-nested-syntax is the same as ++The meaning of a qualifier according to the ++nested-syntax is the same as + inserting <qualifier>* + into the enclosing comprehension. + This construct can be used to reduce comprehensions with several + qualifiers into a form with exactly one qualifier. +-
      +-
      ++ ++ + + +-

      Generators

      +- ++

      Generators

      ++

      + This section defines the syntax <generator>. +-Each generator defines a sequence of bindings through ++Each generator defines a sequence of bindings through + which one or more variables are run. +-The scope of the variables begins after the closing ++The scope of the variables begins after the closing + parenthesis of the generator expression and extends +-to the end of the comprehension it is part of.

      +- +-The variables defined by the generators +-are specified using the syntax

      +- ++to the end of the comprehension it is part of. ++

      ++

      ++The variables defined by the generators ++are specified using the syntax ++

      +
      + <vars> --> <variable1> [ (index <variable2>) ],
      + ++

      + where <variable1> runs through the values in +-the sequence defined by the generator, and the optional +-<variable2> is an exact integer-valued ++the sequence defined by the generator, and the optional ++<variable2> is an exact integer-valued + index variable counting the values (starting from 0). + The names of the variables must be distinct. +-The following example illustrates the index variable:

      +- ++The following example illustrates the index variable: ++

      +
      
      +-(list-ec (: x (index i) "abc") (list x i)) => ((#\a 0) (#\b 1) (#\c 2))
      ++(list-ec (: x (index i) "abc") (list x i)) => ((#\a 0) (#\b 1) (#\c 2))
      + ++

      + Unless defined otherwise, all generators make sure that the + expressions provided for their syntactic arguments are + evaluated exactly once, before enumeration begins. + Moreover, it may be assumed that the generators do not + copy the code provided for their arguments, because that + could lead to exponential growth in code size. +-Finally, it is possible to assign a value to the variables +-defined by a generator, but the effect of this assignment +-is unspecified.

      +- +-The syntax <generator> consists of the following alternatives:

      ++Finally, it is possible to assign a value to the variables ++defined by a generator, but the effect of this assignment ++is unspecified. ++

      ++

      ++The syntax <generator> consists of the following alternatives: ++

      + +-
      +-
      ++
      ++
      + (: <vars> <arg1> <arg>*) +-
      ++
      + +-
      ++
      ++

      + First the expressions <arg1> <arg>* +-are evaluated into a[1] a[2] ... a[n] ++are evaluated into a[1] a[2] ... a[n] + and then a global dispatch procedure is used to dispatch on + the number and types of the arguments and run the resulting + generator. +- +- +-Initially (after loading the SRFI), +-the following cases are recognized:

      +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +-
      :list +-if +-for all i in {1..n}: +-(list? a[i]). +-
      :string +-if +-for all i in {1..n}: +-(string? a[i]). +-
      :vector +-if +-for all i in {1..n}: +-(vector? a[i]). +-
      :range +-if +-n in {1..3} and +-for all i in {1..n}: +-(integer? a[i]) and +-(exact? a[i]). +-
      :real-range +-if +-n in {1..3} and +-for all i in {1..n}: +-(real? a[i]). +-
      :char-range +-if +-n = 2 and +-for all i in {1, 2}: +-(char? a[i]). +-
      :port +-if +-n in {1,2} and +-(input-port? a[1]) and +-(procedure? a[2]). +-

      +- ++

      ++

      ++Initially (after loading the SRFI), ++the following cases are recognized: ++

      ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
      :list ++if ++for all i in {1..n}: ++(list? a[i]). ++
      :string ++if ++for all i in {1..n}: ++(string? a[i]). ++
      :vector ++if ++for all i in {1..n}: ++(vector? a[i]). ++
      :range ++if ++n in {1..3} and ++for all i in {1..n}: ++(integer? a[i]) and ++(exact? a[i]). ++
      :real-range ++if ++n in {1..3} and ++for all i in {1..n}: ++(real? a[i]). ++
      :char-range ++if ++n = 2 and ++for all i in {1, 2}: ++(char? a[i]). ++
      :port ++if ++n in {1,2} and ++(input-port? a[1]) and ++(procedure? a[2]). ++
      ++

      + +-The current dispatcher can be retrieved as +-(:-dispatch-ref), a new dispatcher d ++The current dispatcher can be retrieved as ++(:-dispatch-ref), a new dispatcher d + can be installed by +-(:-dispatch-set! d) ++(:-dispatch-set! d) + yielding an unspecified result, + and a copy of the initial dispatcher can be obtained as + (make-initial-:-dispatch). +-Please refer to the section below ++Please refer to the section below + for recommendation how to add cases to the dispatcher. +-

      +-
      ++

      ++ + +-
      +-
      +-(:list   <vars> <arg1> <arg>*)
      +-(:string <vars> <arg1> <arg>
      *)
      ++
      ++(:list   <vars> <arg1> <arg>*)
      ++(:string <vars> <arg1> <arg>
      *)
      + (:vector <vars> <arg1> <arg>
      *) +-
      ++ + +-
      ++
      + Run through one or more lists, strings, or vectors. +-First all expressions in <arg1> <arg>* ++First all expressions in <arg1> <arg>* + are evaluated and then all elements of the resulting values + are enumerated from left to right. + One can think of it as first appending all arguments and + then enumerating the combined object. +-As a clarifying example, consider
      +-(list-ec (:string c (index i) "a" "b") (cons c i)) => ++As a clarifying example, consider
      ++(list-ec (:string c (index i) "a" "b") (cons c i)) => + ((#\a . 0) (#\b . 1)). +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (:integers <vars>) +-
      ++
      + +-
      ++
      + Runs through the sequence 0, 1, 2, ... of non-negative integers. +-This is most useful in combination with +-:parallel, +-:while, and +-:until or with ++This is most useful in combination with ++:parallel, ++:while, and ++:until or with + a non-local exit in the body of the comprehension. +-
      +-
      ++ ++ + +-
      +-
      +-(:range <vars>         <stop>)
      +-(:range <vars> <start> <stop>)
      ++
      ++
      ++(:range <vars>         <stop>)
      ++(:range <vars> <start> <stop>)
      + (:range <vars> <start> <stop> <step>)
      +-
      +- +-
      +-Runs through a range of exact rational numbers.

      ++

      + ++
      ++

      ++Runs through a range of exact rational numbers. ++

      ++

      + The form (:range <vars> <stop>) + evaluates the expression <stop>, +-which must result in an exact integer n, +-and runs through the finite sequence 0, 1, 2, ..., n-1. +-If n is zero or negative the sequence is empty.

      ++which must result in an exact integer n, ++and runs through the finite sequence 0, 1, 2, ..., n-1. ++If n is zero or negative the sequence is empty.

      + + The form (:range <vars> <start> <stop>) +-evaluates the expressions <start> and ++evaluates the expressions <start> and + <stop>, +-which must result in exact integers a and b, +-and runs through the finite sequence +-a, a+1, a+2, ..., b-1. +-If b is less or equal a then the sequence is empty.

      +- ++which must result in exact integers a and b, ++and runs through the finite sequence ++a, a+1, a+2, ..., b-1. ++If b is less or equal a then the sequence is empty. ++

      ++

      + The form (:range <vars> <start> <stop> <step>) +-first evaluates the expressions <start>, ++first evaluates the expressions <start>, + <stop>, and <step>, +-which must result in exact integers a, b, and s +-such that s is unequal to zero. ++which must result in exact integers a, b, and s ++such that s is unequal to zero. + Then the sequence +-a, a + s, a + 2 s, ..., a + (n-1) s +-is enumerated where n = ceil((b-a)/s). +-In other words, the sequence starts at a, increments by s, +-and stops when the next value would reach or cross b. +-If n is zero or negative the sequence is empty. +-

      +-
      +- +-
      +-
      +-(:real-range <vars>         <stop>)
      +-(:real-range <vars> <start> <stop>)
      ++a, a + s, a + 2 s, ..., a + (n-1) s ++is enumerated where n = ceil((b-a)/s). ++In other words, the sequence starts at a, increments by s, ++and stops when the next value would reach or cross b. ++If n is zero or negative the sequence is empty. ++

      ++ ++
      ++ ++
      ++
      ++(:real-range <vars>         <stop>)
      ++(:real-range <vars> <start> <stop>)
      + (:real-range <vars> <start> <stop> <step>)
      +-
      ++ + +-
      ++
      ++

      + Runs through a range of real numbers using an explicit index variable. + This form of range enumeration avoids accumulation of rounding errors +-and is the one to use if any of the numbers defining the range is +-inexact, not an integer, or a bignum of large magnitude.

      +- ++and is the one to use if any of the numbers defining the range is ++inexact, not an integer, or a bignum of large magnitude. ++

      ++

      + Providing default value 0 for <start> and + 1 for <step>, the generator first + evaluates <start>, <stop>, + and <step>, which must result in reals +-a, b, and s such that +-n = (b-a)/s is also representable ++a, b, and s such that ++n = (b-a)/s is also representable + as a real. + Then the sequence 0, 1, 2, ... is enumerated while the +-current value i is less than n, and the ++current value i is less than n, and the + variable in <vars> is bound to the +-value a + i s. +-If any of the values a, b, or s is ++value a + i s. ++If any of the values a, b, or s is + non-exact then all values in the sequence are non-exact. +-

      +-
      ++

      ++ ++ ++ + +-
      +-
      ++
      ++
      + (:char-range <vars> <min> <max>) +-
      ++
      + +-
      ++
      + Runs through a range of characters. + First <min> and <max> are +-evaluated, which must result in two characters a and b. +-Then the sequence of characters +-a, a+1, a+2, ..., b ++evaluated, which must result in two characters a and b. ++Then the sequence of characters ++a, a+1, a+2, ..., b + is enumerated in the order defined by char<=? + in the sense of [R5RS, 6.3.4.]. +-If b is smaller than a then the sequence is empty. +-(Note that b is included in the sequence.) +-
      +-
      +- +-
      +-
      +-(:port <vars> <port>)
      ++If b is smaller than a then the sequence is empty. ++(Note that b is included in the sequence.) ++ ++
      ++ ++
      ++
      ++(:port <vars> <port>)
      + (:port <vars> <port> <read-proc>) +-
      ++ + +-
      ++
      + Reads from the port until the eof-object is read. +-Providing the default read for ++Providing the default read for + <read-proc>, the generator first +-evaluates <port> and ++evaluates <port> and + <read-proc>, which must result +-in an input port p and a procedure r. ++in an input port p and a procedure r. + Then the variable is run through the sequence obtained +-by (r p) ++by (r p) + while the result does not satisfy eof-object?. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (:dispatched <vars> <dispatch> <arg1> <arg>*) +-
      ++
      + +-
      ++
      ++

      + Runs the variables through a sequence defined by <dispatch> + and <arg1> <arg>*. + The purpose of :dispatched is implementing + dispatched generators, in particular the predefined dispatching +-generator :.

      +- ++generator :. ++

      ++

      + The working of :dispatched is as follows. + First <dispatch> and + <arg1> <arg>* are evaluated, +-resulting in a procedure d (the 'dispatcher') and +-the values a[1] a[2] ... a[n]. +-Then +-(d (list a[1] a[2] ... a[n] )) +-is evaluated, resulting in a value g. +-If g is not a procedure then the dispatcher ++resulting in a procedure d (the 'dispatcher') and ++the values a[1] a[2] ... a[n]. ++Then ++(d (list a[1] a[2] ... a[n] )) ++is evaluated, resulting in a value g. ++If g is not a procedure then the dispatcher + did not recognize the argument list and an error is raised. +-Otherwise the 'generator procedure' g is used ++Otherwise the 'generator procedure' g is used + to run <vars> through a sequence of values. +-The sequence defined by g is obtained by repeated +-evaluation of (g empty) +-until the result is empty. +-In other words, g indicates the end of the sequence by +-returning its only argument, for which the caller has provided +-an object distinct from anything g can produce. ++The sequence defined by g is obtained by repeated ++evaluation of (g empty) ++until the result is empty. ++In other words, g indicates the end of the sequence by ++returning its only argument, for which the caller has provided ++an object distinct from anything g can produce. + (Generator procedures are state based, they are no such noble things +-as streams in the sense of SRFI 40.)

      +- +- ++as streams in the sense of SRFI 40.) ++

      ++

      + The definition of dispatchers is greatly simplified by the + macro :generator-proc that constructs a generator + procedure from a typed generator. + Let (g var arg1 arg ...) be an instance of + the <generator> syntax, for example an +-application-specific typed generator, ++application-specific typed generator, + with a single variable var and no index variable. + Then +- ++

      +
      +-(:generator-proc (g arg1 arg ...)) => g,
      +- +-where the generator procedure g runs through the list +-(list-ec (g var arg1 arg ...) var).

      ++(:generator-proc (g arg1 arg ...)) => g, ++

      ++where the generator procedure g runs through the list ++(list-ec (g var arg1 arg ...) var). ++

      + +- +-Adding an application-specific dispatching generator. ++

      ++Adding an application-specific dispatching generator. + In order to define a new dispatching generator (say :my) + first a dispatching procedure (say :my-dispatch) is defined. + The dispatcher will be called with a single (!) argument +@@ -998,9 +1036,9 @@ when it is called with the empty list. + Otherwise (if there is at least one value to dispatch on), + the dispatcher must either return a generator procedure + or #f (= no interest). +-As an example, the following skeleton code defines a dispatcher +-similar to the initial dispatcher of :: +- ++As an example, the following skeleton code defines a dispatcher ++similar to the initial dispatcher of :: ++

      +
      + (define (:my-dispatch args)
      +   (case (length args)
      +@@ -1011,28 +1049,28 @@ similar to the initial dispatcher of ::
      +              (:generator-proc (:list a1)) )
      +             ((string? a1)
      +              (:generator-proc (:string a1)) )
      +-            ...more unary cases...
      ++            ...more unary cases...
      +             (else
      +              #f ))))
      +     ((2) (let ((a1 (car args)) (a2 (cadr args)))
      +            (cond
      +             ((and (list? a1) (list? a2))
      +              (:generator-proc (:list a1 a2)) )
      +-            ...more binary cases...
      ++            ...more binary cases...
      +             (else
      +              #f ))))
      +-    ...more arity cases...
      ++    ...more arity cases...
      +     (else
      +      (cond
      +       ((every?-ec (:list a args) (list? a))
      +        (:generator-proc (:list (apply append args))) )
      +-      ...more large variable arity cases...
      ++      ...more large variable arity cases...
      +       (else
      +        #f )))))
      +- +-Once the dispatcher has been defined, the following macro ++

      ++Once the dispatcher has been defined, the following macro + implements the new dispatching generator: +- ++

      +
      + (define-syntax :my
      +   (syntax-rules (index)
      +@@ -1040,83 +1078,85 @@ implements the new dispatching generator:
      +      (:dispatched cc var (index i) :my-dispatch arg1 arg ...) )
      +     ((:my cc var arg1 arg ...)
      +      (:dispatched cc var :my-dispatch arg1 arg ...) )))
      +- ++

      + This method of extension yields complete control of the dispatching process. + Other modules can only add cases to :my +-if they have access to :my-dispatch.

      +- +- +-Extending the predefined dispatched generator. ++if they have access to :my-dispatch. ++

      ++

      ++Extending the predefined dispatched generator. + An alternative to adding a new dispatched generators is extending +-the predefined generator :. +-Technically, extending : means ++the predefined generator :. ++Technically, extending : means + installing a new global dispatching procedure using +-:-dispatch-set! ++:-dispatch-set! + as described above. +- +- ++

      ++

      + In most cases, however, the already installed dispatcher should +-be extended by new cases. ++be extended by new cases. + The following procedure is a utility for doing so: +- +-

      (dispatch-union d1 d2) => d,
      +- +-where the new dispatcher d recognizes the union of the +-cases recognized by the dispatchers d1 and d2. ++

      ++
      (dispatch-union d1 d2) => d,
      ++

      ++where the new dispatcher d recognizes the union of the ++cases recognized by the dispatchers d1 and d2. + The new dispatcher always tries both component dispatchers + and raises an error in case of conflict. +-The identification returned by (d) ++The identification returned by (d) + is the concatenation of the component identifications +-(d1) and +-(d2), enclosed in lists ++(d1) and ++(d2), enclosed in lists + if necessary. + For illustration, consider the following code: +- ++

      +
      + (define (example-dispatch args)
      +   (cond
      +    ((null? args)
      +     'example )
      +    ((and (= (length args) 1) (symbol? (car args)) )
      +-    (:generator-proc (:string (symbol->string (car args)))) )
      ++    (:generator-proc (:string (symbol->string (car args)))) )
      +    (else
      +     #f )))
      + 
      + (:-dispatch-set! (dispatch-union (:-dispatch-ref) example-dispatch))
      +- ++

      + After evaluation of this code, the following example will work: +- +-

      (list-ec (: c 'abc) c) => (#\a #\b #\c)
      +- +-Adding cases to : is particularly useful ++

      ++
      (list-ec (: c 'abc) c) => (#\a #\b #\c)
      ++

      ++Adding cases to : is particularly useful + for frequent cases of interactive input. + Be warned, however, that the advantage of global extension also carries + the danger of conflicts, unexpected side-effects, and slow dispatching. +-

      +-
      ++

      ++ ++ ++ + +-
      +-
      +-(:do (<lb>*) <ne1?> (<ls>*))
      ++
      ++
      ++(:do (<lb>*) <ne1?> (<ls>*))
      + (:do (let (<ob>
      *) <oc>*) (<lb>*) <ne1?> (let (<ib>*) <ic>*) <ne2?> (<ls>*)) +-
      ++
      + +-
      ++
      + Defines a generator in terms of a named-let, + optionally decorated with inner and outer lets. + This generator is for defining other generators. + (In fact, the reference implementation transforms any other + generator into an instance of fully decorated :do.) +-The generator is a compromise between expressive power ++The generator is a compromise between expressive power + (more flexible loops) and fixed structure (necessary + for merging and modifying generators). +-In the fully decorated form, the syntactic variables ++In the fully decorated form, the syntactic variables + <ob> (outer binding), + <oc> (outer command), + <lb> (loop binding), + <ne1?> (not-end1?), + <ib> (inner binding), +-<ic> (inner command), ++<ic> (inner command), + <ne2?> (not-end2?), and + <ls> (loop step) + define the following loop skeleton: +@@ -1124,11 +1164,11 @@ define the following loop skeleton: +
      + (let (<ob>*)
      +   <oc>*
      +-  (let loop (<lb>*) 
      ++  (let loop (<lb>*)
      +     (if <ne1?>
      +         (let (<ib>*)
      +           <ic>*
      +-          payload
      ++          payload
      +           (if <ne2?>
      +               (loop <ls>*) ))))),
      + +@@ -1139,120 +1179,129 @@ i.e. they do not begin with a <definition>. + The latter requirement allows the code generator to + produce more efficient code for special cases by + removing empty let-expressions altogether. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (:let <vars> <expression>) +-
      ++
      + +-
      +-Runs through the sequence consisting of the value of ++
      ++Runs through the sequence consisting of the value of + <expression>, only. + This is the same as + (:list <vars> (list <expression>)). + If an index variable is specified, its value is 0. +-The :let-generator can be used to introduce ++The :let-generator can be used to introduce + an intermediate variable depending on outer generators. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (:parallel <generator>*) +-
      ++
      + +-
      ++
      + Runs several generators in parallel. + This means that the next binding in the sequence is obtained + by advancing each generator in <generator>* + by one step. + The parallel generator terminates when any of its component + generators terminates. +-The generators share a common scope for the variables ++The generators share a common scope for the variables + they introduce. +-This implies that the names of the variables introduced ++This implies that the names of the variables introduced + by the various generators must be distinct. +-
      +-
      ++ ++ + +-
      +-
      ++
      ++
      + (:while <generator> <expression>) +-
      ++
      + +-
      ++
      ++

      + Runs <generator> while <expression> + evaluates to non-#f. + The guarding expression is included in the scope +-of the variables introduced by the generator.

      +- ++of the variables introduced by the generator. ++

      ++

      + Note the distinction between the filter if and + the modified generator expressed by :while. +-

      +-
      ++

      ++ ++ ++ + +-
      +-
      ++
      ++
      + (:until <generator> <expression>) +-
      ++
      + +-
      +-Runs <generator> until after ++
      ++

      ++Runs <generator> until after + <expression> has evaluated to non-#f. + The guarding expression is included in the scope +-of the variables introduced by the generator.

      +- +-Note the distinction between :while, stopping at +-a certain condition, and :until, stopping after ++of the variables introduced by the generator. ++

      ++

      ++Note the distinction between :while, stopping at ++a certain condition, and :until, stopping after + a certain condition has occurred. The latter implies that the binding + that has triggered termination has been processed by the comprehension. +-

      +-
      ++

      ++ ++ + +-
      +-
      ++
      ++
      + <application-specific typed generator> +-
      ++
      + +-
      ++
      ++

      + An important aspect of this SRFI is a modular mechanism to + define new typed generators. + To define a new typed generator a hygienic referentially + transparent macro of the same name is defined to transform +-the generator pattern into an instance of the +-:do-generator. ++the generator pattern into an instance of the ++:do-generator. + The extension is fully modular, meaning that no other + macro has to be modified to add the new generator. + This is achieved by defining the new macro in +-Continuation Passing Style, as in [MWL].

      +- ++Continuation Passing Style, as in [MWL]. ++

      ++

      + Technically, this works as follows. +-Assume the generator syntax (:mygen <var> <arg>) ++Assume the generator syntax (:mygen <var> <arg>) + is to be implemented, for example running the variable <var> + through the list (reverse <arg>). +-The following definition implements :mygen +-in terms of :list +-using the additional syntactic variable cc +-(read current continuation): +- ++The following definition implements :mygen ++in terms of :list ++using the additional syntactic variable cc ++(read current continuation): ++

      +
      + (define-syntax :mygen
      +   (syntax-rules ()
      +     ((:mygen cc var arg)
      +      (:list cc var (reverse arg)) )))
      +- +-After this definition, any comprehension will accept ++

      ++After this definition, any comprehension will accept + the :mygen-generator and produce the + proper code for it. +-This works as follows. ++This works as follows. + When a comprehension sees something of the form + (g arg ...) in the position of a + <qualifier> then it will +-transform the entire comprehension into ++transform the entire comprehension into + (g (continue ...) arg ...). +-This effectively 'transfers control' to the ++This effectively 'transfers control' to the + macro g, for example :mygen. + The macro g has full control of + the transformation, but eventually it should +@@ -1263,145 +1312,152 @@ by the :list-macro. + The macro :do finally transforms + into (continue ... (:do etc ...)). + As continue has been chosen by the +-macro implementing the comprehension, ++macro implementing the comprehension, + it can regain control and proceed +-with other qualifiers.

      +- +-In order to ensure consistency of new generators ++with other qualifiers. ++

      ++

      ++In order to ensure consistency of new generators + with the ones defined in this SRFI, a few conventions + are in order. +-Firstly, the generator patterns begin with one or more ++Firstly, the generator patterns begin with one or more + variables followed by arguments defining the sequence. +-Secondly, each generator except :do ++Secondly, each generator except :do + can handle an optional index variable. + This is most easily implemented using +-:parallel +-together with :integers. ++:parallel ++together with :integers. + In case the payload generator needs an index anyhow +-(e.g. :vector) ++(e.g. :vector) + it is more efficient to add an index-variable if + none is given and to implement the indexed case. + Finally, make sure that no syntactic variable of the + generator pattern ever gets duplicated in the code + (to avoid exponential code size in nested application), +-and introduce sufficient intermediate variables to ++and introduce sufficient intermediate variables to + make sure expressions are evaluated at the correct time. +-

      +-
      +- +-

      +-Suggestions for application-specific extensions

      ++

      ++ ++ + +-

      Arrays in the sense of [SRFI25]

      ++

      ++Suggestions for application-specific extensions

      + ++

      Arrays in the sense of [SRFI25]

      ++

      + In order to create an array from a sequence of elements, + a comprehension with the following syntax would be useful: +- ++

      +
      (array-ec <shape> <qualifier>* <expression>).
      +- ++

      + The comprehension constructs a new array of the given shape +-by filling it row-major with the sequence of elements as specified ++by filling it row-major with the sequence of elements as specified + by the qualifiers. +- ++

      ++

      + On the generator side, it would be most useful to have a + generator of the form +- ++

      +
      (:array <vars> <arg>),
      +- ++

      + running through the elements of the array in row-major. +-For the optional index variable, the extension ++For the optional index variable, the extension + (index <k1> <k>*) + could be defined where <k1> <k>* + are variable names indexing the various dimensions. ++

      + +- +-

      Random Numbers in the sense of [SRFI27]

      +- ++

      Random Numbers in the sense of [SRFI27]

      ++

      + In order to create a vector or list of random numbers, + it would be convenient to have generators of the following form: +- ++

      +
      + (:random-integer [ <range> [ <number> ] ] )
      + (:random-real    [ <number> ] )
      +- +-where <range> (default 2) indicates the range of ++

      ++where <range> (default 2) indicates the range of + the integers and <number> (default infinity) + specifies how many elements are to be generated. + Derived from these basic generators, one could define several + other generators for other distributions (e.g. Gaussian). ++

      + +- +-

      Bitstrings in the sense of [SRFI33]

      +- ++

      Bitstrings in the sense of [SRFI33]

      ++

      + As eager comprehensions are efficient, they can be useful + for operations involving strings of bits. + It could be useful to have the following comprehension: +- ++

      +
      (bitwise-ec <qualifier>* <expression>),
      +- ++

      + which constructs an integer from bits obtained as values + of <expression> in the ordering defined + by [SRFI33]. +-In other words, if the sequence of values is +-x[0], x[1], ..., x[n-1] then +-the result is x[0] + x[1] 2 + ... + x[n-1] 2^(n-1). ++In other words, if the sequence of values is ++x[0], x[1], ..., x[n-1] then ++the result is x[0] + x[1] 2 + ... + x[n-1] 2^(n-1). + On the generator side, a generator of the form +- ++

      +
      (:bitwise <vars> <arg1> <arg>*)
      +- ++

      + runs through the sequence of bits obtained by appending the + binary digits of the integers <arg1> <arg>*. ++

      ++

      Streams in the sense of [SRFI 40]

      + +-

      Streams in the sense of [SRFI 40]

      +- +-It is possible to 'lazify' the eager comprehension ++

      ++It is possible to 'lazify' the eager comprehension + list-ec, + constructing a stream in the sense of [SRFI 40]. + Clearly, such a comprehension (stream-ec) + is not eager at all since it only runs the loops when results are requested. + It is also possible to define a :stream-generator with +-the same API as :list but running +-through streams instead of lists.

      +- +-For what it is worth, +-the file srfi40-ec.scm implements ++the same API as :list but running ++through streams instead of lists. ++

      ++

      ++For what it is worth, ++the file srfi40-ec.scm implements + :stream and stream-ec and gives an example. +-The implementation makes substantial use of ++The implementation makes substantial use of + call-with-current-continuation to run the loop + only when necessary. + In some implementations of Scheme this may involve + considerable overhead. ++

      + +-

      Reading Text Files

      +- ++

      Reading Text Files

      ++

      + Eager comprehensions can also be used to process files. + However, bear in mind that an eager comprehension wants + to read and process the entire file right away. + Nevertheless, these generators would be useful for + reading through the lines of a file or through the + characters of a file: +- ++

      +
      + (:lines-of-file <vars> <file>)
      + (:chars-of-file <vars> [ (line <variable1>) ] [ (column <variable2>) ] <file>)
      +- ++

      + Here <file> is either an input port + or a string interpreted as a filename. + In a similar fashion, generators reading from sockets defined + by URLs or other communication facilities could be defined. ++

      + +-

      The Scheme shell Scsh

      +- ++

      The Scheme shell Scsh

      ++

      + In the Scheme-shell Scsh it could be useful to have certain +-comprehensions and generators. ++comprehensions and generators. + Candidates for comprehensions are + begin-ec, + |-ec, + ||-ec, and +-&&-ec. ++&&-ec. + Concerning generators, it might be useful to have +-:directory running through the +-records of a directory, and maybe a ++:directory running through the ++records of a directory, and maybe a + sophisticated :file-match-generator + could enumerate file record in a directory structure. + Optional variables of the generators could give +@@ -1409,18 +1465,18 @@ convenient access frequent components of the file records + (e.g. the filename). + Another candidate is :env to run through + the environment associations. +-It is left to other authors and other SRFIs to ++It is left to other authors and other SRFIs to + define a useful set of comprehensions and generators + for Scsh. ++

      + ++

      Design Rationale

      + +-

      Design Rationale

      +- +-

      What is the difference between eager and lazy comprehensions?

      +- +-A lazy comprehension, for example stream-of in the ++

      What is the difference between eager and lazy comprehensions?

      ++

      ++A lazy comprehension, for example stream-of in the + sense of [SRFI 40], constructs an object +-representing a sequence of values. ++representing a sequence of values. + Only at the time these values are needed that they + are actually produced. + An eager comprehension, on the other hand, is an instruction to +@@ -1429,167 +1485,187 @@ for example as in do-ec. + In other words, it is nothing more sophisticated than a loop, + potentially with a more convenient notation. + This also explains why stream-of is the most +-fundamental lazy comprehension, and all others can ++fundamental lazy comprehension, and all others can + be formulated in terms of it, whereas the most fundamental +-eager comprehension is do-ec. +- +- +-

      Why the [outer .. inner | expr] +-order of qualifiers?

      ++eager comprehension is do-ec. ++

      + ++

      Why the [outer .. inner | expr] ++order of qualifiers?

      ++

      + In principle, there are six possible orders in which the + qualifiers and the expression of a comprehension can be written. + We denote the different conventions with a pattern in which +-expr denotes the expression over which the comprehension +-ranges, inner denotes the generator spinning fastest, and +-outer denotes the generator spinning slowest. +-For example, [Haskell] and ++expr denotes the expression over which the comprehension ++ranges, inner denotes the generator spinning fastest, and ++outer denotes the generator spinning slowest. ++For example, [Haskell] and + [Python] use +-[expr | outer .. inner]. ++[expr | outer .. inner]. + (Probably with sufficient persistence, instances for any + of the conventions can be found on the Internet.) +-In addition, there is the common mathematical notation +-'{f(x) | x in X}'.

      +- ++In addition, there is the common mathematical notation ++'{f(x) | x in X}'. ++

      ++

      + It is important to understand that the notational convention + does not only determine the order of enumeration but also the + scope of the variables introduced by the generators. +-The scope of inner includes expr, and the +-scope of outer should include inner to allow ++The scope of inner includes expr, and the ++scope of outer should include inner to allow + inner generates depending on outer generators. + Eventually, the choice for a particular syntactic convention is + largely a matter of personal preferences. + However, there are a few considerations that went into the +-choice made for this SRFI:

      +- +-1. The mathematical notation is universally known and widely used. +-However, the mathematical notation denotes a set comprehension ++choice made for this SRFI: ++

      ++
        ++
      1. ++

        ++The mathematical notation is universally known and widely used. ++However, the mathematical notation denotes a set comprehension + in which the order of the qualifiers is either irrelevant or must + be deduced from the context. +-For the purpose of eager comprehensions as a programming language ++For the purpose of eager comprehensions as a programming language + construct, the order does matter and a simple convention is a plus. + For these reasons, the mathematical notation as such is undesirable, + but its widespread use is in favor of +-[expr | inner .. outer] and +-[expr | outer .. inner].

        +- +-2. It is desirable to have the scope of the variables increase ++[expr | inner .. outer] and ++[expr | outer .. inner]. ++

        ++
      2. ++
      3. ++

        ++It is desirable to have the scope of the variables increase + into one direction, as in +-[expr | inner .. outer] and +-[outer .. inner | expr], and ++[expr | inner .. outer] and ++[outer .. inner | expr], and + not change direction, as in +-[expr | outer .. inner] +-where expr is in the scope of inner +-but outer is not. ++[expr | outer .. inner] ++where expr is in the scope of inner ++but outer is not. + This is even more important if the syntax in Scheme +-does not explicitly contain the '|'-separator.

        +- +-3. More complicated comprehensions with several nested generators ++does not explicitly contain the '|'-separator. ++

        ++
      4. ++
      5. ++

        ++More complicated comprehensions with several nested generators + eventually look like nested loops and Scheme always +-introduces them outer .. inner as in ++introduces them outer .. inner as in + do and named-let. +-This is in favor of +-[expr | outer .. inner] and +-[outer .. inner | expr]. ++This is in favor of ++[expr | outer .. inner] and ++[outer .. inner | expr]. + Shorter comprehension may look more naturally the +-other way around.

        +- +-Regarding these contradicting preferences, I regard +-linearity in scoping (2.) most important, followed by ++other way around. ++

        ++
      6. ++
      ++

      ++Regarding these contradicting preferences, I regard ++linearity in scoping (2.) most important, followed by + readability for more complicated comprehensions (3.). +-This leads to [outer .. inner | expr]. ++This leads to [outer .. inner | expr]. + An example in Scheme-syntax is + (list-ec (: x 10) (: y x) (f x y)), + which looks acceptable to me even without similarity + to the mathematical notation. + As a downside, the convention clashes with other the + convention used in other languages (e.g. Haskell and Python). ++

      + +- +-

      You forgot [choose your favorite here]-ec!

      +- ++

      You forgot [choose your favorite here]-ec!

      ++

      + I tried to construct a reasonably useful set of tools + according to what [R5RS] specifies. + Nevertheless, is the choice what to include and what to +-leave out eventually a matter of personal preference.

      +- ++leave out eventually a matter of personal preference.

      ++

      ++

      + When 'packing the toolbox' I went for travelling light; + this SRFI does not include everything imaginable + or even everything useful. +-I oriented myself at the standard procedures ++I oriented myself at the standard procedures + of [R5RS], + with a few omissions and additions. +-A notable omission are gcd-ec and ++A notable omission are gcd-ec and + lcm-ec because they are one-liners, + and more severely, of questionable value in practice. + A notable addition are + fold-ec and + fold3-ec, + providing a mechanism to define lots of useful one-liners. +-The other notable addition is ++The other notable addition is + first-ec, which + is the fundamental 'early stopping' comprehension. +-It is used to define +-any?-ec and +-every?-ec +-which are among the most frequent comprehensions.

      +- ++It is used to define ++any?-ec and ++every?-ec ++which are among the most frequent comprehensions. ++

      ++

      + Concerning the generators, the same principle has been used. +-Additions include :range +-and friends because they are universally needed, and +-:dispatched which is +-primarily intended for implementing :. +- +- +-

      Why is the order of enumeration specified?

      ++Additions include :range ++and friends because they are universally needed, and ++:dispatched which is ++primarily intended for implementing :. ++

      + ++

      Why is the order of enumeration specified?

      ++

      + For the purpose of this SRFI, every generator runs through +-its sequence of bindings in a well specified order, and nested +-generators run through the Cartesian product in the order ++its sequence of bindings in a well specified order, and nested ++generators run through the Cartesian product in the order + of nested loops. +-The purpose of this definition is making the sequence as ++The purpose of this definition is making the sequence as + easily predictable as possible. +- +-On the other hand, many mechanisms for lazy comprehensions ++

      ++

      ++On the other hand, many mechanisms for lazy comprehensions + do not specify the order in which the elements are enumerated. +-When it comes to infinite streams, this has the great advantage +-that a comprehension may interleave an inner and an outer ++When it comes to infinite streams, this has the great advantage ++that a comprehension may interleave an inner and an outer + enumeration, a method also known as 'dove-tailing' or 'diagonalizing'. +-Interleaving ensures that any value of the resulting stream is +-produced after a finite amount of time, even if one or more ++Interleaving ensures that any value of the resulting stream is ++produced after a finite amount of time, even if one or more + inner streams are infinite. ++

      + +-

      Why both typed and dispatching generators?

      +- ++

      Why both typed and dispatching generators?

      ++

      + The reason for typed generators is runtime efficiency. + In fact, the code produced by :range and others + will run as fast as a hand-coded do-loop. + The primary purpose of the dispatching generator is convenience. + It comes at the price of reduced runtime performance, + both for loop iteration and startup. ++

      + +-

      Why the something-ec and :type naming?

      +- +-The purpose of the :type convention is to keep ++

      Why the something-ec and :type naming?

      ++

      ++The purpose of the :type convention is to keep + many common comprehensions down to one-liners. + In my opinion, the fundamental nature of eager comprehensions + justifies a single character naming convention. +-The something-ec convention is primarily intended to +-stay away from the widely used something-of. ++The something-ec convention is primarily intended to ++stay away from the widely used something-of. + It reduces confusion and conflict with related mechanisms. ++

      + +-

      Why combine variable binding and sequence definition?

      +- ++

      Why combine variable binding and sequence definition?

      ++

      + The generators of this SRFI do two different things with + a single syntactic construct: They define a sequence of values + to enumerate and they specify a variable (within a certain + scope) to run through that sequence. +-An alternative is to separate the two, for example as it +-has been done in +-SRFI 40.

      +- ++An alternative is to separate the two, for example as it ++has been done in ++SRFI 40. ++

      ++

      + The reason for combining sequence definition and enumeration +-for the purpose of this SRFI is threefold. ++for the purpose of this SRFI is threefold. + Firstly, sequences of values are not explicitly represented as + objects in the typed generators; the generators merely + manipulate an internal state. +@@ -1598,115 +1674,125 @@ common comprehensions and reduces syntax to the naked minimum. + Thirdly, this SRFI aims at the highest possible performance for + typed generators, which is achieved if the state being manipulated + is represented by the loop variable itself. ++

      + +-

      Why is (: <vars>) illegal?

      +- +-It is reasonable and easy to define (: <vars>) +-as (:integers <vars>), ++

      Why is (: <vars>) illegal?

      ++

      ++It is reasonable and easy to define (: <vars>) ++as (:integers <vars>), + enumerating the non-negative integers. + However, it turned out that a frequent mistake in using the + eager comprehensions is to forget either the variable + or an argument for the enumeration. +-As this would lead to an infinite loop (not always ++As this would lead to an infinite loop (not always + equally pleasant in interactive sessions), it is not allowed. ++

      + +-

      Why is there no :sequential?

      +- +-Just like :parallel ++

      Why is there no :sequential?

      ++

      ++Just like :parallel + enumerates generators in + parallel, a :sequential generator could +-enumerate a concatenation of several generator, starting ++enumerate a concatenation of several generator, starting + the next one when the previous has finished. + The reason for not having such a qualifier is + that the generators should use all the same variable name + and there is no hygienic and referentially transparent + way of enforcing this (or even knowing the variable). ++

      + +-

      Why is there no general let-qualifier?

      +- +-It is easy to add let, let*, ++

      Why is there no general let-qualifier?

      ++

      ++It is easy to add let, let*, + and letrec as cases to <qualifier>. +-This would allow more sophisticated local variables +-and expressions than possible with +-(:let <vars> <expression>) and ++This would allow more sophisticated local variables ++and expressions than possible with ++(:let <vars> <expression>) and + (begin <sequence>*). + In particular, a local <definition> + in the sense of [R5RS, 7.1.5.] would +-be possible.

      +- +-There are two reasons for not including let ++be possible. ++

      ++

      ++There are two reasons for not including let + and friends as qualifiers. + The first reason concerns readability. +-A qualifier of the form ++A qualifier of the form + (let (<binding spec>*) <body>) +-only makes sense if the scope of the new variables ends at the +-end of the comprehension, and not already ++only makes sense if the scope of the new variables ends at the ++end of the comprehension, and not already + after <body>. +-The similarity with ordinary let-expressions ++The similarity with ordinary let-expressions + would be very confusing. + The second reason concerns the design rationale. + If sophisticated let-qualifiers involving +-recursion or local definitions are needed, it is likely ++recursion or local definitions are needed, it is likely + that eager comprehensions are being overused. + In that case it might be better to define a procedure + for the task. + So including an invitation to overuse the mechanism would +-be a serious violation of the +-Keep It Simple and Stupid principle. +- +-

      Why is there no :nested generator?

      ++be a serious violation of the ++Keep It Simple and Stupid principle. ++

      + ++

      Why is there no :nested generator?

      ++

      + The specification above defines nested +-as a qualifier but :parallel ++as a qualifier but :parallel + as a generator. + In particular, this makes it impossible to make parallel +-generators from nested ones.

      +- ++generators from nested ones. ++

      ++

      + This design simply reflects an implementability limitation. + All component generators of :parallel are +-transformed into :do-generators +-and these can be merged into a parallel generator. ++transformed into :do-generators ++and these can be merged into a parallel generator. + However, nested generators cannot be merged easily without +-losing the type of the generator, ++losing the type of the generator, + which would seriously hurt modularity and performance. ++

      + +-

      Is any?-ec eager?

      +- +-Yes, it is still eager because it immediately starts to +-run through the sequence.

      +- +-In fact, the reference implementation makes sure ++

      Is any?-ec eager?

      ++

      ++Yes, it is still eager because it immediately starts to ++run through the sequence. ++

      ++

      ++In fact, the reference implementation makes sure + first-ec, +-any?-ec, and +-every?-ec +-execute efficiently so they can be used conveniently +-as in ++any?-ec, and ++every?-ec ++execute efficiently so they can be used conveniently ++as in + (every?-ec (:list x my-list) (pred? x)). ++

      + +-

      Why this whole :dispatched business?

      +- +-It is specified above that the dispatching generator, +-called :, is just a special case +-of :dispatched using ++

      Why this whole :dispatched business?

      ++

      ++It is specified above that the dispatching generator, ++called :, is just a special case ++of :dispatched using + a global dispatching procedure. + Alternatively, a simple fixed global mechanism to extend +-: could have been used. ++: could have been used. + This is much simpler but does not support the definition +-of new dispatched generators.

      +- +-The purpose of :dispatched ++of new dispatched generators. ++

      ++

      ++The purpose of :dispatched + and its utilities +-(:generator-proc and ++(:generator-proc and + dispatch-union) + is the following. +-Assume : is to be used inside a ++Assume : is to be used inside a + module but it is essential that no other module can spoil it, + e.g. by installing a very slow dispatcher. + The recommended way to proceed in this case is to define a +-local copy of the original dispatching generator +-:, ++local copy of the original dispatching generator ++:, + for example with the following code +- ++

      +
      + (define :my-dispatch
      +   (make-initial-:-dispatch) )
      +@@ -1717,33 +1803,36 @@ for example with the following code
      +      (:dispatched cc var (index i) :my-dispatch arg1 arg ...) )
      +     ((:my cc var arg1 arg ...)
      +      (:dispatched cc var :my-dispatch arg1 arg ...) ))),
      +- ++

      + and to use the new generator :my instead of +-:.

      +- ++:. ++

      ++

      + An alternative for the dispatching mechanism as defined in + this SRFI is the use of parameter objects in the sense of +-[SRFI 39]. ++[SRFI 39]. + The dispatching generator would then access a dynamically + scoped variable to find the dispatcher, allowing full + control over dispatching. + However, this approach does not solve the dilemma that it is +-sometimes useful that : is global ++sometimes useful that : is global + and sometimes undesired. + The approach specified for this SRFI addresses this dilemma +-by offering options.

      +- ++by offering options. ++

      ++

      + Another alternative for dealing with the dispatching + problem is adding an optional argument to the syntax of +-: through which the dispatcher ++: through which the dispatcher + can be passed explicitly. +-However, as : has variable ++However, as : has variable + arity and the identifier for the variable cannot be +-distinguished from any value for a dispatcher, ++distinguished from any value for a dispatcher, + this is syntactically problematic. ++

      + +-

      Why is there no local mechanism for adding to :?

      +- ++

      Why is there no local mechanism for adding to :?

      ++

      + According to [R5RS, 7.1.6.] macros can only + be defined at the level of the <program> syntax. + This implies that the scope of typed generators cannot easily be +@@ -1751,17 +1840,19 @@ limited to local scopes. + As typed and dispatched generators go together, + there is also no strong need for a limited scope + of dispatched generators either. +-Furthermore, locally extendable dispatchers are another major ++Furthermore, locally extendable dispatchers are another major + headache to those trying to understand other people's code. ++

      + +-

      Why are dispatchers unary?

      +- +-As defined in :dispatched, ++

      Why are dispatchers unary?

      ++

      ++As defined in :dispatched, + a dispatching procedure is called with a single argument being +-the list of values to dispatch on. ++the list of values to dispatch on. + An alternative is to apply the dispatcher to the +-list of values to dispatch on, which would be more natural in Scheme.

      +- ++list of values to dispatch on, which would be more natural in Scheme. ++

      ++

      + The reason for not using apply is a minor + improvement in efficiency. + Every time apply is used on a procedure of variable +@@ -1769,55 +1860,61 @@ arity, an object containing the argument list is allocated on + the heap. + As a dispatcher may call many other dispatchers, this will adds + to the overhead of dispatching, which is relevant in inner loops. ++

      + +-

      Why are there two fold comprehensions?

      +- +-The reason for having two fold comprehensions ++

      Why are there two fold comprehensions?

      ++

      ++The reason for having two fold comprehensions + (fold-ec and +-fold3-ec) is efficiency.

      +- +-Clearly, the more general construction is +-fold3-ec ++fold3-ec) is efficiency. ++

      ++

      ++Clearly, the more general construction is ++fold3-ec + as it allows individual treatment of the empty + sequence case and the singleton sequence case. + However, this comes at the price of more book-keeping +-as can be seen from the ++as can be seen from the + implementation example. + As the overhead is located within inner loops, + it makes sense to define another fold comprehension + for the case where the added flexibility is not needed. +-This is fold-ec.

      +- ++This is fold-ec. ++

      ++

      + The names fold-ec and fold3-ec + have been chosen for the comprehensions in order to stay + clear any other 'fold' that may be around. ++

      + +-

      Why is :char-range not defined by integer->char?

      +- +-The definition of :char-range ++

      Why is :char-range not defined by integer->char?

      ++

      ++The definition of :char-range + specifies a sequence of adjacent characters ordered by char<=?. +-The reason for not using char->integer and +-integer->char is the fact that ++The reason for not using char->integer and ++integer->char is the fact that + [R5RS, 6.3.4.] leaves it to the implementation + whether the integers representing characters are consecutive or not. + In effect, this underspecification is inherited by :char-range. ++

      + +- +-

      Related Work and Acknowledgements

      +- ++ ++

      + Several other proposals related to the mechanism specified here exists. +-The following mechanisms are made for and in Scheme (or at least a +-specific dialect thereof):

      +- ++The following mechanisms are made for and in Scheme (or at least a ++specific dialect thereof): ++

      ++

      + First of all, the report [R5RS] of Scheme itself +-defines two constructs for writing loops: do and ++defines two constructs for writing loops: do and + named-let. +-Both constructs express a single loop (not nested), ++Both constructs express a single loop (not nested), + possibly with several variables running in parallel, +-based on explicit manipulation of the state variables. ++based on explicit manipulation of the state variables. + For example (do ((x 0 (+ x 1))) ((= x 10)) (display x)) +-explicitly mentions how to obtain the next binding of x.

      +- ++explicitly mentions how to obtain the next binding of x. ++

      ++

      + Richard Kelsey's "Macros for writing loops", [MWL] + are an extension to Scheme48 to simplify the formulation of loops. + The basic idea is to stick with a do-like syntax for +@@ -1826,9 +1923,9 @@ a state variable explicitly. + For example, (list* x '(1 2 3)) expresses an enumeration + of the variable x through the list (1 2 3) + without explicit state manipulation. +-The iteration constructs of [MWL], named ++The iteration constructs of [MWL], named + iterate and reduce, +-express a single (not nested) loop (iterate) or ++express a single (not nested) loop (iterate) or + comprehension (reduce) with any number of + parallel enumerations. + A most important feature of the [MWL]-concept +@@ -1837,10 +1934,11 @@ In effect, the addition of a new sequence type does not + require a modification of the existing macros. + This is achieved by carefully limiting the expressive + power of the loop constructs and by using the macros +-in Continuation Passing Style to call other macros. +-The [MWL]-concept, and its implementation, +-were most influential for this SRFI.

      +- ++in Continuation Passing Style to call other macros. ++The [MWL]-concept, and its implementation, ++were most influential for this SRFI. ++

      ++

      + Another related mechanism is the library of streams recently + submitted by Phil L. Bewig as [SRFI 40]. + The library contains a data type to represent even +@@ -1856,35 +1954,36 @@ Nevertheless, modularity is high since it is easy to define + a procedure producing a stream object and this can be + used for enumeration. + The order of enumeration is left unspecified to allow +-interleaving of generators (also refer to ++interleaving of generators (also refer to + above.) + Before Phil submitted his SRFIs, we had a short + discussion in which we clarified the semantic and syntactic + differences of our approaches. +-It turned out that the mechanisms are sufficiently ++It turned out that the mechanisms are sufficiently + different not to unify them. + The most important difference is the design rationale: + Phil created his library to support the stream-paradigm +-in Scheme, inspired by the work done for Haskell and ++in Scheme, inspired by the work done for Haskell and + other lazy languages, and intrigued by the beauty + of programming with infinite streams. +-My work only aims at a convenient way of expressing ++My work only aims at a convenient way of expressing + frequent patterns of loops in a compact way. + For what it is worth, section SRFI40-ec + contains a suggestion for extending the eager comprehension +-mechanism for SRFI40-streams.

      +- ++mechanism for SRFI40-streams. ++

      ++

      + Phil's work on streams and lazy comprehensions in Scheme + triggered Eli Barzilay to implement a library of eager + comprehensions for PLT-Scheme, [Eli]. + The mechanism implemented by Eli is in essence very + similar to the one proposed in this SRFI, and the two + efforts have been independent until recently. +-Syntactically, Eli uses infix operators for generators, +-whereas this SRFI is purely prefix, and Eli uses the +-[expr | outer .. inner] convention ++Syntactically, Eli uses infix operators for generators, ++whereas this SRFI is purely prefix, and Eli uses the ++[expr | outer .. inner] convention + for nesting, whereas this SRFI uses the +-[outer .. inner | expr] ++[outer .. inner | expr] + convention. + Semantically, Eli's mechanism defines more flexible + loops than this SRFI. +@@ -1892,208 +1991,214 @@ Comprehensions are regarded as generalized collection + processes like fold and reduce. + The mechanism in this SRFI is more restricted with respect + to control flow (there is no general while) +-and more extensive with respect to generators and ++and more extensive with respect to generators and + comprehensions. +-Despite the strong conceptual similarity, the design ++Despite the strong conceptual similarity, the design + rationales are different. + This SRFI focuses on portability and modular extension, +-whatever that may cost in terms of expressive power.

      +- +-Finally, I would like to thank Mike Sperber for his ++whatever that may cost in terms of expressive power. ++

      ++

      ++Finally, I would like to thank Mike Sperber for his + encouragement to proceed with the SRFI and for several + discussions of the matter. + In particular, the dispatching mechanism evolved + rapidly during discussions with Mike. ++

      + +- +-

      Implementation

      +- +-The reference implementation focuses on portability, ++

      Implementation

      ++

      ++The reference implementation focuses on portability, + performance, readability and simplicity, roughly in this order. +-It is written in [R5RS]-Scheme ++It is written in [R5RS]-Scheme + (including macros) extended by [SRFI 23] + (error). + The reference implementation was developed + under Scheme48 (0.57), + PLT (202, 204), and +-SCM (5d7).

      +- +-The file ec.scm is the source of ++SCM (5d7). ++

      ++

      ++The file ec.scm is the source of + the reference implementation. + It also contains comments concerning potential problems. +-Implementors might find the file design.scm +-helpful. +-It contains alternative implementations of certain comprehensions ++Implementors might find the file design.scm ++helpful. ++It contains alternative implementations of certain comprehensions + and generators in order to simplify tuning the implementation +-of this SRFI for different Scheme systems.

      +- +-The file examples.scm contains a ++of this SRFI for different Scheme systems. ++

      ++

      ++The file examples.scm contains a + collection of examples, and some code checking their results. + The purpose of most examples is detecting implementation errors, + but the section 'Less artificial examples' contains a few +-real-world examples.

      +- +-The file timing.scm contains some ++real-world examples. ++

      ++

      ++The file timing.scm contains some + code to measure an idea of performance of the comprehensions. + A hand-coded do-loop, the typed generator +-(:range n), +-and the dispatching generator +-(: n) ++(:range n), ++and the dispatching generator ++(: n) + are compared. + For each loop we compare the time needed + per iteration and the time needed to construct the loop (the startup delay). +-As a rule of thumb, :range is as fast (or slightly faster) +-as a hand-coded do-loop per iteration and needs about a ++As a rule of thumb, :range is as fast (or slightly faster) ++as a hand-coded do-loop per iteration and needs about a + third more time for startup (due to type checking of the argument). + The dispatching generator needs about twice the time per iteration + (due to calling the generator procedure) and needs about five times +-as long for startup (due to dispatching).

      +- +-The file extension.scm contains +-examples for adding new generators and comprehensions.

      ++as long for startup (due to dispatching). ++

      ++

      ++The file extension.scm contains ++examples for adding new generators and comprehensions. ++

      + +-

      References

      ++

      References

      + +- ++
      + +- +- ++ ++ + +- +- ++ +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +- +- ++ ++http://srfi.schemers.org/srfi-1/mail-archive/msg00021.html ++ + +- +- ++ ++ + +- +- ++ ++ + +- +- ++ ++ + +- +- ++ ++ + +- +- ++ ++ + +- +- ++ ++ + +- +- ++ ++ + +- +- ++ ++ + + +-
      [R5RS] +-Richard Kelsey, William Clinger, and Jonathan Rees (eds.): ++
      [R5RS] ++Richard Kelsey, William Clinger, and Jonathan Rees (eds.): + Revised(5) Report on the Algorithmic Language Scheme of + 20 February 1998. + Higher-Order and Symbolic Computation, Vol. 11, No. 1, September 1998. + + http://schemers.org/Documents/Standards/R5RS/. +-
      [MWL] +-Richard Kelsey, Jonathan Rees: ++
      [MWL] ++Richard Kelsey, Jonathan Rees: + The Incomplete Scheme48 Reference Manual for Release 0.57 (July 15, 2001). + Section "Macros for writing loops". + http://s48.org/0.57/manual/s48manual_49.html +-
      [SRFI 1] +-Olin Shivers: List Library. +-http://srfi.schemers.org/srfi-1/ +-
      [SRFI 23] +-Stephan Houben: Error reporting mechanism +-http://srfi.schemers.org/srfi-23/ +-
      [SRFI 25] +-Jussi Piitulainen: Multi-dimensional Array Primitives. +-http://srfi.schemers.org/srfi-25/ +-
      [SRFI 27] +-Sebastian Egner: Sources of Random Bits. +-http://srfi.schemers.org/srfi-27/ +-
      [SRFI 33] +-Olin Shivers: Integer Bitwise-operation Library. +-http://srfi.schemers.org/srfi-33/ +-
      [SRFI 39] +-Marc Feeley: Parameter objects. +-http://srfi.schemers.org/srfi-39/ +-
      [SRFI 40] +-Philip L. Bewig: A Library of Streams. +-http://srfi.schemers.org/srfi-40/ +-
      [Eli] +-Eli Barzilay: Documentation for "misc.ss". 2002. ++
      [SRFI 1] ++Olin Shivers: List Library. ++http://srfi.schemers.org/srfi-1/ ++
      [SRFI 23] ++Stephan Houben: Error reporting mechanism ++http://srfi.schemers.org/srfi-23/ ++
      [SRFI 25] ++Jussi Piitulainen: Multi-dimensional Array Primitives. ++http://srfi.schemers.org/srfi-25/ ++
      [SRFI 27] ++Sebastian Egner: Sources of Random Bits. ++http://srfi.schemers.org/srfi-27/ ++
      [SRFI 33] ++Olin Shivers: Integer Bitwise-operation Library. ++http://srfi.schemers.org/srfi-33/ ++
      [SRFI 39] ++Marc Feeley: Parameter objects. ++http://srfi.schemers.org/srfi-39/ ++
      [SRFI 40] ++Philip L. Bewig: A Library of Streams. ++http://srfi.schemers.org/srfi-40/ ++
      [Eli] ++Eli Barzilay: Documentation for "misc.ss". 2002. + http://www.cs.cornell.edu/eli/Swindle/misc-doc.html#collect +-
      [Folds] +-John David Stone: Folds and reductions. ++
      [Folds] ++John David Stone: Folds and reductions. + Posting in relation to [SRFI 1] on 8-Jan-1999. +-http://srfi.schemers.org/srfi-1/mail-archive/msg00021.html +-
      [Haskell] +-Simon L. Peyton Jones, John Hughes: The Haskell 98 Report 1 February 1999. ++
      [Haskell] ++Simon L. Peyton Jones, John Hughes: The Haskell 98 Report 1 February 1999. + Section 3.11 "List Comprehensions". + http://www.haskell.org/onlinereport/exps.html#sect3.11 +-
      [Python] +-Guido van Rossum, Fred L. Drake Jr. (eds.): ++
      [Python] ++Guido van Rossum, Fred L. Drake Jr. (eds.): + Python Reference Manual. + Section 5.2.4 "List displays". + Release 2.2, December 21, 2001. + http://python.org/doc/2.2/ref/lists.html +-
      [SICP] +-Harold Abelson, Gerald J. Sussman, Julie Sussman: ++
      [SICP] ++Harold Abelson, Gerald J. Sussman, Julie Sussman: + Structure and Interpretation of Computer Programs. + MIT Press, 1985. + http://mitpress.mit.edu/sicp/ +-
      [IFPL] +-Philip Wadler: List Comprehensions (Chapter 7). In: ++
      [IFPL] ++Philip Wadler: List Comprehensions (Chapter 7). In: + Simon L. Peyton Jones: The Implementation of Functional Programming Languages. + Prentice Hall, 1987. +-
      [Scheme48] +-Richard Kelsey, Jonathan Rees: Scheme48 Release 0.57 (July 15, 2001). ++
      [Scheme48] ++Richard Kelsey, Jonathan Rees: Scheme48 Release 0.57 (July 15, 2001). + http://s48.org/ +-
      [SCM] +-Aubrey Jaffer: SCM Scheme Implementation. Version 5d7 (November 27, 2002). ++
      [SCM] ++Aubrey Jaffer: SCM Scheme Implementation. Version 5d7 (November 27, 2002). + http://www.swiss.ai.mit.edu/~jaffer/SCM.html +-
      [PLT] +-PLT People: PLT Scheme, DrScheme Version 203. ++
      [PLT] ++PLT People: PLT Scheme, DrScheme Version 203. + http://www.plt-scheme.org/ +-
      [Scsh] +-Olin Shivers, Brian D. Carlstrom, Martin Gasbichler, Mike Sperber: ++
      [Scsh] ++Olin Shivers, Brian D. Carlstrom, Martin Gasbichler, Mike Sperber: + Scsh Reference Manual. + For scsh release 0.6.3. + http://scsh.net/ +-
      ++ + + + +-

      Copyright

      ++

      Copyright

      +

      Copyright (C) Sebastian Egner (2003). All Rights Reserved.

      + +

      +@@ -2120,12 +2225,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

      + + +-
      ++
      +
      Author: Sebastian Egner
      +-
      Editor: Francisco Solsona
      ++
      Editor: Francisco Solsona
      + + +-Last modified: Tue Apr 5 10:43:00 CEST 2005 ++Last modified: Sun Jan 28 13:40:34 MET 2007 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-43.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-43.html +index 7ca1cd3..8c12b5a 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-43.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-43.html +@@ -1,34 +1,30 @@ +- +- ++ ++ + ++ ++ + +-SRFI 43: Vector Library +- ++ SRFI 43: Vector Library ++ ++ ++ + +-
      +-

      Title

      +-A Scheme API for test suites +-
      +- +-

      Author

      +-

      Per Bothner +-<per@bothner.com>

      ++ ++ ++ ++ ++

      SRFI 64: A Scheme API for test suites

      + +-

      Status

      +- +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-It will remain in draft status until 2005/03/17, or as amended. To +-provide input on this SRFI, please +-mailto:srfi minus 64 at srfi dot schemers dot org. +-See instructions +-here to subscribe to the list. You can access previous messages via +-the +-archive of the mailing list. +-

      +-

        +-
      • Received: 2005/01/07
      • +-
      • Draft: 2005/01/28 - 2005/03/28
      • +-
      • Revised: 2005/10/18 +-
      • Revised: 2006/02/24 +-
      • Final: 2006/06/18
      • ++

        by Per Bothner
        ++<per@bothner.com>

        ++

        This copy of the SRFI 64 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-64/srfi-64.html.

        ++ ++

        Status

        ++ ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-64 @nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Received: 2005-01-07
        • ++
        • Draft: 2005-01-28--2005-03-28
        • ++
        • Revised: 2005-10-18 ++
        • Revised: 2006-02-24 ++
        • Final: 2006-06-18
        • ++
        • Revised to fix errata: 2016-08-11
        • +
        +-

        + + +-

        Abstract

        ++ ++

        Abstract

        +

        + This defines an API for writing test suites, to make it easy + to portably test Scheme APIs, libraries, applications, and implementations. +@@ -52,7 +61,7 @@ in the context of a test-runner. This specifications + also supports writing new test-runners, to allow customization + of reporting and processing the result of running test suites.

        + +-

        Rationale

        ++

        Rationale

        + +

        The Scheme community needs a standard for writing test suites. + Every SRFI or other library should come with a test suite. +@@ -91,18 +100,19 @@ as functions or macros or built-ins. The reason for specifying them as + syntax is to allow specific tests to be skipped without evaluating sub-expressions, or for implementations + to add features such as printing line numbers or catching exceptions.

        + +-

        Specification

        ++

        Specification

        + +

        While this is a moderately complex specification, + you should be able to write simple test suites after just reading the + first few sections below. More advanced functionality, such + as writing a custom test-runner, is at the end of the specification.

        + +-

        Writing basic test suites

        ++

        Writing basic test suites

        +

        Let's start with a simple example. + This is a complete self-contained test-suite.

        + +-
        ;; Initialize and give a name to a simple testsuite.
        ++
        ++;; Initialize and give a name to a simple testsuite.
        + (test-begin "vec-test")
        + (define v (make-vector 5 99))
        + ;; Require that an expression evaluate to true.
        +@@ -132,12 +142,13 @@ tests to be executed using an implementation-specified default test runner,
        + and test-end will cause a summary to be displayed
        + in an implementation-specified manner.

        + +-

        Simple test-cases

        ++

        Simple test-cases

        +

        + Primitive test cases test that a given condition is true. + They may have a name. + The core test case form is test-assert:

        +-
        (test-assert [test-name] expression)
        ++
        ++(test-assert [test-name] expression)
        + 
        +

        + This evaluates the expression. +@@ -156,39 +167,46 @@ if there is no current test runner.

        +

        + The following forms may be more convenient than + using test-assert directly:

        +-
        (test-eqv [test-name] expected test-expr)
        ++
        ++(test-eqv [test-name] expected test-expr)
        + 
        +

        + This is equivalent to:

        +-
        (test-assert [test-name] (eqv? expected test-expr))
        ++
        ++(test-assert [test-name] (eqv? expected test-expr))
        + 
        +

        + Similarly test-equal and test-eq + are shorthand for test-assert combined with + equal? or eq?, respectively:

        +-
        (test-equal [test-name] expected test-expr)
        ++
        ++(test-equal [test-name] expected test-expr)
        + (test-eq [test-name] expected test-expr)
        +

        + Here is a simple example:

        +-
        (define (mean x y) (/ (+ x y) 2.0))
        ++
        ++(define (mean x y) (/ (+ x y) 2.0))
        + (test-eqv 4 (mean 3 5))
        + 
        +

        For testing approximate equality of inexact reals + we can use test-approximate:

        +-
        (test-approximate [test-name] expected test-expr error)
        ++
        ++(test-approximate [test-name] expected test-expr error)
        + 
        +

        + This is equivalent to (except that each argument is only evaluated once):

        +-
        (test-assert [test-name]
        ++
        ++(test-assert [test-name]
        +   (and (>= test-expr (- expected error))
        +        (<= test-expr (+ expected error))))
        + 
        + +-

        Tests for catching errors

        ++

        Tests for catching errors

        +

        + We need a way to specify that evaluation should fail. + This verifies that errors are detected when required.

        +-
        (test-error [[test-name] error-type] test-expr)
        ++
        ++(test-error [[test-name] error-type] test-expr)
        + 
        +

        + Evaluating test-expr is expected to signal an error. +@@ -197,33 +215,36 @@ The kind of error is indicated by error-type.

        + If the error-type is left out, or it is + #t, it means "some kind of unspecified error should be signaled". + For example:

        +-
        (test-error #t (vector-ref '#(1 2) 9))
        ++
        ++(test-error #t (vector-ref '#(1 2) 9))
        + 
        +

        + This specification leaves it implementation-defined (or for a future + specification) what form test-error may take, + though all implementations must allow #t. + Some implementations may support +-SRFI-35's conditions, ++SRFI-35's conditions, + but these are only standardized for +-SRFI-36's I/O conditions, which are seldom useful in test suites. ++SRFI-36's I/O conditions, which are seldom useful in test suites. + An implementation may also allow implementation-specific + exception types. + For example Java-based implementations may allow + the names of Java exception classes:

        +-
        ;; Kawa-specific example
        ++
        ++;; Kawa-specific example
        + (test-error <java.lang.IndexOutOfBoundsException> (vector-ref '#(1 2) 9))
        + 
        +

        + An implementation that cannot catch exceptions should skip + test-error forms.

        + +-

        Testing syntax

        ++

        Testing syntax

        +

        + Testing syntax is tricky, especially if we want to + check that invalid syntax is causes an error. + The following utility function can help:

        +-
        (test-read-eval-string string)
        ++
        ++(test-read-eval-string string)
        + 
        +

        + This function parses string (using read) +@@ -231,16 +252,17 @@ and evaluates the result. + The result of evaluation is returned from test-read-eval-string. + An error is signalled if there are unread characters after the + read is done. +-For example:
        +-(test-read-eval-string "(+ 3 4)") evaluates to 7.
        +-(test-read-eval-string "(+ 3 4") signals an error.
        ++For example:
        ++(test-read-eval-string "(+ 3 4)") evaluates to 7.
        ++(test-read-eval-string "(+ 3 4") signals an error.
        + (test-read-eval-string "(+ 3 4) ") signals an error, + because there is extra junk (i.e. a space) after the + list is read. +

        +

        + The test-read-eval-string used in tests:

        +-
        (test-equal 7 (test-read-eval-string "(+ 3 4)"))
        ++
        ++(test-equal 7 (test-read-eval-string "(+ 3 4)"))
        + (test-error (test-read-eval-string "(+ 3"))
        + (test-equal #\newline (test-read-eval-string "#\\newline"))
        + (test-error (test-read-eval-string "#\\newlin"))
        +@@ -251,7 +273,7 @@ The test-read-eval-string used in tests:

        + (test-equal '(x z) (test-read-string "(list 'x #;'y 'z)")) +
        + +-

        Test groups and paths

        ++

        Test groups and paths

        +

        A test group is a named sequence of forms containing testcases, + expressions, and definitions. + Entering a group sets the test group name; leaving a +@@ -265,7 +287,8 @@ Scheme values, nor are they syntactic forms.

        + A test group may contain nested inner test groups. + The test group path is a list of the currently-active + (entered) test group names, oldest (outermost) first.

        +-
        (test-begin suite-name [count])
        ++
        ++(test-begin suite-name [count])
        + 
        +

        A test-begin enters a new test group. + The suite-name becomes the current test group name, +@@ -286,7 +309,8 @@ get executed because of some unexpected error.

        +

        + Additionally, if there is no currently executing test runner, + one is installed in an implementation-defined manner.

        +-
        (test-end [suite-name])
        ++
        ++(test-end [suite-name])
        + 
        +

        + A test-end leaves the current test group. +@@ -301,11 +325,13 @@ installed a new test-runner, then the test-end + will de-install it, after reporting the accumulated test + results in an implementation-defined manner.

        + +-
        (test-group suite-name decl-or-expr ...)
        ++
        ++(test-group suite-name decl-or-expr ...)
        + 
        +

        + Equivalent to:

        +-
        (if (not (test-to-skip% suite-name))
        ++
        ++(if (not (test-to-skip% suite-name))
        +   (dynamic-wind
        +     (lambda () (test-begin suite-name))
        +     (lambda () decl-or-expr ...)
        +@@ -316,8 +342,9 @@ within the named test group.  However, the entire group is skipped
        + if it matched an active test-skip (see later).
        + Also, the test-end is executed in case of an exception.

        + +-

        Handling set-up and cleanup

        +-
        (test-group-with-cleanup suite-name
        ++

        Handling set-up and cleanup

        ++
        ++(test-group-with-cleanup suite-name
        +   decl-or-expr ...
        +   cleanup-form)
        + 
        +@@ -329,14 +356,16 @@ The latter should be executed even if + one of a decl-or-expr forms raises an exception + (assuming the implementation has a way to catch exceptions).

        +

        For example:

        +-
        (test-group-with-cleanup "test-file"
        +-  (define f (open-output-file "log"))
        +-  (do-a-bunch-of-tests f)
        +-  (close-output-port f))
        ++
        ++(let ((f (open-output-file "log")))
        ++  (test-group-with-cleanup "test-file"
        ++    (do-a-bunch-of-tests f)
        ++    (close-output-port f)))
        + 
        +- ++

        Erratum note: Earlier versions had a non-working example. ++

        + + +-

        Conditonal test-suites and other advanced features

        ++

        Conditonal test-suites and other advanced features

        +

        + The following describes features for controlling which tests to execute, + or specifing that some tests are expected to fail.

        + +-

        Test specifiers

        ++

        Test specifiers

        +

        Sometimes we want to only run certain tests, or we know that + certain tests are expected to fail. + A test specifier is one-argument function that takes a test-runner +@@ -374,16 +403,17 @@ which is coerced to a specifier procedure, as described below for + count and name.

        +

        + A simple example is:

        +-
        (if some-condition
        ++
        ++(if some-condition
        +   (test-skip 2)) ;; skip next 2 tests
        + 
        +

        +-(test-match-name name)
        ++(test-match-name name)
        + The resulting specifier matches if the current test name (as + returned by test-runner-test-name) is equals? to + name.

        +

        +-(test-match-nth n [count])
        ++(test-match-nth n [count])
        + This evaluates to a stateful predicate: A counter keeps track of + how many times it has been called. + The predicate matches the n'th time it is called +@@ -391,29 +421,30 @@ The predicate matches the n'th time it is called + the next (- count 1) times, + where count defaults to 1.

        +

        +-(test-match-any specifier ...)
        ++(test-match-any specifier ...)
        + The resulting specifier matches if any specifier + matches. + Each specifier is applied, in order, + so side-effects from a later specifier happen + even if an earlier specifier is true.

        +

        +-(test-match-all specifier ...)
        ++(test-match-all specifier ...)
        + The resulting specifier matches if each specifier + matches. + Each specifier is applied, in order, + so side-effects from a later specifier happen + even if an earlier specifier is false.

        +

        +-count (i.e. an integer)
        ++count (i.e. an integer)
        + Convenience short-hand for: (test-match-nth 1 count).

        +

        +-name (i.e. a string)
        ++name (i.e. a string)
        + Convenience short-hand for (test-match-name name).

        + +-

        Skipping selected tests

        ++

        Skipping selected tests

        +

        In some cases you may want to skip a test.

        +-
        (test-skip specifier)
        ++
        ++(test-skip specifier)
        + 
        +

        Evaluating test-skip adds the + resulting specifier +@@ -425,40 +456,44 @@ If any specifier matches, then the test is skipped.

        + For convenience, if the specifier is a string that + is syntactic sugar for (test-match-name specifier). + For example:

        +-
        (test-skip "test-b")
        ++
        ++(test-skip "test-b")
        + (test-assert "test-a")   ;; executed
        + (test-assert "test-b")   ;; skipped
        + 
        +

        + Any skip specifiers introduced by a test-skip + are removed by a following non-nested test-end.

        +-
        (test-begin "group1")
        ++
        ++(test-begin "group1")
        + (test-skip "test-a")
        + (test-assert "test-a")   ;; skipped
        + (test-end "group1")      ;; Undoes the prior test-skip
        + (test-assert "test-a")   ;; executed
        + 
        + +-

        Expected failures

        ++

        Expected failures

        +

        + Sometimes you know a test case will fail, but you don't have time + to or can't fix it. Maybe a certain feature only works on certain platforms. + However, you want the test-case to be there + to remind you to fix it. You want to note that + such tests are expected to fail.

        +-
        (test-expect-fail specifier)
        ++
        ++(test-expect-fail specifier)
        + 
        +

        + Matching tests (where matching is defined as in test-skip) + are expected to fail. This only affects test reporting, + not test execution. For example:

        +-
        (test-expect-fail 2)
        ++
        ++(test-expect-fail 2)
        + (test-eqv ...) ;; expected to fail
        + (test-eqv ...) ;; expected to fail
        + (test-eqv ...) ;; expected to pass
        + 
        + +-

        Test-runner

        ++

        Test-runner

        +

        + A test-runner is an object that runs a test-suite, + and manages the state. The test group path, and the sets skip and +@@ -466,39 +501,39 @@ expected-fail specifiers are part of the test-runner. + A test-runner will also typically accumulate statistics about executed tests, +

        +

        +-(test-runner? value)
        ++(test-runner? value)
        + True iff value is a test-runner object.

        +

        +-(test-runner-current)
        +-(test-runner-current runner)
        ++(test-runner-current)
        ++(test-runner-current runner)
        + Get or set the current test-runner. + If an implementation supports parameter objects +-(as in SRFI-39), ++(as in SRFI-39), + then test-runner-current can be a parameter object. + Alternatively, test-runner-current may be implemented + as a macro or function + that uses a fluid or thread-local variable, or a plain global variable.

        +

        +-(test-runner-get)
        +-Same as (test-runner-current), buth trows an exception ++(test-runner-get)
        ++Same as (test-runner-current), buth throws an exception + if there is no current test-runner.

        +

        +-(test-runner-simple)
        ++(test-runner-simple)
        + Creates a new simple test-runner, that prints errors and a summary + on the standard output port.

        +

        +-(test-runner-null)
        ++(test-runner-null)
        + Creates a new test-runner, that does nothing with the test results. + This is mainly meant for extending when writing a custom runner.

        +

        + Implementations may provide other test-runners, perhaps + a (test-runner-gui).

        +-

        (test-runner-create)
        ++

        (test-runner-create)
        + Create a new test-runner. Equivalent to + ((test-runner-factory)).

        +

        +-(test-runner-factory)
        +-(test-runner-factory factory)
        ++(test-runner-factory)
        ++(test-runner-factory factory)
        + Get or set the current test-runner factory. + A factory is a zero-argument function that creates a new test-runner. + The default value is test-runner-simple, +@@ -506,9 +541,9 @@ but implementations may provide a way to override the default. + As with test-runner-current, this may be a parameter object, + or use a per-thread, fluid, or global variable.

        + +-

        Running specific tests with a specified runner

        ++

        Running specific tests with a specified runner

        +

        +-(test-apply [runner] specifier ... procedure)
        ++(test-apply [runner] specifier ... procedure)
        + Calls procedure with no arguments using the specified + runner as the current test-runner. + If runner is omitted, +@@ -521,16 +556,16 @@ if it matches any of the specifiers in the + test-apply and does not match any + active test-skip specifiers.

        +

        +-(test-with-runner runner decl-or-expr ...)
        ++(test-with-runner runner decl-or-expr ...)
        + Executes each decl-or-expr in order in a context + where the current test-runner is runner.

        + +-

        Test results

        ++

        Test results

        +

        Running a test sets various status properties in the current test-runner. + This can be examined by a custom test-runner, + or (more rarely) in a test-suite.

        + +-

        Result kind

        ++

        Result kind

        +

        Running a test may yield one of the following + status symbols:

        +
        +@@ -541,7 +576,7 @@ status symbols:

        +
        'skip
        The test was skipped.
        +
        +

        +-(test-result-kind [runner])
        ++(test-result-kind [runner])
        + Return one of the above result codes from the most recent tests. + Returns #f if no tests have been run yet. + If we've started on a new test, but don't have a result yet, +@@ -549,13 +584,13 @@ then the result kind is 'xfail is the test is expected to fail, + 'skip is the test is supposed to be skipped, + or #f otherwise.

        +

        +-(test-passed? [runner])
        ++(test-passed? [runner])
        + True if the value of (test-result-kind [runner]) + is one of 'pass or 'xpass. + This is a convenient shorthand that might be useful + in a test suite to only run certain tests if the previous test passed.

        + +-

        Test result properties

        ++

        Test result properties

        +

        + A test runner also maintains a set of more detailed result properties + associated with the current or most recent test. (I.e. the properties of the +@@ -564,44 +599,44 @@ Each property has a name (a symbol) and a value (any value). + Some properties are standard or set by the implementation; + implementations can add more.

        +

        +-(test-result-ref runner 'pname [default])
        ++(test-result-ref runner 'pname [default])
        + Returns the property value associated with the pname property name. + If there is no value associated with 'pname + return default, + or #f if default isn't specified.

        +

        +-(test-result-set! runner 'pname value)
        ++(test-result-set! runner 'pname value)
        + Sets the property value associated with the pname + property name to value. + Usually implementation code should call this function, but it may be + useful for a custom test-runner to add extra properties.

        +

        +-(test-result-remove runner 'pname)
        ++(test-result-remove runner 'pname)
        + Remove the property with the name 'pname.

        +

        +-(test-result-clear runner)
        ++(test-result-clear runner)
        + Remove all result properties. + The implementation automatically calls test-result-clear + at the start of a test-assert and similar procedures.

        +

        +-(test-result-alist runner)
        ++(test-result-alist runner)
        + Returns an association list of the current result properties. + It is unspecified if the result shares state with the test-runner. + The result should not be modified, on the other hand the result + may be implicitly modified by future test-result-set! or + test-result-remove calls. +-However, A test-result-clear does not modify the returned ++However, a test-result-clear does not modify the returned + alist. Thus you can archive result objects from previous runs.

        + +-

        Standard result properties

        ++

        Standard result properties

        +

        + The set of available result properties is implementation-specific. + However, it is suggested that the following might be provided:

        +
        +
        'result-kind
        +
        The result kind, as defined previously. +-This is the only mandatory result property.
        +-(test-result-kind runner) is equivalent to:
        ++This is the only mandatory result property.
        ++(test-result-kind runner) is equivalent to:
        + (test-result-ref runner 'result-kind) +
        +
        'source-file
        +@@ -622,12 +657,12 @@ specified in a test-error, if it meaningful and known. + The actual error value is implementation-defined. +
        + +-

        Writing a new test-runner

        ++

        Writing a new test-runner

        +

        This section specifies how to write a test-runner. + It can be ignored if you just want to write test-cases.

        + + +-

        Call-back functions

        ++

        Call-back functions

        +

        + These call-back functions are methods (in the object-oriented sense) + of a test-runner. A method test-runner-on-event +@@ -635,66 +670,66 @@ is called by the implementation when event happens.

        +

        + To define (set) the callback function for event use the following expression. + (This is normally done when initializing a test-runner.) +-
        ++
        + (test-runner-on-event! runner event-function)

        +

        + An event-function takes a test-runner argument, and possibly other arguments, depending on the event.

        +

        +-To extract (get) the callback function for event do this:
        ++To extract (get) the callback function for event do this:
        + (test-runner-on-event runner)

        +

        + To extract call the callback function for event use the following expression. +-(This is normally done by the implementation core.)
        ++(This is normally done by the implementation core.)
        + ((test-runner-on-event runner) runner other-args ...)

        +

        + The following call-back hooks are available.

        +

        +-(test-runner-on-test-begin runner)
        +-(test-runner-on-test-begin! runner on-test-begin-function)
        +-(on-test-begin-function runner)
        ++(test-runner-on-test-begin runner)
        ++(test-runner-on-test-begin! runner on-test-begin-function)
        ++(on-test-begin-function runner)
        + The on-test-begin-function is called at the start of an + individual testcase, before the test expression (and expected value) are + evaluated. +

        +

        +-(test-runner-on-test-end runner)
        +-(test-runner-on-test-end! runner on-test-end-function)
        +-(on-test-end-function runner)
        ++(test-runner-on-test-end runner)
        ++(test-runner-on-test-end! runner on-test-end-function)
        ++(on-test-end-function runner)
        + The on-test-end-function is called at the end of an + individual testcase, when the result of the test is available.

        +

        +-(test-runner-on-group-begin runner)
        +-(test-runner-on-group-begin! runner on-group-begin-function)
        +-(on-group-begin-function runner suite-name count)
        ++(test-runner-on-group-begin runner)
        ++(test-runner-on-group-begin! runner on-group-begin-function)
        ++(on-group-begin-function runner suite-name count)
        + The on-group-begin-function is called by a test-begin, + including at the start of a test-group. + The suite-name is a Scheme string, + and count is an integer or #f.

        +

        +-(test-runner-on-group-end runner)
        +-(test-runner-on-group-end! runner on-group-end-function)
        +-(on-group-end-function runner)
        ++(test-runner-on-group-end runner)
        ++(test-runner-on-group-end! runner on-group-end-function)
        ++(on-group-end-function runner)
        + The on-group-end-function is called by a test-end, + including at the end of a test-group.

        +

        +-(test-runner-on-bad-count runner)
        +-(test-runner-on-bad-count! runner on-bad-count-function)
        +-(on-bad-count-function runner actual-count expected-count)
        ++(test-runner-on-bad-count runner)
        ++(test-runner-on-bad-count! runner on-bad-count-function)
        ++(on-bad-count-function runner actual-count expected-count)
        + Called from test-end (before the on-group-end-function + is called) if an expected-count was specified by the matching + test-begin and the expected-count does not match + the actual-count of tests actually executed or skipped.

        +

        +-(test-runner-on-base-end-name runner)
        +-(test-runner-on-bad-end-name! runner on-bad-end-name-function)
        +-(on-bad-end-name-function runner begin-name end-name)
        ++(test-runner-on-bad-end-name runner)
        ++(test-runner-on-bad-end-name! runner on-bad-end-name-function)
        ++(on-bad-end-name-function runner begin-name end-name)
        + Called from test-end (before the on-group-end-function + is called) if a suite-name was specified, and it did not that the + name in the matching test-begin.

        +

        +-(test-runner-on-final runner)
        +-(test-runner-on-final! runner on-final-function)
        +-(on-final-function runner)
        ++(test-runner-on-final runner)
        ++(test-runner-on-final! runner on-final-function)
        ++(on-final-function runner)
        + The on-final-function takes one parameter (a test-runner) + and typically displays a summary (count) of the tests. + The on-final-function is called after called the +@@ -705,73 +740,74 @@ to the standard output port the number of tests of the various kinds. +

        +

        + The default test-runner returned by test-runner-simple +-uses the following call-back functions:
        +-(test-on-test-begin-simple runner)
        +-(test-on-test-end-simple runner)
        +-(test-on-group-begin-simple runner suite-name count)
        +-(test-on-group-end-simple runner)
        +-(test-on-bad-count-simple runner actual-count expected-count)
        +-(test-on-bad-end-name-simple runner begin-name end-name)
        +-You can call those if you want to write a your own test-runner.

        ++uses the following call-back functions:
        ++(test-on-test-begin-simple runner)
        ++(test-on-test-end-simple runner)
        ++(test-on-group-begin-simple runner suite-name count)
        ++(test-on-group-end-simple runner)
        ++(test-on-bad-count-simple runner actual-count expected-count)
        ++(test-on-bad-end-name-simple runner begin-name end-name)
        ++You can call those if you want to write your own test-runner.

        + +-

        Test-runner components

        ++

        Test-runner components

        +

        + The following functions are for accessing the other components of a test-runner. + They would normally only be used to write a new test-runner or + a match-predicate.

        +

        +-(test-runner-pass-count runner)
        ++(test-runner-pass-count runner)
        + Returns the number of tests that passed, and were expected to pass.

        +

        +-(test-runner-fail-count runner)
        ++(test-runner-fail-count runner)
        + Returns the number of tests that failed, but were expected to pass.

        +

        +-(test-runner-xpass-count runner)
        ++(test-runner-xpass-count runner)
        + Returns the number of tests that passed, but were expected to fail.

        +

        +-(test-runner-xfail-count runner)
        ++(test-runner-xfail-count runner)
        + Returns the number of tests that failed, and were expected to pass.

        +

        +-(test-runner-skip-count runner)
        ++(test-runner-skip-count runner)
        + Returns the number of tests or test groups that were skipped.

        +

        +-(test-runner-test-name runner)
        ++(test-runner-test-name runner)
        + Returns the name of the current test or test group, as a string. + During execution of test-begin this is the name of the + test group; during the execution of an actual test, this is the name + of the test-case. + If no name was specified, the name is the empty string.

        +

        +-(test-runner-group-path runner)
        ++(test-runner-group-path runner)
        + A list of names of groups we're nested in, with the outermost group first.

        +

        +-(test-runner-group-stack runner)
        ++(test-runner-group-stack runner)
        + A list of names of groups we're nested in, with the outermost group last. + (This is more efficient than test-runner-group-path, + since it doesn't require any copying.)

        +

        +-(test-runner-aux-value runner)
        +-(test-runner-aux-value! runner on-test)
        ++(test-runner-aux-value runner)
        ++(test-runner-aux-value! runner on-test)
        + Get or set the aux-value field of a test-runner. + This field is not used by this API or the test-runner-simple + test-runner, but may be used by custom test-runners to store extra state.

        +

        +-(test-runner-reset runner)
        ++(test-runner-reset runner)
        + Resets the state of the runner to its initial state. +

        + +-

        Example

        ++

        Example

        +

        This is an example of a simple custom test-runner. + Loading this program before running a test-suite will install + it as the default test runner.

        +-
        (define (my-simple-runner filename)
        ++
        ++(define (my-simple-runner filename)
        +   (let ((runner (test-runner-null))
        + 	(port (open-output-file filename))
        +         (num-passed 0)
        +         (num-failed 0))
        +-    (test-runner-on-test! runner
        +-      (lambda (runner result)
        +-        (case (cdr (assq 'result-kind result))
        ++    (test-runner-on-test-end! runner
        ++      (lambda (runner)
        ++        (case (test-result-kind runner)
        +           ((pass xpass) (set! num-passed (+ num-passed 1)))
        +           ((fail xfail) (set! num-failed (+ num-failed 1)))
        +           (else #t))))
        +@@ -786,31 +822,31 @@ it as the default test runner.

        + (lambda () (my-simple-runner "/tmp/my-test.log"))) +
        + +-

        Implementation

        ++

        Implementation

        +

        + The test implementation uses cond-expand +-(SRFI-0) ++(SRFI-0) + to select different code depending on certain SRFI names (srfi-9, + srfi-34, srfi-35, srfi-39), + or implementations (kawa). + It should otherwise be portable to any R5RS implementation.

        + +-

        testing.scm

        ++

        testing.scm

        + +-

        Examples

        +-

        Here is srfi-25-test.scm, ++

        Examples

        ++

        Here is srfi-25-test.scm, + based converted from Jussi Piitulainen's +-test.scm +-for SRFI-25.

        ++test.scm ++for SRFI-25.

        + +-

        Test suite

        ++

        Test suite

        +

        + Of course we need a test suite for the testing framework itself. +-This suite srfi-64-test.scm ++This suite srfi-64-test.scm + was contributed by Donovan Kolbly + <donovan@rscheme.org>.

        + +-

        Copyright

        ++

        Copyright

        +

        + Copyright (C) Per Bothner (2005, 2006)

        +

        +@@ -832,14 +868,14 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

        +-
        ++
        +
        Author: Per Bothner
        +
        Editor: Francisco Solsona
        +

        + + +-Last modified: Sun Jan 28 13:40:18 MET 2007 ++Last modified: Thu Mar 31 19:49:52 MST 2011 + +

        +- +- ++ ++ +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-66.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-66.html +index 7d8fcb3..c3936b9 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-66.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-66.html +@@ -1,40 +1,243 @@ +- +- +- ++ ++ + +-SRFI 66: Octet Vectors ++ ++ ++ SRFI 66: Octet Vectors ++ ++ ++ + + + +-

        Title

        +- +-Octet Vectors +- +-

        Authors

        +- +-Michael Sperber +- +-

        Status

        +- +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-To +-provide input on this SRFI, please +-mailto:srfi-66@srfi.schemers.org. +-See instructions +-here to subscribe to the list. You can access previous messages via +-the +-archive of the mailing list. +-

        +-

        +- +-

        Abstract

        This SRFI defines a set of procedures for creating, accessing, and manipulating uniform vectors of octets.

        Rationale

        A number of applications deal with sequences of octets (often called bytes), most prominently interfaces to C and I/O. Vectors are typically too space-costly and too slow to work well in these circumstance. This justifies having a separate type for octet vectors.

        This SRFI is related to SRFI 4 (Homogeneous numeric vector datatypes), which also provides vectors of octets, and uses names consistent with it. However, the extension described here does not require any extensions to the syntax of the underlying Scheme system, and provides a slightly richer set of primtives.

        Scheme systems implementing both SRFI 4 and this SRFI should use the same type for u8vector and octet vectors as specified here.

        Specification

        Octet vectors are objects of a new type. This type may or may not be disjoint from the type of regular vectors. Its elements must be octets, that is, exact integers in the range [0,255].

        As with vectors, the length of a octet vector is the number of elements it contains. This number is fixed. A valid index into a octet vector is an exact, non-negative integer. The first element of a octet vector has index 0, the last element has an index one less than the length of the vector.

        (u8vector? obj)

        Returns #t if obj is a vector, otherwise returns #f. Analogous to vector?.

        (make-u8vector k fill)

        Returns a newly allocated octet vector of k elements. Each element is initialized to fill. Fill must be an octet. Analogous to make-vector.

        (u8vector octet ...)

        Returns a newly allocated octet vector whose elements contain the given arguments, which must all be octets. Analogous to vector.

        (u8vector->list u8vector)
        (list->u8vector octets)

        u8vector->listreturns a newly allocated list of the elements of u8vector in the same order.Analogous to vector->list.

        List->u8vector returns a newly allocated octet vector whose elements are the elements of list octets, which must all be octets. Analogous to list->vector.

        (u8vector-length u8vector)

        Returns the number of elements in u8vector as an exact integer. Analogous to vector-length.

        (u8vector-ref u8vector k)

        k must be a valid index of u8vector. u8vector-ref returns the contents of element k of u8vector. Analogous to vector-ref.

        (u8vector-set! u8vector k octet)

        k must be a valid index of u8vector. u8vector-set! stores octet in element k of u8vector. The number of return values and the return values are unspecified. However, the number of return values is such that it is accepted by a continuation created by begin. Analogous to vector-set!.

        (u8vector=? u8vector-1 u8vector-2)

        Returns #t if u8vector-1 and u8vector-2 are equal---that is, if they have the same length and equal elements at all valid indices.

        (u8vector-compare u8vector-1 u8vector-2)

        Compares u8vector-1 and u8vector-2 and returns a value consistent with the vector ordering specified in SRFI 67, i.e. -1 if u8vector-1 is smaller than u8vector-2, 0 if they are equal, and 1 if u8vector-1 is greater than u8vector-2. Shorter vectors are always smaller than longer ones, and vectors of equal length are compared lexicographically.

        (u8vector-copy! source source-start target target-start n)

        Copies data from octet vector source to octet vector target. Source-start, target-start, and n must be non-negative exact integers that satisfy

        0 <= source-start <= source-start + n <= (u8vector-length source)

        0 <= target-start <= target-start + n <= (u8vector-length target)

        This copies the octets from source at indices [source-start, source-start + n) to consecutive indices in target starting at target-index.

        This must work even if the memory regions for the source and the target overlap, i.e., the octets at the target location after the copy must be equal to the octets at the source location before the copy.

        The number of return values and the return values are unspecified. However, the number of return values is such that it is accepted by a continuation created by begin. Analogous to vector-ref.

        (u8vector-copy u8vector)

        Returns a newly allocated copy of octet vector u8vector.

        Reference Implementation

        This reference implementation makes use of SRFI 9 (Defining Record Types) and SRFI 23 (Error reporting mechanism) .

        (define-record-type :u8vector
        ++

        SRFI 66: Octet Vectors

        ++ ++

        by Michael Sperber

        ++

        This copy of the SRFI 66 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-66/srfi-66.html.

        ++ ++

        Status

        ++ ++

        ++ This SRFI is currently in final status. Here ++ is an explanation ++ of each status that a SRFI can hold. To provide input on this SRFI, please ++ send email ++ to srfi-66@nospamsrfi.schemers.org. ++ To subscribe to the list, ++ follow these ++ instructions. You can access previous messages via the mailing ++ list archive.

        ++
          ++
        • ++ Received: 2005-03-11 ++
        • ++
        • ++ Revised: 2005-04-18 ++
        • ++
        • ++ Revised: 2005-06-06 ++
        • ++
        • ++ Final: 2005-12-15 ++
        • ++
        • ++ Revised to fix errata: ++
            ++
          • ++ 2017-07-17 (Added missing arguments to u8vector-ref.) ++
          • ++
          ++
        • ++
        ++ ++

        Abstract

        ++

        ++ This SRFI defines a set of procedures for creating, accessing, and ++ manipulating uniform vectors of octets. ++

        ++

        Rationale

        ++

        ++ A number of applications deal with sequences of octets (often called bytes), ++ most prominently interfaces to C and I/O. Vectors are typically too ++ space-costly and too slow to work well in these circumstance. This ++ justifies having a separate type for octet vectors. ++

        ++

        ++ This SRFI is related to SRFI ++ 4 (Homogeneous numeric vector datatypes), which also provides vectors of ++ octets, and uses names consistent with it. However, the extension described ++ here does not require any extensions to the syntax of the underlying Scheme ++ system, and provides a slightly richer set of primtives. ++

        ++

        ++ Scheme systems implementing both SRFI 4 and this SRFI should use the same ++ type for u8vector and octet vectors as specified here. ++

        ++

        Specification

        ++

        ++ Octet vectors are objects of a new type. This type may or may not be ++ disjoint from the type of regular vectors. Its elements must be octets, ++ that is, exact integers in the range [0,255]. ++

        ++

        ++ As with vectors, the length of a octet vector is the number of elements it ++ contains. This number is fixed. A valid index into a octet vector is an ++ exact, non-negative integer. The first element of a octet vector has index ++ 0, the last element has an index one less than the length of the vector. ++

        ++
        ++
        (u8vector? obj)
        ++
        ++

        ++ Returns #t if obj is an octect vector, otherwise ++ returns #f. Analogous to vector?. ++

        ++
        ++
        (make-u8vector k fill)
        ++
        ++

        ++ Returns a newly allocated octet vector of k elements. Each ++ element is initialized to fill. Fill must be an ++ octet. Analogous to make-vector. ++

        ++
        ++
        (u8vector octet ...)
        ++
        ++

        ++ Returns a newly allocated octet vector whose elements contain the given ++ arguments, which must all be octets. Analogous to vector. ++

        ++
        ++
        (u8vector->list u8vector)
        ++
        (list->u8vector octets)
        ++
        ++

        ++ u8vector->listreturns a newly allocated list of the ++ elements of u8vector in the same order.Analogous ++ to vector->list. ++

        ++
        ++
        ++

        ++ List->u8vector returns a newly allocated octet vector ++ whose elements are the elements of list octets, which must all ++ be octets. Analogous to list->vector. ++

        ++
        ++
        (u8vector-length u8vector)
        ++
        ++

        ++ Returns the number of elements in u8vector as an exact integer. ++ Analogous to vector-length. ++

        ++
        ++
        (u8vector-ref u8vector k)
        ++
        ++

        ++ k must be a valid index ++ of u8vector. u8vector-ref returns the contents of ++ element k of u8vector. Analogous ++ to vector-ref. ++

        ++
        ++
        (u8vector-set! u8vector k octet)
        ++
        ++

        ++ k must be a valid index ++ of u8vector. u8vector-set! ++ stores octet in element k of u8vector. ++ The number of return values and the return values are unspecified. ++ However, the number of return values is such that it is accepted by a ++ continuation created by begin. Analogous ++ to vector-set!. ++

        ++
        ++
        (u8vector=? u8vector-1 u8vector-2)
        ++
        ++

        ++ Returns #t if u8vector-1 and u8vector-2 ++ are equal---that is, if they have the same length and equal elements at ++ all valid indices. ++

        ++
        ++
        (u8vector-compare u8vector-1 u8vector-2)
        ++
        ++

        ++ Compares u8vector-1 and u8vector-2 and returns a ++ value consistent with the vector ordering specified ++ in SRFI 67, i.e. -1 ++ if u8vector-1 is smaller than u8vector-2, 0 if they ++ are equal, and 1 if u8vector-1 is greater ++ than u8vector-2. Shorter vectors are always smaller than longer ++ ones, and vectors of equal length are compared lexicographically. ++

        ++
        ++
        (u8vector-copy! source source-start target target-start n)
        ++
        ++

        ++ Copies data from octet vector source to octet ++ vector target. Source-start, target-start, ++ and n must be non-negative exact integers that satisfy ++

        ++

        ++ 0 <= source-start <= source-start ++ + n <= (u8vector-length source) ++

        ++

        ++ 0 <= target-start <= target-start ++ + n <= (u8vector-length target) ++

        ++

        ++ This copies the octets from source at indices ++ [source-start, source-start + n) to ++ consecutive indices in target starting ++ at target-index. ++

        ++

        ++ This must work even if the memory regions for the source and the target ++ overlap, i.e., the octets at the target location after the copy must be ++ equal to the octets at the source location before the copy. ++

        ++

        ++ The number of return values and the return values are unspecified. ++ However, the number of return values is such that it is accepted by a ++ continuation created by begin. Analogous ++ to vector-ref. ++

        ++
        ++
        (u8vector-copy u8vector)
        ++
        ++

        ++ Returns a newly allocated copy of octet vector u8vector. ++

        ++
        ++
        ++

        Reference Implementation

        ++

        ++ This reference implementation makes use ++ of SRFI 9 (Defining Record ++ Types) and SRFI 23 (Error ++ reporting mechanism) . ++

        ++
        (define-record-type :u8vector
        +   (really-make-u8vector elements)
        +   u8vector?
        +   (elements u8vector-elements))
        +@@ -44,7 +247,7 @@ archive of the mailing list.
        + 		(exact? thing)
        + 		(>= thing 0)
        + 		(<= thing 255)))
        +-      (error "not a octet" thing)))
        ++      (error "not a octet" thing)))
        + 
        + (define (make-u8vector k fill)
        +   (ensure-octet fill)
        +@@ -94,8 +297,8 @@ archive of the mailing list.
        +     (and (= size (u8vector-length u8vector-2))
        + 	 (let loop ((i 0))
        + 	   (or (>= i size)
        +-	       (and (= (u8vector-ref u8vector-1)
        +-		       (u8vector-ref u8vector-2))
        ++	       (and (= (u8vector-ref u8vector-1 i)
        ++		       (u8vector-ref u8vector-2 i))
        + 		    (loop (+ 1 i))))))))
        + 
        + (define (u8vector-compare u8vector-1 u8vector-2)
        +@@ -113,27 +316,45 @@ archive of the mailing list.
        +                (cond ((< elt-1 elt-2) -1)
        +                      ((> elt-1 elt-2)  1)
        +                      (else (loop (+ i 1)))))))))))
        +-

        References

        • SRFI 4 (Homogeneous numeric vector datatypes)
        • The "Byte Vectors" section of The Incomplete Scheme 48 Reference Manual available from this page.

        Copyright

        +-Copyright (C) Michael Sperber (2005). All Rights Reserved. ++
        ++

        References

        ++
          ++
        • ++ SRFI 4 (Homogeneous ++ numeric vector datatypes) ++
        • ++
        • ++ The "Byte Vectors" section of The Incomplete Scheme 48 ++ Reference Manual available from this ++ page. ++
        • ++
        ++

        Copyright

        ++

        ++ Copyright (C) Michael Sperber (2005). All Rights Reserved. ++

        +

        +-Permission is hereby granted, free of charge, to any person obtaining a +-copy of this software and associated documentation files (the "Software"), +-to deal in the Software without restriction, including without limitation +-the rights to use, copy, modify, merge, publish, distribute, sublicense, +-and/or sell copies of the Software, and to permit persons to whom the +-Software is furnished to do so, subject to the following conditions: ++ Permission is hereby granted, free of charge, to any person obtaining a copy ++ of this software and associated documentation files (the "Software"), to ++ deal in the Software without restriction, including without limitation the ++ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ sell copies of the Software, and to permit persons to whom the Software is ++ furnished to do so, subject to the following conditions: ++

        +

        +-The above copyright notice and this permission notice shall be included in +-all copies or substantial portions of the Software. ++ The above copyright notice and this permission notice shall be included in ++ all copies or substantial portions of the Software. ++

        +

        +-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +-DEALINGS IN THE SOFTWARE. +- +-


        +-
        Editor: David Van Horn
        +- ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ IN THE SOFTWARE. ++

        ++
        ++
        Editor: David Van Horn
        ++ ++ +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-69.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-69.html +index 6e4c3bb..3f99b11 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-69.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-69.html +@@ -1,69 +1,81 @@ +- +- ++ ++ + +- SRFI 69: Basic hash tables +- +- +- +- ++ ++ ++ SRFI 69: Basic hash tables ++ ++ ++ ++ ++ ++ + + + +-

        Title

        ++

        SRFI 69: Basic hash tables

        + +-SRFI 69: Basic hash tables ++

        by Panu Kalliokoski

        ++

        This copy of the SRFI 69 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-69/srfi-69.html.

        + +-

        Author

        ++

        Status

        + +-Panu Kalliokoski +- +-

        Status

        +- +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-It will remain in draft status until 2005/09/09, or as amended. To +-provide input on this SRFI, please +-mailto:srfi-69@srfi.schemers.org. +-See instructions +-here to subscribe to the list. You can access previous messages via +-the +-archive of the mailing list. +-

        ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-69 @nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        + + +-

        Abstract

        ++

        Abstract

        + +

        This SRFI defines basic hash tables. Hash tables are widely recognised + as a fundamental data structure for a wide variety of applications. A + hash table is a data structure that: +- ++

        +
        1. provides a mapping from some set of keys to some set of values + associated to those keys +-
        2. has no intrinsic order for the (key, value) associations it contains +-
        3. supports in-place modification as the primary means of setting the ++
        4. has no intrinsic order for the (key, value) associations it contains ++
        5. supports in-place modification as the primary means of setting the + contents of a hash table +-
        6. provides key lookup and destructive update in amortised constant ++
        7. provides key lookup and destructive update in amortised constant + time, provided that a good hash function is used. + +-

        This SRFI aims to accomplish these goals: +- ++ ++

        This SRFI aims to accomplish these goals: ++

        +
        1. to provide a consistent, generic and widely applicable API for hash + tables +-
        2. to improve code portability by providing a standard hash table ++
        3. to improve code portability by providing a standard hash table + facility with guaranteed behaviour +-
        4. to help the programmer by defining utility routines that account for ++
        5. to help the programmer by defining utility routines that account for + the most common situations of using hash tables. + +-

        Issues

        ++ ++ ++

        Issues

        + +

        There is no single best way to make hash tables. The tables presented + in this SRFI aim at being both conceptually simple and usable for a wide +@@ -77,7 +89,7 @@ the global environment, and specifically, to provide support for + between implementation-specific environment data types and the hash + table API presented here; however, these issues are left open. + +-

        This SRFI does not conform to the interface of maps presented in SRFI ++

        This SRFI does not conform to the interface of maps presented in SRFI + 44. Following SRFI 44 would seriously cripple the interface of hash + tables. The naming of the operations for maps in SRFI 44 goes against + common use and is unnatural. However, this SRFI has been written so +@@ -85,15 +97,16 @@ that it does not prevent a SRFI-44 API to hash tables. An + implementation supporting both SRFI 44 and this SRFI is encouraged to + provide a SRFI 44 interface to hash tables in addition to the one + presented here. ++

        + +-

        Rationale

        ++

        Rationale

        + +

        Hash tables are widely recognised as a fundamental data structure for + many kinds of computational tasks. Thus far, there is no existing + standard for Scheme hash tables; however, almost every non-minimal + Scheme implementation provides some kind of hash table functionality. + +-

        Alas, although somewhat similar, these hash table APIs have many ++

        Alas, although somewhat similar, these hash table APIs have many + differences: some trivial, like the naming of certain functions; some + complex, like revealing different aspects of the internal implementation + to the user; some coarse, like requiring keys to be of some specific +@@ -102,86 +115,89 @@ hash table in advance to get optimal performance. As a result, the + existing hash table facilities cannot be used to write portable + programs. + +-

        The primary aim of this SRFI is to establish a standard API for hash ++

        The primary aim of this SRFI is to establish a standard API for hash + tables so that portable programs can be written that make efficient use + of common hash table functionality. The SRFI resolves discrepancies + that exist between the various hash table API's with respect to naming + and semantics of hash table operations. A lot of effort has been put +-into making the API consistent, simple and generic. The SRFI also ++into making the the API consistent, simple and generic. The SRFI also + defines some of the most common utility routines that would otherwise + need to be written and rewritten for various applications. + +-

        Incorporating this SRFI as a standard feature in Scheme implementations ++

        Incorporating this SRFI as a standard feature in Scheme implementations + makes it possible to write efficient and portable programs that use hash + tables. ++

        + +-

        Specification

        ++

        Specification

        + +

        Names defined in this SRFI: +- ++

        +
        Type constructors and predicate
        +-
        make-hash-table, hash-table?, alist->hash-table ++
        make-hash-table, hash-table?, alist->hash-table + +
        Reflective queries
        +-
        hash-table-equivalence-function, hash-table-hash-function ++
        hash-table-equivalence-function, hash-table-hash-function + +
        Dealing with single elements
        +-
        hash-table-ref, hash-table-ref/default, hash-table-set!, +-hash-table-delete!, hash-table-exists?, +-hash-table-update!, hash-table-update!/default ++
        hash-table-ref, hash-table-ref/default, hash-table-set!, ++hash-table-delete!, hash-table-exists?, ++hash-table-update!, hash-table-update!/default + +
        Dealing with the whole contents
        +-
        hash-table-size, hash-table-keys, hash-table-values, +-hash-table-walk, hash-table-fold, hash-table->alist, +-hash-table-copy, hash-table-merge! ++
        hash-table-size, hash-table-keys, hash-table-values, ++hash-table-walk, hash-table-fold, hash-table->alist, ++hash-table-copy, hash-table-merge! + +
        Hashing
        +-
        hash, string-hash, string-ci-hash, hash-by-identity ++
        hash, string-hash, string-ci-hash, hash-by-identity + +-

        An implementation that does not provide hash-table-ref, ++ ++

        An implementation that does not provide hash-table-ref, + hash-table-set!, hash-table-delete!, hash-table-update!, + hash-table-exists?, and hash-table-size in amortised constant + time (when a good hash function is used), or fails to provide good hash + function definitions for hash, string-hash, string-ci-hash, + and hash-by-identity, does not conform to this SRFI. + +-

        Hash table implementations are allowed to rely on the fact that the hash ++

        Hash table implementations are allowed to rely on the fact that the hash + value of a key in hash table does not change. In most cases, modifying + a key in-place after it has been inserted into the hash table will + violate this constraint and thus leads to unspecified behaviour. ++

        + +-

        Type constructors and predicate

        +- +-

        Procedure: make-hash-table [ equal? [ hash [ args … ]]] +-→ hash-table ++

        Type constructors and predicate

        + ++

        Procedure: make-hash-table [ equal? [ hash [ args … ]]] ++→ hash-table ++

        +

        Create a new hash table with no associations. equal? is a + predicate that should accept two keys and return a boolean telling + whether they denote the same key value; it defaults to equal?. +- ++

        +

        hash is a hash function, and defaults to an appropriate hash function +-for the given equal? predicate (see section Hashing). However, ++for the given equal? predicate (see section Hashing). However, + an acceptable default is not guaranteed to be given for any equivalence + predicate coarser than equal?, except for string-ci=?.[1] The function hash must be acceptable for equal?, so if + you use coarser equivalence than equal? other than string-ci=?, + you must always provide the function hash yourself. +-
        [1] An ++
        [1] An + equivalence predicate c1 is coarser than a equivalence predicate c2 + iff there exist values x and y such that (and (c1 x y) (not (c2 x +-y))).
        +- ++y))). ++

        +

        Implementations are allowed to use the rest args for + implementation-specific extensions. Be warned, though, that using these + extensions will make your program less portable. +- +-

        Procedure: hash-table? objboolean +- ++

        ++

        Procedure: hash-table? objboolean ++

        +

        A predicate to test whether a given object obj is a hash table. The + hash table type should be disjoint from all other types, if possible. +- +-

        Procedure: alist->hash-table alist [ equal? [ hash +-[ args … ]]] → hash-table +- ++

        ++

        Procedure: alist->hash-table alist [ equal? [ hash ++[ args … ]]] → hash-table ++

        +

        Takes an association list alist and creates a hash table + hash-table which maps the car of every element in alist to the + cdr of corresponding elements in alist. equal?, hash, and +@@ -191,24 +207,26 @@ precedence over later ones. (Note: the choice of using cdr (instead + of cadr) for values tries to strike balance between the two + approaches: using cadr would render this procedure unusable for + cdr alists, but not vice versa.) +- +-

        The rest args are passed to make-hash-table and can thus be used for ++

        ++

        The rest args are passed to make-hash-table and can thus be used for + implementation-specific extensions. ++

        + +-

        Reflective queries

        ++

        Reflective queries

        + +

        Procedure: hash-table-equivalence-function hash-table +- ++

        +

        Returns the equivalence predicate used for keys of hash-table. +- ++

        +

        Procedure: hash-table-hash-function hash-table +- ++

        +

        Returns the hash function used for keys of hash-table. ++

        + +-

        Dealing with single elements

        +- +-

        Procedure: hash-table-ref hash-table key [ thunk ] → value ++

        Dealing with single elements

        + ++

        Procedure: hash-table-ref hash-table key [ thunk ] → value ++

        +

        This procedure returns the value associated to key in hash-table. + If no value is associated to key and thunk is given, it is called + with no arguments and its value is returned; if thunk is not given, an +@@ -217,28 +235,28 @@ Given a good hash function, this operation should have an (amortised) + complexity of O(1) with respect to the number of associations in + hash-table. (Note: this rules out implementation by association lists + or fixed-length hash tables.) +- +-

        Procedure: hash-table-ref/default hash-table key default → ++

        ++

        Procedure: hash-table-ref/default hash-table key default → + value +- ++

        +

        Evaluates to the same value as (hash-table-ref hash-table key (lambda + () default)). + Given a good hash function, this operation should have an (amortised) + complexity of O(1) with respect to the number of associations in + hash-table. (Note: this rules out implementation by association lists + or fixed-length hash tables.) +- +-

        Procedure: hash-table-set! hash-table key value → undefined +- ++

        ++

        Procedure: hash-table-set! hash-table key value → undefined ++

        +

        This procedure sets the value associated to key in hash-table. + The previous association (if any) is removed. + Given a good hash function, this operation should have an (amortised) + complexity of O(1) with respect to the number of associations in + hash-table. (Note: this rules out implementation by association lists + or fixed-length hash tables.) +- +-

        Procedure: hash-table-delete! hash-table key → undefined +- ++

        ++

        Procedure: hash-table-delete! hash-table key → undefined ++

        +

        This procedure removes any association to key in hash-table. It is + not an error if no association for that key exists; in this case, + nothing is done. +@@ -246,69 +264,70 @@ Given a good hash function, this operation should have an (amortised) + complexity of O(1) with respect to the number of associations in + hash-table. (Note: this rules out implementation by association lists + or fixed-length hash tables.) +- +-

        Procedure: hash-table-exists? hash-table keyboolean +- ++

        ++

        Procedure: hash-table-exists? hash-table keyboolean ++

        +

        This predicate tells whether there is any association to key in + hash-table. + Given a good hash function, this operation should have an (amortised) + complexity of O(1) with respect to the number of associations in + hash-table. (Note: this rules out implementation by association lists + or fixed-length hash tables.) +- ++

        +

        Procedure: hash-table-update! hash-table key function +-[ thunk ] → undefined +- ++[ thunk ] → undefined ++

        +

        Semantically equivalent to, but may be implemented more efficiently + than, the following code: ++

        +
        + (hash-table-set! hash-table key
        +                  (function (hash-table-ref hash-table key thunk)))
        + 
        +- +

        Procedure: hash-table-update!/default +-hash-table key function default → undefined +- ++hash-table key function default → undefined ++

        +

        Behaves as if it evaluates to (hash-table-update! hash-table key + function (lambda () default)). ++

        + +-

        Dealing with the whole contents

        +- +-

        Procedure: hash-table-size hash-tableinteger ++

        Dealing with the whole contents

        + ++

        Procedure: hash-table-size hash-tableinteger ++

        +

        Returns the number of associations in hash-table. This operation + must have a complexity of O(1) with respect to the number of + associations in hash-table. +- +-

        Procedure: hash-table-keys hash-tablelist +- ++

        ++

        Procedure: hash-table-keys hash-tablelist ++

        +

        Returns a list of keys in hash-table. The order of the keys is + unspecified. +- +-

        Procedure: hash-table-values hash-tablelist +- ++

        ++

        Procedure: hash-table-values hash-tablelist ++

        +

        Returns a list of values in hash-table. The order of the values is + unspecified, and is not guaranteed to match the order of keys in the +-result of hash-table-keys. +- +-

        Procedure: hash-table-walk hash-table proc → unspecified +- ++result of hash-table-keys. ++

        ++

        Procedure: hash-table-walk hash-table proc → unspecified ++

        +

        proc should be a function taking two arguments, a key and a value. + This procedure calls proc for each association in hash-table, giving + the key of the association as key and the value of the association as + value. The results of proc are discarded. The order in which + proc is called for the different associations is unspecified. +- ++

        +

        (Note: in some implementations, there is a procedure called + hash-table-map which does the same as this procedure. However, in + other implementations, hash-table-map does something else. In no + implementation that I know of, hash-table-map does a real functorial + map that lifts an ordinary function to the domain of hash tables. + Because of these reasons, hash-table-map is left outside this SRFI.) +- ++

        +

        Procedure: hash-table-fold hash-table f init-value +-→ final-value +- ++→ final-value ++

        +

        This procedure calls f for every association in hash-table with + three arguments: the key of the association key, the value of the + association value, and an accumulated value, val. val is +@@ -317,42 +336,44 @@ invocations of f, the return value of the previous invocation of final-value returned by hash-table-fold is the return + value of the last invocation of f. The order in which f is called + for different associations is unspecified. +- +-

        Procedure: hash-table->alist hash-tablealist +- ++

        ++

        Procedure: hash-table->alist hash-tablealist ++

        +

        Returns an association list such that the car of each element in + alist is a key in hash-table and the corresponding cdr of each + element in alist is the value associated to the key in hash-table. + The order of the elements is unspecified. +- ++

        +

        The following should always produce a hash table with the same mappings + as a hash table h: ++

        +
        + (alist->hash-table (hash-table->alist h)
        +                         (hash-table-equivalence-function h)
        +                         (hash-table-hash-function h))
        + 
        + +-

        Procedure: hash-table-copy hash-tablehash-table +- ++

        Procedure: hash-table-copy hash-tablehash-table ++

        +

        Returns a new hash table with the same equivalence predicate, hash + function and mappings as in hash-table. +- +-

        Procedure: hash-table-merge! hash-table1 hash-table2 → ++

        ++

        Procedure: hash-table-merge! hash-table1 hash-table2 → + hash-table +- ++

        +

        Adds all mappings in hash-table2 into hash-table1 and returns the + resulting hash table. This function may modify hash-table1 + destructively. ++

        + +-

        Hashing

        ++

        Hashing

        + +

        Hashing means the act of taking some value and producing a number from + the value. A hash function is a function that does this. Every + equivalence predicate e has a set of acceptable hash functions for +-that predicate; a hash function hash is acceptable iff (e obj1 +-obj2)(= (hash obj1) (hash obj2)). +- ++that predicate; a hash funtion hash is acceptable iff (e obj1 ++obj2)(= (hash obj1) (hash obj2)). ++

        +

        A hash function h is good for a equivalence predicate e if it + distributes the result numbers (hash values) for non-equal objects (by + e) as uniformly as possible over the numeric range of hash values, +@@ -360,44 +381,45 @@ especially in the case when some (non-equal) objects resemble each other + by e.g. having common subsequences. This definition is vague but should + be enough to assert that e.g. a constant function is not a good hash + function. +- +-

        When the definition of make-hash-table above talks about an ++

        ++

        When the definition of make-hash-table above talks about an + appropriate hashing function for e, it means a hashing function that + gives decent performance (for the hashing operation) while being both + acceptable and good for e. This definition, too, is intentionally + vague. +- +-

        Procedure: hash object [ bound ] → integer +- ++

        ++

        Procedure: hash object [ bound ] → integer ++

        +

        Produces a hash value for object in the range ( 0, bound (. If + bound is not given, the implementation is free to choose any bound, + given that the default bound is greater than the size of any imaginable + hash table in a normal application. (This is so that the implementation + may choose some very big value in fixnum range for the default bound.) + This hash function is acceptable for equal?. +- +-

        Procedure: string-hash string [ bound ] → integer +- +-

        The same as hash, except that the argument string must be a string. +- +-

        Procedure: string-ci-hash string [ bound ] → integer +- +-

        The same as string-hash, except that the case of characters in ++

        ++

        Procedure: string-hash string [ bound ] → integer ++

        ++

        The same as hash, except that the argument string must be a string. ++

        ++

        Procedure: string-ci-hash string [ bound ] → integer ++

        ++

        The same as string-hash, except that the case of characters in + string does not affect the hash value produced. +- +-

        Procedure: hash-by-identity object [ bound ] → integer +- +-

        The same as hash, except that this function is only guaranteed to be ++

        ++

        Procedure: hash-by-identity object [ bound ] → integer ++

        ++

        The same as hash, except that this function is only guaranteed to be + acceptable for eq?. The reason for providing this function is that + it might be implemented significantly more efficiently than hash. + Implementations are encouraged to provide this function as a builtin. ++

        + +-

        Implementation

        ++

        Implementation

        + +

        This implementation relies on SRFI-9 for distinctness of the hash table + type, and on SRFI-23 for error reporting. Otherwise, the implementation + is pure R5RS. +- ++

        +
        + 
        + (define *default-bound* (- (expt 2 29) 3))
        +@@ -657,10 +679,10 @@ is pure R5RS.
        + 
        + 
        + +-

        Copyright

        +- +-

        Copyright © Panu Kalliokoski (2005). All Rights Reserved. ++

        Copyright

        + ++

        Copyright © Panu Kalliokoski (2005). All Rights Reserved. ++

        +

        Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + Software), to deal in the Software without restriction, including +@@ -668,20 +690,20 @@ without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: +- ++

        +

        The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. +- ++

        +

        THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-


        +-
        Editor: David Van Horn
        ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++

        ++
        ++
        Editor: David Van Horn
        + Last modified: Wed Sep 14 09:54:51 EDT 2005 +- + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-7.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-7.html +index 17cbb0b..056522a 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-7.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-7.html +@@ -1,32 +1,51 @@ +- +- ++ ++ + ++ ++ + SRFI 7: Feature-based program configuration language ++ ++ ++ + + + +-

        Title

        ++

        SRFI 7: Feature-based program configuration language

        + +-SRFI-7: Feature-based program configuration language ++

        by Richard Kelsey

        ++

        This copy of the SRFI 7 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-7/srfi-7.html.

        + +-

        Author

        ++

        Status

        + +-Richard Kelsey ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-7@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Received: 1999-05-12 ++
        • Draft: 1999-05-26--1999-07-26 ++
        • Final: 1999-08-19 ++
        + +-

        Status

        +- +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

          +-
        • Received: 1999/05/12 +-
        • Draft: 1999/05/26-1999/07/26 +-
        • Final: 1999/08/19 +-
        +- +-

        Abstract

        ++

        Abstract

        + +

        +-This SRFI describes a configuration language to be used for specifing ++This SRFI describes a configuration language to be used for specifying + the set of Scheme features or extensions required to run a program. + In addition to a list of required features, a program may also contain + Scheme code to be used only when a particular feature or combination of +@@ -38,7 +57,7 @@ The configuration language is entirely distinct from Scheme; it is + neither embedded in Scheme nor includes Scheme as a subset. +

        + +-

        Rationale

        ++

        Rationale

        + +

        + The use of a separate configuration language makes it easy for +@@ -48,48 +67,38 @@ macros to determine which features, and thus which macros, are used + in the program. +

        + +-

        See SRFI 0 for a ++

        See SRFI 0 for a + rationale for the need for some kind of configuration control. +

        + +-

        Specification

        +- +- +- +- +- +- +- +- ++

        Specification

        + +-

        Syntax

        ++

        Syntax

        + +-

        +-

        ++
        +  <program> --> (program <program clause>+)
        + 
        +  <program clause>
        +-   --> (requires <feature identifier>+)
        ++   --> (requires <feature identifier>+)
        +      | (files <filename>*)
        +-     | (code <Scheme expression, definition, or syntax definition>*)
        +-     | (feature-cond <feature-cond clause>+)
        +-     | (feature-cond <feature-cond clause>* (else <program clause>+))
        ++     | (code <Scheme expression, definition, or syntax definition>*)
        ++     | (feature-cond <feature-cond clause>+)
        ++     | (feature-cond <feature-cond clause>* (else <program clause>+))
        + 
        +  <feature-cond clause>
        +    --> (<feature requirement> <program clause>+)
        + 
        +  <feature requirement>
        +    --> <feature identifier>
        +-     | (and <feature requirement>*)
        +-     | (or <feature requirement>*)
        +-     | (not <feature requirement>)
        ++     | (and <feature requirement>*)
        ++     | (or <feature requirement>*)
        ++     | (not <feature requirement>)
        + 
        +  <feature identifier>
        +    --> a symbol which is the name of a SRFI
        + 
        +-

        + +-

        Semantics

        ++

        Semantics

        +

        + The configuration language is distinct from Scheme. Given a set of + available features a <program> can be converted into a +@@ -109,7 +118,7 @@ compiles a program into an executable file. + given below. The ordering of the clauses in a <program> + determines the order of the forms in the resultant Scheme program. + +-

        In processing the REQUIRES and ++

        In processing the REQUIRES and + FEATURE-COND clauses in a <program>, + an implementation should be consistent with some fixed set of present + and absent features. An implementation may analyze a <program> +@@ -132,14 +141,16 @@ same <program>. +

        The forms in <body> are added to the program.
        + +
        (feature-cond <feature-cond clause>+)
        +-
        The meaning of a FEATURE-COND clause is that of the ++
        ++

        ++ The meaning of a FEATURE-COND clause is that of the + <program-clause>s in the first <feature-cond clause> whose + <implementation-requirement> is satisfied by the implementation. + If an ELSE clause is present it is used if and only if no preceding + clause is satisfied; a FEATURE-COND with an + ELSE clause is always satisfied. +- +-

        If no clause can be satisified the <program> cannot be evaluated in ++

        ++

        If no clause can be satisfied the <program> cannot be evaluated in + the implementation.

        + +

        +@@ -163,10 +174,11 @@ The meaning of the <implementation requirement>s is as follow + + (not x)satisfied if X is not satisfied + +- ++

        + + +-

        Implementation

        ++ ++

        Implementation

        + +

        Two implementations are provided here. The first is a + PROCESS-PROGRAM function that converts a +@@ -184,7 +196,6 @@ an (implementation-dependent) method for evaluating the forms returned by + PROCESS-PROGRAM. +

        + +-

        +

        + (define (process-program program features)
        +   (call-with-current-continuation
        +@@ -271,17 +282,17 @@ an (implementation-dependent) method for evaluating the forms returned by
        + 			  '()
        + 			  (cons next (label)))))))
        + 	      (read-files (cdr filenames)))))
        +-

        ++
        + +

        + The second implementation is a PROGRAM macro that implements + the configuration language in terms of the COND-EXPAND +-syntax of SRFI 0. ++syntax of SRFI 0. + Note that this implementation requires that LOAD use the current + evaluation environment. +

        + +-

        ++
        + (define-syntax program
        +   (syntax-rules (requires files code feature-cond)
        +     ((program)
        +@@ -302,11 +313,12 @@ evaluation environment.
        +               more ...)
        +      (begin (cond-expand (requirement (program stuff ...)) ...)
        +             (program more ...)))))
        +-

        +- +-

        Copyright

        ++
        + ++

        Copyright

        ++

        + Copyright (C) Richard Kelsey (1999). All Rights Reserved. ++

        +

        + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the +@@ -330,8 +342,8 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        +-
        Editor: Mike Sperber
        ++
        ++
        Editor: Mike Sperber
        + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-71.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-71.html +index a22c3d6..f8a75e7 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-71.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-71.html +@@ -1,46 +1,54 @@ +- +- ++ ++ + ++ ++ + SRFI 71: Extended LET-syntax for multiple values ++ ++ ++ + + + + +-

        Title

        ++

        SRFI 71: Extended LET-syntax for multiple values

        + +-Extended LET-syntax for multiple values ++

        by Sebastian Egner

        ++

        This copy of the SRFI 71 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-71/srfi-71.html.

        + +-

        Author

        ++

        Status

        + +-Sebastian Egner +- +-

        +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-To +-provide input on this SRFI, please +-mailto:srfi-71@srfi.schemers.org. +-See instructions +-here to subscribe to the list. You can access the discussion via +-the +-archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +-

        +- ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-71@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++ + + +-

        Abstract

        ++

        Abstract

        + ++

        + This SRFI is a proposal for extending let, + let*, and letrec + for receiving multiple values. +@@ -48,16 +56,19 @@ The syntactic extension is fully compatible with the existing syntax. + It is the intention that single-value bindings, + i.e. (let ((var expr)) ...), and + multiple-value binding can be mixed freely and conveniently. ++

        +

        + The most simple form of the new syntax is best explained by an example: +-

        +-

        (define (quo-rem x y)
        ++

        ++
        ++(define (quo-rem x y)
        +   (values (quotient x y) (remainder x y)))
        + 
        + (define (quo x y)
        +   (let ((q r (quo-rem x y)))
        +     q))
        + 
        ++

        + The procedure quo-rem delivers two values to + its continuation. These values are received as q + and r in the let-expression of the +@@ -65,13 +76,17 @@ procedure quo. + In other words, the syntax of let is extended such + that several variables can be specified---and these variables + receive the values delivered by the expression (quo-rem x y). ++

        +

        + The syntax of let is further extended to cases in which + a rest argument receives the list of all residual values. + Again by example, +-

        (let (((values y1 y2 . y3+) (foo x)))
        ++

        ++
        ++(let (((values y1 y2 . y3+) (foo x)))
        +    body)
        + 
        ++

        + In this example, values is a syntactic keyword + indicating the presence of multiple values to be received, + and y1, y2, and y3+, +@@ -82,6 +97,7 @@ The syntactic keyword values allows receiving + all values as in (let (((values . xs) (foo x))) body). + It also allows receiving no values at all as in + (let (((values) (for-each foo list))) body). ++

        +

        + A common application of binding multiple values is + decomposing data structures into their components. +@@ -90,9 +106,12 @@ The procedure uncons (defined below) + decomposes a pair x into its car and its cdr + and delivers them as two values to its continuation. + Then an extended let can receive these values: +-

        (let ((car-x cdr-x (uncons x)))
        ++

        ++
        ++(let ((car-x cdr-x (uncons x)))
        +   (foo car-x cdr-x))
        + 
        ++

        + Of course, for pairs this method is probably neither faster + nor clearer than using the procedures car + and cdr. +@@ -107,16 +126,19 @@ point already as both quotient and remainder are probably + computed by a common exact division algorithm. + (And often caching is used to avoid executing this + algorithm twice as often as needed.) ++

        +

        + As the last feature of this SRFI, a mechanism is specified + to store multiple values in heap-allocated data structures. +-For this purpose, values->list and values->vector ++For this purpose, values->list and values->vector + construct a list (a vector, resp.) storing all values delivered + by evaluating their argument expression. + Note that these operations cannot be procedures. ++

        + +-

        Rationale

        ++

        Rationale

        + ++

        + My original motivation for writing this SRFI is my unhappiness with + the current state of affairs in Scheme with respect to multiple values. + Multiple values are mandatory in the +@@ -124,6 +146,7 @@ Revised^5 Report on the Algorithmic + Language Scheme (R5RS), + and they are fully available in all major Scheme implementations. + Yet there is often a painful hesitation about using them. ++

        +

        + The reason for this hesitation is that multiple values are + nearly fully integrated into Scheme---but not quite. +@@ -136,6 +159,7 @@ and I understand this SRFI as a minor contribution + "placing the last corner stone". + But first a very brief history of multiple values in Scheme, + as far as relevant for this SRFI. ++

        +

        + R5RS specifies the procedures values + and call-with-values for passing any number of values +@@ -143,6 +167,7 @@ from a producer procedure to a consumer procedure. + This is the only construct in R5RS + dealing with multiple values explicitly, and it is sufficient + to implement anything that can be implemented for multiple values. ++

        +

        + However, as John David Stone observed in SRFI 8, + the mechanism exposes explicitly how multiple values are +@@ -155,6 +180,7 @@ by adding the special form + for receiving several values produced by the expression + in variables specified by <formals> and + using them in the body. ++

        +

        + The major limitation of receive is that it can only + handle a single expression, which means programs dealing with +@@ -173,17 +199,19 @@ to the list of all values delivered by x (as in S + Or is x to deliver a single value to be + bound to v (as in let)? + Refer to the +-discussion ++discussion + archive of SRFI 11 for details. + Moreover, let-values suffers from "parenthesis complexity", + despite Scheme programmers are tolerant to braces. ++

        +

        +-Eli Barzilay's Swindle library (for MzScheme) on ++Eli Barzilay's Swindle library (for MzScheme) on + the other hand redefines let to include multiple-values and internal + procedures: The syntactic keyword values indicates the + presence of multiple values, while additional parentheses (with the + syntax of <formals>) + indicate a lambda-expression as right-hand side. ++

        +

        + This SRFI follows Eli's approach, while keeping the syntax + simple (few parentheses and concepts) and adding tools for +@@ -194,6 +222,7 @@ This is achieved by extending the syntax in two different + ways (multiple left-hand sides or a syntactic keyword) + and adding operations to convert between (implicitly passed) + values and (first class) data structures. ++

        +

        + Finally, I would like to mention that Oscar Waddell et al. + describe an efficient compilation method for Scheme's +@@ -203,25 +232,30 @@ to as a basis for internal define. + I expect their compilation method (and letrec*) + and this SRFI to be fully compatible with one another, + although I have not checked this claim by way of implementation. ++

        + +-

        Specification

        ++

        Specification

        + +-The syntax of Scheme (R5RS, Section 7.1.3.) ++

        ++The syntax of Scheme (R5RS, Section 7.1.3.) + is extended by replacing the existing production: +- +-

        <binding spec> --> (<variable> <expression>)
        ++

        ++
        ++<binding spec> --> (<variable> <expression>)
        + 
        +- ++

        + by the three new productions +- +-

        <binding spec> --> ((values <variable>*) <expression>)
        ++

        ++
        ++<binding spec> --> ((values <variable>*) <expression>)
        + <binding spec> --> ((values <variable>* . <variable>) <expression>)
        + <binding spec> --> (<variable>+ <expression>)
        + 
        +- ++

        + The form (<variable>+ <expression>) is just + an abbreviation for ((values <variable>+) <expression>), + and it includes the original <binding spec> of R5RS. ++

        +

        + The first two forms are evaluated as follows: The variables are bound and + the expression is evaluated according to the enclosing construct +@@ -229,6 +263,7 @@ the expression is evaluated according to the enclosing construct + However, the expression may deliver any number of values to its continuation, + which stores these values into the variables specified, + possibly allocating a rest list in case of the . <variable> form. ++

        +

        + The number of values delivered by the expression must match the + number of values expected by the binding specification. +@@ -236,12 +271,16 @@ Otherwise an error is raised, as call-with-values would. + This implies in particular, that each binding of a named let involves + exactly one value, because this binding can also be an argument to a + lambda-expression. ++

        + +

        Standard operations

        + ++

        + The following procedures, specified in terms of standard procedures, + are added to the set of standard procedures: +-

        (define (uncons pair)
        ++

        ++
        ++(define (uncons pair)
        +   (values (car pair) (cdr pair)))
        + 
        + (define (uncons-2 list)
        +@@ -253,20 +292,22 @@ are added to the set of standard procedures:
        + (define (uncons-4 list)
        +   (values (car list) (cadr list) (caddr list) (cadddr list) (cddddr list)))
        + 
        +-(define (uncons-cons alist)
        ++(define (uncons-cons alist)
        +   (values (caar alist) (cdar alist) (cdr alist)))
        + 
        +-(define (unlist list)
        ++(define (unlist list)
        +   (apply values list))
        + 
        +-(define (unvector vector)
        +-  (apply values (vector->list vector)))
        ++(define (unvector vector)
        ++  (apply values (vector->list vector)))
        + 
        ++

        + These procedures decompose the standard concrete data structures + (pair, list, vector) and deliver the components as values. + It is an error if the argument cannot be decomposed as expected. + Note that the procedures are not necessarily implemented by + the definition given above. ++

        +

        + The preferred way of decomposing a list into the first two elements + and the rest list is (let ((x1 x2 x3+ (uncons-2 x))) body), +@@ -275,33 +316,38 @@ This is not equivalent to + (let (((values x1 x2 . x3+) (unlist x))) body) + because the latter binds x3+ to a newly allocated + copy of (cddr x). ++

        +

        + Finally, the following two macros are added to the standard macros: +- +-

        (values->list   <expression>)
        +-(values->vector <expression>)
        ++

        ++
        ++(values->list   <expression>)
        ++(values->vector <expression>)
        + 
        +- ++

        + These operation receive all values (if any) delivered by their + argument expression and return a newly allocated list (vector, resp.) + of these values. +-Note that values->list is not the same as ++Note that values->list is not the same as + list (the procedure returning the list of its arguments). ++

        + +-

        Design Rationale

        ++

        Design Rationale

        + +

        Which alternatives designs for the syntax were considered?

        + ++

        + This SRFI defines two notations for receiving several values: + Using the keyword values, + or simply listing the variables if there is at least one. + There are several alternatives for this design, + some of which were proposed during the discussion. +-(Refer in particular to msg00000, +-msg00001, and +-msg00002, +-msg00007.) ++(Refer in particular to msg00000, ++msg00001, and ++msg00002, ++msg00007.) + The alternatives considered include: ++

        +
          +
        1. Just listing the variables (no syntactic keyword at all) as in + (let ((x1 x2 expr)) body).
        2. +@@ -316,20 +362,21 @@ rest list as in (let ((x1 x2 (rest x3+) expr)) body). +
        3. Using the <formals> syntax of + R5RS as in + (let (((x1 x2 . x3+) expr)) body). +-
        4. Mimicking <formals> but with ++
        5. Mimicking <formals> but with + one level of parentheses removed as in + (let ((x1 x2 . x3+ expr)) body).
        6. +
        7. As the previous but with additional syntax for +-"no values" and "just a rest", e.g. ++"no values" and "just a rest", e.g. + (let ((! expr)) body) and + (let ((xs . expr)) body). +-
        ++ +

        + The requirements for the design are + compatibility with the existing let, + concise notation for the frequent use cases, + robustness against most common mistakes, and + full flexibility of receiving values. ++

        +

        + For the sake of compatibility, + only modifications of <binding spec> were +@@ -340,9 +387,10 @@ Concerning concise notation, by far the most convenient notation + is listing the variables. + As this notation also covers the existing syntax, it was adopted + as the basis of the extension to be specified. ++

        +

        + The listing the variables notation is limited by the fact that +-the preferred marker for a rest list (".") ++the preferred marker for a rest list (".") + cannot follow an opening parenthesis as in + (let ((. xs expr)) body), + nor that it can be followed by two syntactic elements as in +@@ -350,6 +398,7 @@ nor that it can be followed by two syntactic elements as in + Lifting these restrictions would require major modifications + in unrelated parts of the Scheme syntax, which is not an + attractive option. ++

        +

        + Another problematic aspect of the listing the variables notation + is the case of no variables at all. +@@ -360,29 +409,34 @@ it seriously harms syntactic robustness: + syntactically correct and could easily be confused with one another. + For this reason, the notation of listing the variables was + restricted to one or more variables. ++

        +

        + This leaves the problem of extending the notation in order to +-cover rest arguments and the "no values"-case. ++cover rest arguments and the "no values"-case. + This can either be done ad hoc, covering the open cases, + or by adding a general notation covering all cases. + In view of readability and uniformity (useful when code gets + processed automatically) the latter approach was chosen. + This has resulted in the design specified in this SRFI. ++

        + +-

        Why is values needed in the "zero values"-case?

        ++

        Why is values needed in the "zero values"-case?

        + ++

        + The syntax specified in this SRFI allows zero variables being + bound in a binding specification using the syntax + (let (((values) (for-each foo (bar)))) body). + An alternative is allowing (<expression>) + as a binding specification. +-(Refer to the discussion archive starting at msg00001.) ++(Refer to the discussion archive starting at msg00001.) ++

        +

        + The syntax specified in this SRFI is designed for static + detection of the most frequent types (forgotten parentheses). + For example, writing + (let ((values) (for-each foo (bar))) body) + is not a well-formed let-expression in this SRFI. ++

        +

        + In the alternative syntax, both + (let (((for-each foo (bar)))) body) +@@ -396,29 +450,36 @@ the error will probably manifest itself at the moment + (bar) fails to deliver exactly two values. + Unless it does, in which case the error must manifest itself much + further downstream from the fact that foo never got called. ++

        +

        + In order to avoid this sort of expensive typos, + the syntax proposed in this SRFI is more verbose + than it needs to be. ++

        + +

        Why not also include a syntax for procedures?

        + ++

        + This SRFI is a proposal for extending the syntax of let + etc. in order to include multiple values. + It is also desirable to extend the syntax of let + for simplifying the definition of local procedures. + (For example, as in Swindle.) + However, this SRFI does not include this feature. ++

        +

        + The reason I have chosen not restrict this SRFI to a syntax + for multiple values is simplicity. ++

        + +

        Why the names unlist etc.?

        + ++

        + An alternative naming convention for the decomposition +-operation unlist is list->values, ++operation unlist is list->values, + which is more symmetric with respect to its +-inverse operation values->list. ++inverse operation values->list. ++

        +

        + This symmetry ends, however, as soon as more complicated + data structures with other operations are involved. +@@ -426,21 +487,25 @@ Then it becomes apparent that the same data structure can + support different decomposition operations: + A double-ended queue (deque) for example supports splitting off + the head and splitting of the tail; and neither of these +-operations should be named deque->values. ++operations should be named deque->values. + The un-convention covers this in a natural way. ++

        +

        + Please also refer to the double-ended queue (deque) example +-in examples.scm to see how to ++in examples.scm to see how to + use decomposition procedures for dealing with data structures. ++

        + +

        Which decomposition operations are included?

        + ++

        + The particular set of operations specified in this SRFI + for decomposing lists represents a trade-off between limiting + the number of operations and convenience. ++

        +

        + As Al Petrofsky has pointed out during the discussion +-( ++( + msg00018) it is not sufficient to have only + unlist as this will copy the rest list. + For this reason specialized decomposition operations +@@ -448,15 +513,17 @@ for splitting off the first 1, ..., 4 elements are + provided, and a decomposition operation expecting the + first element to be a pair itself. + These appear to be the most common cases. ++

        + +-

        Implementation

        ++

        Implementation

        + ++

        + The reference implementation is written in R5RS + using hygienic macros, only. + It is not possible, however, to portably detect read access to + an uninitialized variable introduced by letrec. + The definition of the actual functionality can be found +-here. ++here. + The implementation defines macros srfi-let/*/rec etc. + in terms of r5rs-let/*/rec. + Implementors may use this to redefine (or even re-implement) +@@ -464,86 +531,93 @@ Implementors may use this to redefine (or even re-implement) + while providing implementations of r5rs-let/*/rec. + An efficient method for the latter is given in Fixing Letrec + by O. Waddell et al. ++

        +

        + R5RS: + For trying out the functionality, a complete implementation under +-R5RS can be found here. ++R5RS can be found here. + It defines r5rs-let/*/rec in terms of lambda + and redefines let/*/rec as srfi-let/*/rec. + This may not be the most efficient implementation, because many + Scheme systems handle let etc. specially and do not + reduce it into lambda ++

        +

        + PLT 208: +-The implementation found here +-uses PLT's module system for exporting ++The implementation found here ++uses PLT's module system for exporting + srfi-let/*/rec + under the name of let/*/rec, while defining + r5rs-let/*/rec as a copy of the built-in + let/*/rec. This code should be efficient. ++

        +

        + Examples using the new functionality +-can be found in examples.scm. ++can be found in examples.scm. ++

        + +-

        References

        ++

        References

        + + + + + ++ + + + ++ + + + ++ + + +- ++ + + + ++ + +
        [R5RS] +-Richard Kelsey, William Clinger, and Jonathan Rees (eds.): ++Richard Kelsey, William Clinger, and Jonathan Rees (eds.): + Revised^5 Report on the Algorithmic Language Scheme of + 20 February 1998. + Higher-Order and Symbolic Computation, Vol. 11, No. 1, September 1998. + + http://schemers.org/Documents/Standards/R5RS/. +-
        [SRFI 8] +-John David Stone: Receive: Binding to multiple values. +-http://srfi.schemers.org/srfi-8/ +-
        John David Stone: Receive: Binding to multiple values. ++http://srfi.schemers.org/srfi-8/ ++
        [SRFI 11] +-Lars T. Hansen: Syntax for receiving multiple values. +-http://srfi.schemers.org/srfi-11/ +-
        Lars T. Hansen: Syntax for receiving multiple values. ++http://srfi.schemers.org/srfi-11/ ++
        [Swindle] +-Eli Barzilay: Swindle, documentation for "base.ss" (Swindle Version 20040908.) ++[Swindle] ++Eli Barzilay: Swindle, documentation for "base.ss" (Swindle Version 20040908.) + http://www.cs.cornell.edu/eli/Swindle/base-doc.html#let +-
        [Fix] +-O. Waddell, D. Sarkar, R. K. Dybvig: ++O. Waddell, D. Sarkar, R. K. Dybvig: + Fixing Letrec: A Faithful Yet Efficient Implementation of Scheme's + Recursive Binding Construct. To appear, 2005. + http://www.cs.indiana.edu/~dyb/pubs/fixing-letrec.pdf +-
        + + +-

        Copyright

        ++

        Copyright

        ++

        + Copyright (c) 2005 Sebastian Egner. ++

        +

        + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: ++

        +

        + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ++

        +

        + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +- +-


        ++

        ++
        +
        Author: Sebastian Egner
        +-
        Editor: Mike Sperber
        ++
        Editor: Mike Sperber
        + + +-Last modified: Sun Sep 11 16:07:38 CEST 2005 ++Last modified: Sun Jan 28 13:40:16 MET 2007 + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-74.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-74.html +index 50be385..6058742 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-74.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-74.html +@@ -1,60 +1,449 @@ +- +- +- ++ ++ + +-SRFI 74: Octet-Addressed Binary Blocks ++ ++ ++ SRFI 74: Octet-Addressed Binary Blocks ++ ++ ++ + + + +-

        Title

        +- +-Octet-Addressed Binary Blocks ++

        SRFI 74: Octet-Addressed Binary Blocks

        + +-

        Authors

        ++

        by Michael Sperber

        ++

        This copy of the SRFI 74 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-74/srfi-74.html.

        + +-Michael Sperber ++

        Status

        + +

        +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-To +-provide input on this SRFI, please +-mailto:srfi-74@srfi.schemers.org. +-See instructions +-here to subscribe to the list. You can access previous messages via +-the +-archive of the mailing list. ++ This SRFI is currently in final status. Here ++ is an explanation ++ of each status that a SRFI can hold. To provide input on this SRFI, please ++ send email ++ to srfi-74@nospamsrfi.schemers.org. ++ To subscribe to the list, ++ follow these ++ instructions. You can access previous messages via the mailing ++ list archive. ++

        ++ ++

        Abstract

        ++

        ++ This SRFI defines a set of procedures for creating, accessing, and ++ manipulating octet-addressed blocks of binary data, in ++ short, blobs. The SRFI provides access primitives for fixed-length ++ integers of arbitrary size, with specified endianness, and a choice of ++ unsigned and two's complement representations. ++

        ++

        Rationale

        ++

        ++ Many applications must deal with blocks of binary data by accessing them in ++ various ways---extracting signed or unsigned numbers of various sizes. Such ++ an application can use octet vectors as ++ in SRFI 66 or any of the ++ other types of homogeneous vectors ++ in SRFI 4, but these both ++ only allow retrieving the binary data of one type. ++

        ++

        ++ This is awkward in many situations, because an application might access ++ different kinds of entities from a single binary block. Even for uniform ++ blocks, the disjointness of the various vector data types in SRFI 4 means ++ that, say, an I/O API needs to provide an army of procedures for each of ++ them in order to provide efficient access to binary data. ++

        ++

        ++ Therefore, this SRFI provides a single type for blocks of binary ++ data with multiple ways to access that data. It deals only with integers in ++ various sizes with specified endianness, because these are the most frequent ++ applications. Dealing with other kinds of binary data, such as ++ floating-point numbers or variable-size integers would be natural ++ extensions, but are left for a future SRFI. ++

        ++

        Specification

        ++

        General remarks

        ++

        ++ Blobs are objects of a new type. Conceptually, a blob represents a sequence ++ of octets. ++

        ++

        ++ Scheme systems implementing both SRFI 4 and/or SRFI 66 and this SRFI may or ++ may not use the same type for u8vector and blobs. They are encouraged to do ++ so, however. ++

        ++

        ++ As with u8vectors, the length of a blob is the number of octets it contains. ++ This number is fixed. A valid index into a blob is an exact, non-negative ++ integer. The first octet of a blob has index 0, the last octet has an index ++ one less than the length of the blob. ++

        ++

        ++ Generally, the access procedures come in different flavors according to the ++ size of the represented integer, and ++ the endianness of the ++ representation. The procedures also distinguish signed and unsigned ++ representations. The signed representations all ++ use two's ++ complement.

        ++

        ++ For procedures that have no "natural" return value, this SRFI often uses the ++ sentence: ++

        ++

        ++ The return values are unspecified. ++

        ++

        ++ This means that number of return values and the return values are ++ unspecified. However, the number of return values is such that it is ++ accepted by a continuation created by begin. Specifically, on ++ Scheme implementations where continuations created by begin ++ accept an arbitrary number of arguments (this includes most ++ implementations), it is suggested that the procedure return zero return ++ values. ++

        ++

        Interface

        ++
        ++
        (endianness big) (syntax)
        ++
        (endianness little) (syntax)
        ++
        (endianness native) (syntax)
        ++
        ++

        ++ (endianness big) and (endianness little) ++ evaluate to two distinct and unique objects representing an endianness. ++ The native endianness evaluates to the endianness of the ++ underlying machine architecture, and must be eq? to ++ either (endianness big) or (endianness little). ++

        ++
        ++
        (blob? obj)
        ++
        ++

        ++ Returns #t if obj is a blob, otherwise ++ returns #f. ++

        ++
        ++
        (make-blob k)
        ++
        ++

        ++ Returns a newly allocated blob of k octets, all of them 0. ++

        ++
        ++
        (blob-length blob)
        ++
        ++

        ++ Returns the number of octets in blob as an exact integer. ++

        ++
        ++
        (blob-u8-ref blob k)
        ++
        (blob-s8-ref blob k)
        ++
        ++

        ++ K must be a valid index of blob. ++

        ++

        ++ Blob-u8-ref returns the octet at index k ++ of blob. ++

        ++

        ++ Blob-s8-ref returns the exact integer corresponding to the ++ two's complement representation at index k ++ of blob. ++

        ++
        ++
        (blob-u8-set! blob k octet)
        ++
        (blob-s8-set! blob k byte)
        ++
        ++

        ++ K must be a valid index ++ of blob.

        Blob-u8-set! ++ stores octet in element k of blob. ++

        ++

        ++ Byte, must be an exact integer in the interval {-128, ..., ++ 127}. Blob-u8-set! stores the two's complement representation ++ of byte in element k of blob. ++

        ++

        The return values are unspecified.

        ++
        ++
        (blob-uint-ref size endianness blob k)
        ++
        (blob-sint-ref size endianness blob k)
        ++
        (blob-uint-set! size endianness blob k n)
        ++
        (blob-sint-set! size endianness blob k n)
        ++
        ++

        ++ Size must be a positive exact integer. K must be a ++ valid index of blob; so must the indices {k, ++ ..., k + size - 1}. Endianness must be an ++ endianness object. ++

        ++

        ++ Blob-uint-ref retrieves the exact integer corresponding to ++ the unsigned representation of size size and specified ++ by endianness at indices {k, ..., k ++ + size - 1}. ++

        ++

        ++ Blob-sint-ref retrieves the exact integer corresponding to ++ the two's complement representation of size size and specified ++ by endianness at indices {k, ..., k ++ + size - 1}. ++

        ++

        ++ For blob-uint-set!, n must be an exact integer in ++ the interval [0, (256^size)-1]. Blob-uint-set! ++ stores the unsigned representation of size size and specified ++ by endianness into the blob at indices {k, ++ ..., k + size - 1}. ++

        ++

        ++ For blob-uint-set!, n must be an exact integer in ++ the interval [-256^(size-1), ++ (256^(size-1))-1]. Blob-sint-set! stores the two's ++ complement representation of size size and specified ++ by endianness into the blob at indices {k, ++ ..., k + size - 1}. ++

        ++
        ++
        (blob-u16-ref endianness blob k)
        ++
        (blob-s16-ref endianness blob k)
        ++
        (blob-u16-native-ref blob k)
        ++
        (blob-s16-native-ref blob k)
        ++
        (blob-u16-set! endianness blob k n)
        ++
        (blob-s16-set! endianness blob k n)
        ++
        (blob-u16-native-set! blob k n)
        ++
        (blob-s16-native-set! blob k n)
        ++
        ++

        ++ K must be a valid index of blob; so must the ++ index k+ 1. Endianness must be an endianness ++ object. ++

        ++

        ++ These retrieve and set two-octet representations of numbers at ++ indices k and k+1, according to the endianness ++ specified by endianness. The procedures with u16 ++ in their names deal with the unsigned representation, those ++ with s16 with the two's complement representation. ++

        ++

        ++ The procedures with native in their names employ the native ++ endianness, and only work at aligned indices: k must be a ++ multiple of 2. It is an error to use them at non-aligned indices. ++

        ++
        ++
        (blob-u32-ref endianness blob k)
        ++
        (blob-s32-ref endianness blob k)
        ++
        (blob-u32-native-ref blob k)
        ++
        (blob-s32-native-ref blob k)
        ++
        (blob-u32-set! endianness blob k n)
        ++
        (blob-s32-set! endianness blob k n)
        ++
        (blob-u32-native-set! blob k n)
        ++
        (blob-s32-native-set! blob k n)
        ++
        ++

        ++ K must be a valid index of blob; so must the indices ++ {k, ..., k+ 3}. Endianness must be an ++ endianness object. ++

        ++

        ++ These retrieve and set four-octet representations of numbers at indices ++ {k, ..., k+ 3}, according to the endianness ++ specified by endianness. The procedures with u32 ++ in their names deal with the unsigned representation, those ++ with s32 with the two's complement representation. ++

        ++

        ++ The procedures with native in their names employ the native ++ endianness, and only work at aligned indices: k must be a ++ multiple of 4. It is an error to use them at non-aligned indices. ++

        ++
        ++
        (blob-u64-ref endianness blob k)
        ++
        (blob-s64-ref endianness blob k)
        ++
        (blob-u64-native-ref blob k)
        ++
        (blob-s64-native-ref blob k)
        ++
        (blob-u64-set! endianness blob k n)
        ++
        (blob-s64-set! endianness blob k n)
        ++
        (blob-u64-native-set! blob k n)
        ++
        (blob-s64-native-set! blob k n)
        ++
        ++

        ++ K must be a valid index of blob; so must the indices ++ {k, ..., k+ 7}. Endianness must be an ++ endianness object. ++

        ++

        ++ These retrieve and set eight-octet representations of numbers at indices ++ {k, ..., k+ 7}, according to the endianness ++ specified by endianness. The procedures with u64 ++ in their names deal with the unsigned representation, those ++ with s64 with the two's complement representation. ++

        ++

        ++ The procedures with native in their names employ the native ++ endianness, and only work at aligned indices: k must be a ++ multiple of 8. It is an error to use them at non-aligned indices. ++

        ++
        ++
        (blob=? blob-1 blob-2)
        ++
        ++

        ++ Returns #t if blob-1 and blob-2 are ++ equal---that is, if they have the same length and equal octets at all ++ valid indices. ++

        ++
        ++
        (blob-copy! source source-start target target-start n)
        ++
        ++

        ++ Copies data from blob source to ++ blob target. Source-start, target-start, ++ and n must be non-negative exact integers that satisfy ++

        ++

        ++ 0 <= source-start <= source-start ++ + n <= (blob-length source) ++

        ++

        ++ 0 <= target-start <= target-start ++ + n <= (blob-length target) ++

        ++

        ++ This copies the octets from source at indices ++ [source-start, source-start + n) to ++ consecutive indices in target starting ++ at target-index. ++

        ++

        ++ This must work even if the memory regions for the source and the target ++ overlap, i.e., the octets at the target location after the copy must be ++ equal to the octets at the source location before the copy. ++

        ++

        ++ The return values are unspecified. ++

        ++
        ++
        (blob-copy blob)
        ++
        ++

        ++ Returns a newly allocated copy of blob blob. ++

        ++
        ++
        (blob->u8-list blob)
        ++
        (u8-list->blob blob)
        ++
        ++

        ++ blob->u8-listreturns a newly allocated list of the octets ++ of blob in the same ++ order. ++

        ++
        ++
        ++

        ++ U8-list->blob returns a newly allocated blob whose ++ elements are the elements of list octets, which must all be ++ octets, in the same order. Analogous to list->vector. ++

        ++
        ++
        (blob->uint-list size endianness blob)
        ++
        (blob->sint-list size endianness blob)
        ++
        (uint-list->blob size endianness list)
        ++
        (sint-list->blob size endianness list)
        ++
        ++

        ++ Size must be a positive exact integer. Endianness ++ must be an endianness object. ++

        ++

        ++ These convert between lists of integers and their consecutive ++ representations according to size and endianness in ++ blobs in the same way ++ as blob->u8-list, blob->s8-list, ++ u8-list->blob, and s8-list->blob do for ++ one-octet representations. ++

        ++
        ++
        + ++

        Reference Implementation

        ++

        ++ This reference implementation makes use ++ of SRFI 23 (Error reporting ++ mechanism), SRFI 26 ++ (Notation for Specializing Parameters without ++ Currying), SRFI 60 (Integers ++ as Bits), and SRFI 66 (Octet ++ Vectors). ++

        ++

        Examples

        ++

        ++ The test suite doubles as a source of examples. +

        ++

        References

        + +-

        Abstract

        This SRFI defines a set of procedures for creating, accessing, and manipulating octet-addressed blocks of binary data, in short, blobs. The SRFI provides access primitives for fixed-length integers of arbitrary size, with specified endianness, and a choice of unsigned and two's complement representations.

        Rationale

        Many applications must deal with blocks of binary data by accessing them in various ways---extracting signed or unsigned numbers of various sizes. Such an application can use octet vectors as in SRFI 66 or any of the other types of homogeneous vectors in SRFI 4, but these both only allow retrieving the binary data of one type.

        This is awkward in many situations, because an application might access different kinds of entities from a single binary block. Even for uniform blocks, the disjointness of the various vector data types in SRFI 4 means that, say, an I/O API needs to provide an army of procedures for each of them in order to provide efficient access to binary data.

        Therefore, this SRFI provides a single type for blocks of binary data with multiple ways to access that data. It deals only with integers in various sizes with specified endianness, because these are the most frequent applications. Dealing with other kinds of binary data, such as floating-point numbers or variable-size integers would be natural extensions, but are left for a future SRFI.

        Specification

        General remarks

        Blobs are objects of a new type. Conceptually, a blob represents a sequence of octets.

        Scheme systems implementing both SRFI 4 and/or SRFI 66 and this SRFI may or may not use the same type for u8vector and blobs. They are encouraged to do so, however.

        As with u8vectors, the length of a blob is the number of octets it contains. This number is fixed. A valid index into a blob is an exact, non-negative integer. The first octet of a blob has index 0, the last octet has an index one less than the length of the blob.

        Generally, the access procedures come in different flavors according to the size of the represented integer, and the endianness of the representation. The procedures also distinguish signed and unsigned representations. The signed representations all use two's complement.

        For procedures that have no "natural" return value, this SRFI often uses the sentence

        The return values are unspecified.

        This means that number of return values and the return values are unspecified. However, the number of return values is such that it is accepted by a continuation created by begin. Specifically, on Scheme implementations where continuations created by begin accept an arbitrary number of arguments (this includes most implementations), it is suggested that the procedure return zero return values.

        Interface

        (endianness big) (syntax)
        (endianness little) (syntax)
        (endianness native) (syntax)

        (endianness big) and (endianness little) evaluate to two distinct and unique objects representing an endianness. The native endianness evaluates to the endianness of the underlying machine architecture, and must be eq? to either (endianness big) or (endianness little).

        (blob? obj)

        Returns #t if obj is a blob, otherwise returns #f.

        (make-blob k)

        Returns a newly allocated blob of k octets, all of them 0.

        (blob-length blob)

        Returns the number of octets in blob as an exact integer.

        (blob-u8-ref blob k)
        (blob-s8-ref blob k)

        K must be a valid index of blob.

        Blob-u8-ref returns the octet at index k of blob.

        Blob-s8-ref returns the exact integer corresponding to the two's complement representation at index k of blob.

        (blob-u8-set! blob k octet)
        (blob-s8-set! blob k byte)

        K must be a valid index of blob.

        Blob-u8-set! stores octet in element k of blob.

        Byte, must be an exact integer in the interval {-128, ..., 127}. Blob-u8-set! stores the two's complement representation of byte in element k of blob.

        The return values are unspecified.

        (blob-uint-ref size endianness blob k)
        (blob-sint-ref size endianness blob k)
        (blob-uint-set! size endianness blob k n)
        (blob-sint-set! size endianness blob k n)

        Size must be a positive exact integer. K must be a valid index of blob; so must the indices {k, ..., k + size - 1}. Endianness must be an endianness object.

        Blob-uint-ref retrieves the exact integer corresponding to the unsigned representation of size size and specified by endianness at indices {k, ..., k + size - 1}.

        Blob-sint-ref retrieves the exact integer corresponding to the two's complement representation of size size and specified by endianness at indices {k, ..., k + size - 1}.

        For blob-uint-set!, n must be an exact integer in the interval [0, (256^size)-1]. Blob-uint-set! stores the unsigned representation of size size and specified by endianness into the blob at indices {k, ..., k + size - 1}.

        For blob-uint-set!, n must be an exact integer in the interval [-256^(size-1), (256^(size-1))-1]. Blob-sint-set! stores the two's complement representation of size size and specified by endianness into the blob at indices {k, ..., k + size - 1}.

        (blob-u16-ref endianness blob k)
        (blob-s16-ref endianness blob k)
        (blob-u16-native-ref blob k)
        (blob-s16-native-ref blob k)
        (blob-u16-set! endianness blob k n)
        (blob-s16-set! endianness blob k n)
        (blob-u16-native-set! blob k n)
        (blob-s16-native-set! blob k n)

        K must be a valid index of blob; so must the index k+ 1. Endianness must be an endianness object.

        These retrieve and set two-octet representations of numbers at indices k and k+1, according to the endianness specified by endianness. The procedures with u16 in their names deal with the unsigned representation, those with s16 with the two's complement representation.

        The procedures with native in their names employ the native endianness, and only work at aligned indices: k must be a multiple of 2. It is an error to use them at non-aligned indices.

        (blob-u32-ref endianness blob k)
        (blob-s32-ref endianness blob k)
        (blob-u32-native-ref blob k)
        (blob-s32-native-ref blob k)
        (blob-u32-set! endianness blob k n)
        (blob-s32-set! endianness blob k n)
        (blob-u32-native-set! blob k n)
        (blob-s32-native-set! blob k n)

        K must be a valid index of blob; so must the indices {k, ..., k+ 3}. Endianness must be an endianness object.

        These retrieve and set four-octet representations of numbers at indices {k, ..., k+ 3}, according to the endianness specified by endianness. The procedures with u32 in their names deal with the unsigned representation, those with s32 with the two's complement representation.

        The procedures with native in their names employ the native endianness, and only work at aligned indices: k must be a multiple of 4. It is an error to use them at non-aligned indices.

        (blob-u64-ref endianness blob k)
        (blob-s64-ref endianness blob k)
        (blob-u64-native-ref blob k)
        (blob-s64-native-ref blob k)
        (blob-u64-set! endianness blob k n)
        (blob-s64-set! endianness blob k n)
        (blob-u64-native-set! blob k n)
        (blob-s64-native-set! blob k n)

        K must be a valid index of blob; so must the indices {k, ..., k+ 7}. Endianness must be an endianness object.

        These retrieve and set eight-octet representations of numbers at indices {k, ..., k+ 7}, according to the endianness specified by endianness. The procedures with u64 in their names deal with the unsigned representation, those with s64 with the two's complement representation.

        The procedures with native in their names employ the native endianness, and only work at aligned indices: k must be a multiple of 8. It is an error to use them at non-aligned indices.

        (blob=? blob-1 blob-2)

        Returns #t if blob-1 and blob-2 are equal---that is, if they have the same length and equal octets at all valid indices.

        (blob-copy! source source-start target target-start n)

        Copies data from blob source to blob target. Source-start, target-start, and n must be non-negative exact integers that satisfy

        0 <= source-start <= source-start + n <= (blob-length source)

        0 <= target-start <= target-start + n <= (blob-length target)

        This copies the octets from source at indices [source-start, source-start + n) to consecutive indices in target starting at target-index.

        This must work even if the memory regions for the source and the target overlap, i.e., the octets at the target location after the copy must be equal to the octets at the source location before the copy.

        The return values are unspecified.

        (blob-copy blob)

        Returns a newly allocated copy of blob blob.

        (blob->u8-list blob)
        (u8-list->blob blob)

        blob->u8-listreturns a newly allocated list of the octets of blob in the same order.

        U8-list->blob returns a newly allocated blob whose elements are the elements of list octets, which must all be octets, in the same order. Analogous to list->vector.

        (blob->uint-list size endianness blob)
        (blob->sint-list size endianness blob)
        (uint-list->blob size endianness list)
        (sint-list->blob size endianness list)

        Size must be a positive exact integer. Endianness must be an endianness object.

        These convert between lists of integers and their consecutive representations according to size and endianness in blobs in the same way as blob->u8-list, blob->s8-list, u8-list->blob, and s8-list->blob do for one-octet representations.

        Reference Implementation

        This reference implementation makes use of SRFI 23 (Error reporting mechanism), SRFI 26 (Notation for Specializing Parameters without Currying), SRFI 60 (Integers as Bits), and SRFI 66 (Octet Vectors) .

        Examples

        The test suite doubles as a source of examples.

        References

        Copyright

        +-Copyright (C) Michael Sperber (2005). All Rights Reserved. +-

        +-Permission is hereby granted, free of charge, to any person obtaining a +-copy of this software and associated documentation files (the "Software"), +-to deal in the Software without restriction, including without limitation +-the rights to use, copy, modify, merge, publish, distribute, sublicense, +-and/or sell copies of the Software, and to permit persons to whom the +-Software is furnished to do so, subject to the following conditions: +-

        +-The above copyright notice and this permission notice shall be included in +-all copies or substantial portions of the Software. +-

        +-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +-DEALINGS IN THE SOFTWARE. +- +-


        +-
        Editor: David Van Horn
        +- ++

        Copyright

        ++

        ++ Copyright (C) Michael Sperber (2005). All Rights Reserved. ++

        ++

        ++ Permission is hereby granted, free of charge, to any person obtaining a copy ++ of this software and associated documentation files (the "Software"), to ++ deal in the Software without restriction, including without limitation the ++ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++ sell copies of the Software, and to permit persons to whom the Software is ++ furnished to do so, subject to the following conditions: ++

        ++

        ++ The above copyright notice and this permission notice shall be included in ++ all copies or substantial portions of the Software. ++

        ++

        ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ IN THE SOFTWARE. ++

        ++
        ++
        Editor: David Van Horn
        ++ ++ +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-78.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-78.html +index 4267157..270196e 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-78.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-78.html +@@ -1,102 +1,122 @@ +- +- ++ ++ + ++ ++ + SRFI 78: Lightweight testing ++ ++ ++ + + + + +-

        Title

        +- +-Lightweight testing +- +-

        Author

        +- +-Sebastian Egner +- +-

        Status

        +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +- +-To provide input on this SRFI, please mail to +-<srfi-78@srfi.schemers.org>. See instructions here to subscribe to +-the list. You can access previous messages via the archive of the mailing list. +- +- +-

          +-
        • Received: 2005/10/25
        • +-
        • Draft: 2005/11/11 - 2006/01/10
        • +-
        • Draft extended: 2006/01/17 - 2006/01/31
        • +-
        • Revised: 2006/01/18
        • +-
        • Revised: 2006/02/08
        • +-
        • Final: 2006/03/06
        • +-
        +- +-

        Abstract

        +- ++

        SRFI 78: Lightweight testing

        ++ ++

        by Sebastian Egner

        ++

        This copy of the SRFI 78 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-78/srfi-78.html.

        ++ ++

        Status

        ++ ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-78@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Received: 2005-10-25
        • ++
        • Draft: 2005-11-11--2006-01-10
        • ++
        • Draft extended: 2006-01-17--2006-01-31
        • ++
        • Revised: 2006-01-18
        • ++
        • Revised: 2006-02-08
        • ++
        • Final: 2006-03-06
        • ++
        • Revised to fix errata:
            ++
          • 2019-10-25 (Fix broken links.)
        • ++
        ++ ++

        Abstract

        ++

        + A simple mechanism is defined for testing Scheme programs. + As a most primitive example, the expression +- +-

           (check (+ 1 1) => 3)
        +-
        +- +-evaluates the expression (+ 1 1) and compares the result ++

        ++
        ++   (check (+ 1 1) => 3)
        ++
        ++

        ++evaluates the expression (+ 1 1) and compares the result + with the expected result 3 provided after the syntactic +-keyword =>. Then the outcome of this comparison is reported ++keyword =>. Then the outcome of this comparison is reported + in human-readable form by printing a message of the form +- +-

           (+ 1 1) => 2 ; *** failed ***
        ++

        ++
        ++   (+ 1 1) => 2 ; *** failed ***
        +    ; expected result: 3
        +-
        +- ++
        ++

        + Moreover, the outcome of any executed check is recorded + in a global state counting the number of correct and failed + checks and storing the first failed check. At the end of a + file, or at any other point, the user can print a summary +-using check-report. ++using check-report. ++

        +

        + In addition to the simple test above, it is also possible + to execute a parametric sequence of checks. Syntactically, + this takes the form of an eager comprehension in the sense +-of SRFI 42 [5]. For example, +- +-

           (check-ec (:range e 100)
        ++of SRFI 42 [5]. For example,
        ++

        ++
        ++   (check-ec (:range e 100)
        +              (:let x (expt 2.0 e)) 
        +-             (= (+ x 1) x) => #f (e x))
        +-
        +- +-This statement runs the variable e through {0..99} and +-for each binding defines x as (expt 2.0 e). Then it is +-checked if (+ x 1) is equal to x, and it is expected that +-this is not the case (i.e. expected value is #f). The +-trailing (e x) tells the reporting mechanism to print +-the values of both e and x in case of a failed check. ++ (= (+ x 1) x) => #f (e x)) ++
        ++

        ++This statement runs the variable e through {0..99} and ++for each binding defines x as (expt 2.0 e). Then it is ++checked if (+ x 1) is equal to x, and it is expected that ++this is not the case (i.e. expected value is #f). The ++trailing (e x) tells the reporting mechanism to print ++the values of both e and x in case of a failed check. + The output could look like this: +- +-

           (let ((e 53) (x 9007199254740992.0)) (= (+ x 1) x)) => #t ; *** failed ***
        ++

        ++
        ++   (let ((e 53) (x 9007199254740992.0)) (= (+ x 1) x)) => #t ; *** failed ***
        +     ; expected result: #f
        +-
        +- +-The specification of bindings to report, (e x) in the ++
        ++

        ++The specification of bindings to report, (e x) in the + example, is optional but very informative. +- ++

        ++

        + Other features of this SRFI are: +-

          +-
        • A way to specify a different equality predicate (default is equal?).
        • +-
        • Controlling the amount of reporting being printed.
        • +-
        • Switching off the execution and reporting of checks entriely.
        • +-
        • Retrieving a boolean if all checks have been executed and passed.
        • +-
        +- +-

        Rationale

        ++

        ++
          ++
        • A way to specify a different equality predicate (default is equal?).
        • ++
        • Controlling the amount of reporting being printed.
        • ++
        • Switching off the execution and reporting of checks entriely.
        • ++
        • Retrieving a boolean if all checks have been executed and passed.
        • ++
        ++ ++

        Rationale

        ++

        + The mechanism defined in this SRFI should be available in + every Scheme system because it has already proven useful + for interactive development---of SRFIs. ++

        +

        + Although it is extremely straight-forward, the origin of the + particular mechanism described here is the 'examples.scm' file +@@ -104,209 +124,234 @@ accompanying the reference implementation of SRFI 42 [5]. + The same mechanism has been reimplemented for the reference + implementation of SRFI 67, and a simplified version is yet + again found in the reference implementation of SRFI 77. ++

        +

        + The mechanism in this SRFI does not replace more sophisticated + approaches to unit testing, like SRFI 64 [1] or SchemeUnit [2]. + These systems provide more control of the testing, separate + the definition of a test, its execution, and its reports, and + provide several other features. ++

        +

        + Neil Van Dyke's Testeez library [3] is very close in spirit + to this SRFI. In Testeez, tests are disabled by (re-)defining a + macro. The advantage of this method is that the code for the + test cases can be removed entirely, and hence even the dependency + on the Testeez library. This SRFI on the other hand, uses a +-Scheme conditional (COND, IF) to prevent execution of the ++Scheme conditional (COND, IF) to prevent execution of the + testing code. This method is more dynamic but retains dead + testing code, unless a compiler and a module system are used + to apply constant folding and dead code elimination. The only + major addition in SRFI over Testeez is the comprehension for + formulating parametric tests. ++

        +

        + Design considerations for this SRFI include the following: +-

          +-
        • Reporting is human-readable and as specific as possible, ++

          ++
            ++
          • Reporting is human-readable and as specific as possible, + i.e. not just "assertion failed" but the expression with + actual and expected value, and if possibly the relevant +- part of the bindings environment.
          • +-
          • An effort is made to print closed Scheme expressions, i.e. ++ part of the bindings environment.
          • ++
          • An effort is made to print closed Scheme expressions, i.e. + expressions that can directly be copy/pasted into a REPL +- for further analysis (e.g. the let expression in the abstract).
          • +-
          • By default the checks report both correct and failed checks. ++ for further analysis (e.g. the let expression in the abstract).
          • ++
          • By default the checks report both correct and failed checks. + However, it is possible to reduce the output---or even to + switch off the execution of checks. It has turned out useful + to be able to run only some subset checks for the features + currently under development. This can be done by changing +- the reporting mode between different sections.
          • +-
          • The global state (correct/failed count) is not made available ++ the reporting mode between differnt sections.
          • ++
          • The global state (correct/failed count) is not made available + to the user program. This reduces the dependencies between +- different checks because it is not possible to use the state.
          • +-
          • Ocassionally, it is useful to check that a certain expression +- does not yield an ordinary result but raises an error. However, ++ different checks because it is not possible to use the state.
          • ++
          • Ocassionally, it is useful to check that a certain expression ++ does not yield an ordinary result but raises an error. However, + R5RS [4] does not specify the mechanism by which this occurs + (e.g. raising exception, breaking into a REPL, aborting the + program, etc.). For this reason, this SRFI is restricted to +- the case that the checked expressions evaluate normally.
          • +-
          • Though usually I am very much in favor of strictly prefix ++ the case that the checked expressions evaluate normally.
          • ++
          • Though usually I am very much in favor of strictly prefix + syntax, for this SRFI I make an exception because the +- infix "=>" syntax is widely used and intuitive.
          • +-
          ++ infix "=>" syntax is widely used and intuitive.
        • ++
        + +-

        Specification

        ++

        Specification

        + +-
        +-
        +-(check <expr> (=> <equal>) <expected>)         MACRO
        ++
        ++
        ++(check <expr> (=> <equal>) <expected>)         MACRO
        + (check <expr> => <expected>) +-
        +-
        +- evaluates <expr> and compares the value to the value +- of <expected> using the predicate <equal>, which is +- equal? when omitted. Then a report is printed according ++
        ++
        ++ evaluates <expr> and compares the value to the value ++ of <expected> using the predicate <equal>, which is ++ equal? when omitted. Then a report is printed according + to the current mode setting (see below) and the outcome +- is recorded in a global state to be used in check-report. +- The precise order of evaluation is that first <equal> +- and <expected> are evaluated (in unspecified order) and +- then <expr> is evaluated.
        +- Example: (check (+ 1 1) => 2) +-
        +-
        +- +-
        +-
        +-(check-ec <qualifier>* <expr> (=> <equal>) <expected> (<argument>*))         MACRO
        +-(check-ec <qualifier>
        * <expr> => <expected> (<argument>*))
        +-(check-ec <qualifier>
        * <expr> (=> <equal>) <expected>)
        +-(check-ec <qualifier>
        * <expr> => <expected>) +-
        +-
        +- an eager comprehension for executing a parametric sequence of checks.

        +- Enumerates the sequence of bindings specified by <qualifier>*. +- For each binding evaluates <equal> and <expected> in unspecified +- order. Then evalues <expr> and compares the value obtained to the +- value of <expected> using the value of <equal> as predicate, which +- is equal? when omitted. ++ is recorded in a global state to be used in check-report. ++ The precise order of evaluation is that first <equal> ++ and <expected> are evaluated (in unspecified order) and ++ then <expr> is evaluated.
        ++ Example: (check (+ 1 1) => 2) ++

        ++
        ++ ++
        ++
        ++(check-ec <qualifier>* <expr> (=> <equal>) <expected> (<argument>*))         MACRO
        ++(check-ec <qualifier>
        * <expr> => <expected> (<argument>*))
        ++(check-ec <qualifier>
        * <expr> (=> <equal>) <expected>)
        ++(check-ec <qualifier>
        * <expr> => <expected>) ++
        ++
        ++

        ++ an eager comprehension for executing a parametric sequence of checks. ++

        ++

        ++ Enumerates the sequence of bindings specified by <qualifier>*. ++ For each binding evaluates <equal> and <expected> in unspecified ++ order. Then evalues <expr> and compares the value obtained to the ++ value of <expected> using the value of <equal> as predicate, which ++ is equal? when omitted. + The comprehension stops after the first failed check, if there + is any. Then a report is printed according to the current mode + setting (see below) and the outcome is recorded in a global state +- to be used in check-report. The entire check-ec counts as a single +- check.

        +- In case the check fails <argument>* is used for constructing an +- informative message with the argument values. Use <argument>* to +- list the relevant free variables of <expr> (see examples) that you +- want to have printed.

        +- A <qualifier> is any qualifier of an eager comprehension as +- specified in SRFI 42 [5].

        +- ++ to be used in check-report. The entire check-ec counts as a single ++ check.

        ++ In case the check fails <argument>* is used for constructing an ++ informative message with the argument values. Use <argument>* to ++ list the relevant free variables of <expr> (see examples) that you ++ want to have printed.

        ++ A <qualifier> is any qualifier of an eager comprehension as ++ specified in SRFI 42 [5]. ++

        ++

        + Examples: +-

             (check-ec (: e 100) (positive? (expt 2 e)) => #t (e)) ; fails on fixnums
        ++

        ++
        ++     (check-ec (: e 100) (positive? (expt 2 e)) => #t (e)) ; fails on fixnums
        +      (check-ec (: e 100) (:let x (expt 2.0 e)) (= (+ x 1) x) => #f (x)) ; fails
        +      (check-ec (: x 10) (: y 10) (: z 10)
        +                (* x (+ y z)) => (+ (* x y) (* x z))
        +                (x y z)) ; passes with 10^3 cases checked
        +-   
        +-
        +-
        ++
        ++ ++ ++ + +-
        +-
        +-(check-report)         PROCEDURE +-
        +-
        ++
        ++
        ++(check-report)         PROCEDURE ++
        ++
        ++

        + prints a summary and the first failed check, if there is any, + depending on the current mode settings. +-

        +-
        +- +-
        +-
        +-(check-set-mode! mode)         PROCEDURE +-
        +-
        ++

        ++
        ++
        ++ ++
        ++
        ++(check-set-mode! mode)         PROCEDURE ++
        ++
        ++

        + sets the current mode to mode, which must be a symbol in +- '(off summary report-failed report), default is 'report. ++ '(off summary report-failed report), default is 'report. + Note that you can change the mode at any time, and that check, +- check-ec and check-report use the current value. +-

        +- The mode symbols have the following meaning:
        +- off: do not execute any of the checks,
        +- summary: print only summary in (check-report) and nothing else,
        +- report-failed: report failed checks when they happen, and in summary,
        +- report: report every example executed.
        +-

        +-
        +- +-
        +-
        +-(check-reset!)         PROCEDURE +-
        +-
        ++ check-ec and check-report use the current value. ++

        ++

        ++ The mode symbols have the following meaning:
        ++ off: do not execute any of the checks,
        ++ summary: print only summary in (check-report) and nothing else,
        ++ report-failed: report failed checks when they happen, and in summary,
        ++ report: report every example executed.
        ++

        ++
        ++
        ++ ++ ++
        ++
        ++(check-reset!)         PROCEDURE ++
        ++
        + resets the global state (counters of correct/failed examples) + to the state immediately after loading the module for the + first time, i.e. no checks have been executed. +-
        +-
        +- +-
        +-
        +-(check-passed? expected-total-count)         PROCEDURE +-
        +-
        +- #t if there were no failed checks and expected-total-count +- correct checks, #f otherwise.

        ++

        ++
        ++ ++
        ++
        ++(check-passed? expected-total-count)         PROCEDURE ++
        ++
        ++

        ++ #t if there were no failed checks and expected-total-count ++ correct checks, #f otherwise. ++

        ++

        + Rationale: This procedure can be used in automatized + tests by terminating a test program with the statement +- (exit (if (check-passed? n) 0 1)). +-

        +-
        +- ++ (exit (if (check-passed? n) 0 1)). ++

        ++
        ++
        + +-

        Implementation

        + +-check.scm: ++

        Implementation

        ++

        ++check.scm: + implementation in R5RS + SRFI 23 (error) + SRFI 42 (comprehensions); +- tested under PLT 208p1 and Scheme 48 1.3.
        +- +-examples.scm: ++ tested under PLT 208p1 and Scheme 48 1.3.
        ++

        ++

        ++examples.scm: + a few examples. ++

        ++

        References

        + +-

        References

        +- +- + ++

        Copyright

        ++

        + Copyright (C) Sebastian Egner (2005-2006). All Rights Reserved. ++

        +

        + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: ++

        +

        + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ++

        +

        + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-

        +-


        ++

        ++
        +
        Author: srfi-78@sebastian-egner.net
        +-
        Editors: srfi-editors@srfi.schemers.org
        +- ++
        Editor: David Van Horn
        ++ + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-8.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-8.html +index 38b7340..ed3e26e 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-8.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-8.html +@@ -1,41 +1,58 @@ +- +- ++ ++ + +-SRFI 8: RECEIVE: Binding to multiple values ++ ++ ++ SRFI 8: RECEIVE: Binding to multiple values ++ ++ ++ + + + +-

        Title

        ++

        SRFI 8: receive: Binding to multiple values

        + +-SRFI 8: receive: Binding to multiple values +- +-

        Author

        +- +-John David Stone +- +-

        ++

        by John David Stone
        + Department of Mathematics and Computer Science, Grinnell College, Grinnell, Iowa 50112, + email. +

        ++

        This copy of the SRFI 8 specification document ++is distributed as part of the Racket package ++srfi-doc.

        The canonical source of this document is ++https://srfi.schemers.org/srfi-8/srfi-8.html.

        + +-

        Status

        ++

        Status

        + +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

          +-
        • Received: 1999/05/27 +-
        • Draft: 1999/07/01-1999/08/30 +-
        • Final: 1999/08/30 +-
        ++

        This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-8@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

        ++
          ++
        • Received: 1999-05-27 ++
        • Draft: 1999-07-01--1999-08-30 ++
        • Final: 1999-08-30 ++
        + +-

        Related SRFIs

        ++

        Related SRFIs

        + +

        + The syntax proposed in this SRFI is used in the reference implementation of + SRFI-1, ``List library.'' +

        + +-

        Abstract

        ++

        Abstract

        + +

        + The only mechanism that R5RS provides for binding identifiers to +@@ -44,7 +61,7 @@ the values of a multiple-valued expression is the primitive + readable syntax for creating such bindings. +

        + +-

        Rationale

        ++

        Rationale

        + +

        + Although R5RS supports multiple-valued expressions, it provides +@@ -116,8 +133,8 @@ established from a ``body'' in which they are used makes it easier to + follow the code. +

        + +-

        Specification

        +- ++

        Specification

        ++ +

        + (receive <formals> <expression> + <body>)     library syntax +@@ -134,7 +151,7 @@ forms: + (<variable1> ... + <variablen>): The environment in which + the receive-expression is evaluated is extended by binding +-<variable1>, ..., ++<variable1>, ..., + <variablen> to fresh locations. The + <expression> is evaluated, and its values are stored into those + locations. (It is an error if <expression> does not have exactly +@@ -154,7 +171,7 @@ stored in the location bound to <variable>. + <variablen> . <variablen + + 1>): The environment in which + the receive-expression is evaluated is extended by binding +-<variable1>, ..., ++<variable1>, ..., + <variablen + 1> to fresh locations. The + <expression> is evaluated. Its first n values are stored into + the locations bound to <variable1> ... +@@ -172,7 +189,7 @@ the extended environment. The results of the last expression in the body + are the values of the receive-expression. +

        + +-

        Reference implementation

        ++

        Reference implementation

        + +
        + 
        +@@ -184,7 +201,7 @@ are the values of the receive-expression.
        + 
        + 
        + +-
        ++
        + +

        + Copyright (C) John David Stone (1999). All Rights Reserved. +@@ -213,9 +230,9 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

        + +-
        ++
        + +-
        Editor: Mike Sperber
        ++
        Editor: Mike Sperber
        + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-86.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-86.html +index 39255f2..414fc56 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-86.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-86.html +@@ -1,41 +1,51 @@ +- +-SRFI 86: MU and NU simulating VALUES & CALL-WITH-VALUES, and their related LET-syntax +- +-

        Title

        +- +-MU and NU simulating VALUES & CALL-WITH-VALUES, and their related LET-syntax +- +-

        Author

        +- +-Joo ChurlSoo +- +-

        Status

        +- +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-To +-provide input on this SRFI, please +-mailto:srfi minus 86 at srfi dot schemers dot org. +-See instructions +-here to subscribe to the list. You can access the discussion via +-the +-archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +-

        +-

          +-
        • Received: 2006/04/03
        • +-
        • Revised: 2006/05/08
        • +-
        • Revised: 2006/05/22
        • +-
        • Revised: 2006/06/20
        • +-
        • Final: 2006/06/20
        • +-
        • Draft: 2006/04/04 - 2006/06/01
        • ++ ++ ++ ++ ++ ++ SRFI 86: MU and NU simulating VALUES & CALL-WITH-VALUES, and their related LET-syntax ++ ++ ++ ++ ++ ++ ++

          SRFI 86: MU and NU simulating VALUES & CALL-WITH-VALUES, and their related LET-syntax

          ++ ++

          by Joo ChurlSoo

          ++

          This copy of the SRFI 86 specification document ++is distributed as part of the Racket package ++srfi-doc.

          The canonical source of this document is ++https://srfi.schemers.org/srfi-86/srfi-86.html.

          ++ ++

          Status

          ++ ++

          This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-86@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

          ++ + +-

          Abstract

          ++

          Abstract

          + +

          + Unlike the values/call-with-values mechanism of +@@ -66,7 +76,7 @@ multiple values. In addition, they have several new binding forms for + useful functions such as escape, recursion, etc. +

          + +-

          Rationale

          ++

          Rationale

          + +

          + It is impossible to bind the evaluated result of values +@@ -79,7 +89,8 @@ consumer procedure of call-with-values. The following are examples + show the differences. +

          + +-
          (define v (values 1 2 3))		=> error
          ++
          ++(define v (values 1 2 3))		=> error
          + (define v (lambda () (values 1 2 3)))	=> (lambda () (values 1 2 3))
          + (define m (mu 1 2 3))			=> (lambda (f) (f 1 2 3))
          + (define a (apply values 1 '(2 3)))	=> error
          +@@ -107,21 +118,24 @@ best explained by simple examples.
          + 
          + 

          In SRFI 11:

          + +-
          (let-values ((a (values 1 2)) ((b c) (values 3 4)))
          ++
          ++(let-values ((a (values 1 2)) ((b c) (values 3 4)))
          + 	    (list a b c))
          + => ((1 2) 3 4)
          + 
          + +

          In SRFI 71:

          + +-
          (srfi-let (((values . a) (values 1 2)) ((values b c) (values 3 4)))
          ++
          ++(srfi-let (((values . a) (values 1 2)) ((values b c) (values 3 4)))
          + 	  (list a b c))
          + => ((1 2) 3 4)
          + 
          + +

          In this SRFI:

          + +-
          (alet (a (mu 1 2) ((b c) (mu 3 4)))
          ++
          ++(alet (a (mu 1 2) ((b c) (mu 3 4)))
          +   (list a b c))
          + => ((1 2) 3 4)
          + 
          +@@ -134,7 +148,8 @@ sequence from left to right unlike let of R5RS and + +

          In SRFI 71:

          + +-
          (srfi-let ((a (begin (display "1st") 1))
          ++
          ++(srfi-let ((a (begin (display "1st") 1))
          + 	   (b c (values (begin (display "2nd") 2) 3))
          + 	   (d (begin (display "3rd") 4))
          + 	   ((values e . f) (values (begin (display "4th") 5) 6)))
          +@@ -144,7 +159,8 @@ sequence from left to right unlike let of R5RS and
          + 
          + 

          In this SRFI:

          + +-
          (alet ((a (begin (display "1st") 1))
          ++
          ++(alet ((a (begin (display "1st") 1))
          +        (b c (mu (begin (display "2nd") 2) 3))
          +        (d (begin (display "3rd") 4))
          +        ((e . f) (mu (begin (display "4th") 5) 6)))
          +@@ -157,7 +173,8 @@ sequence from left to right unlike let of R5RS and
          +    syntactically possible, as well as a single expression that produce
          +    multiple values.

          + +-
          (alet* (((a b) (mu 1 2))
          ++
          ++(alet* (((a b) (mu 1 2))
          + 	((c d e) a (+ a b c) (+ a b c d))
          + 	((f . g) (mu 5 6 7))
          + 	((h i j . k) e 9 10 h i j))
          +@@ -172,14 +189,16 @@ allowed to take multiple values bindings.

          + +

          In SRFI 71:

          + +-
          (srfi-let tag ((a 1) (b 2) (c 3) (d 4) (e 5))
          ++
          ++(srfi-let tag ((a 1) (b 2) (c 3) (d 4) (e 5))
          + 	  (if (< a 10) (tag 10 b c d e) (list a b c d e)))
          + => (10 2 3 4 5)
          + 
          + +

          In this SRFI:

          + +-
          (alet* tag ((a 1) (a b b c (mu (+ a 2) 4 5 6)) ((d e e) b 5 (+ a b c)))
          ++
          ++(alet* tag ((a 1) (a b b c (mu (+ a 2) 4 5 6)) ((d e e) b 5 (+ a b c)))
          +        (if (< a 10) (tag a 10 b c c d e d) (list a b c d e)))
          + => (10 6 6 5 5)
          + 
          +@@ -189,7 +208,8 @@ allowed to take multiple values bindings.

          + named-alet. It is also allowed to take multiple values + bindings.

          + +-
          (alet* ((a 1)
          ++
          ++(alet* ((a 1)
          + 	((b 2) (b c c (mu 3 4 5)) ((d e d (mu a b c)) . intag) . tag)
          + 	(f 6))
          +   (if (< d 10)
          +@@ -203,7 +223,8 @@ bindings.

          + +
        • They have a new binding form that has an escape function.

          + +-
          (alet ((exit)
          ++
          ++(alet ((exit)
          +        (a (begin (display "1st") 1))
          +        (b c (mu (begin (display "2nd") 2) (begin (display "3rd") 3))))
          +   (display (list a b c))
          +@@ -217,7 +238,8 @@ bindings.

          + integrated into the alet and alet* with a + syntactic keyword and.

          + +-
          (alet ((and (a (begin (display "1st") 1))
          ++
          ++(alet ((and (a (begin (display "1st") 1))
          + 	    (b (begin (display "2nd") 2))
          + 	    (c (begin (display "false") #f))
          + 	    (d (begin (display "3nd") 3))))
          +@@ -238,7 +260,8 @@ integrated into the alet and alet* with a
          +    syntactic keywords opt and cat in the
          +    similar way to let-optionals in Scsh.

          + +-
          ((lambda (str . rest)
          ++
          ++((lambda (str . rest)
          +    (alet* ((len (string-length str))
          + 	   (opt rest
          + 		(start 0 (integer? start)
          +@@ -277,8 +300,9 @@ integrated into the alet and alet* with a
          + 	  are integrated into the alet and
          + 	  alet* with a syntactic keyword key.
          + 	  They use any Scheme objects as keywords.
          +-
          +-

          (define rest-list '(a 10 cc 30 40 b 20))
          ++

          ++
          ++(define rest-list '(a 10 cc 30 40 b 20))
          + (alet ((key rest-list (a 1) (b 2) ((c 'cc) 3) . d)) (list a b c d))
          + => (10 2 30 (40 b 20))
          + 
          +@@ -318,7 +342,8 @@ integrated into the alet and alet* with a
          + into the alet and alet* with a
          +     syntactic keyword rec.

          + +-
          (alet* ((a 1)
          ++
          ++(alet* ((a 1)
          + 	(rec (a 2) (b 3) (b (lambda () c)) (c a))
          + 	(d 50))
          +   (list a (b) c d))
          +@@ -330,7 +355,8 @@ into the alet and alet* with a
          + and values to handle multiple values with a syntactic
          + keyword values like SRFI 71.

          + +-
          (alet ((a b (mu 1 2))
          ++
          ++(alet ((a b (mu 1 2))
          +        (values c d (values 3 4))	;This is different from SRFI 71.
          +        ((e f) (mu 5 6))
          +        ((values g h) (values 7 8))
          +@@ -347,7 +373,8 @@ keyword values like SRFI 71.

          + environment in alet and as an intervening internal + environment in alet*.

          + +-
          (alet ((a 1)
          ++
          ++(alet ((a 1)
          +        (() (define a 10) (define b 100))
          +        (b a))
          +   (list a b))
          +@@ -362,9 +389,10 @@ keyword values like SRFI 71.

          +
        • + + +-

          Specification

          ++

          Specification

          + +-
          (mu <expr> ...)			=> (lambda (f) (f <expr> ...))
          ++
          ++(mu <expr> ...)			=> (lambda (f) (f <expr> ...))
          + (nu <expr> ... <exprn>)		=> (lambda (f) (apply f <expr> ... <exprn>))
          + 
          + +@@ -381,7 +409,8 @@ argument procedure of mu is called with the <expr>s, + and that of nu is applied to APPLY procedure with the + <expr>s.

          + +-
          (alet  (<binding spec> ...) body ...)
          ++
          ++(alet  (<binding spec> ...) body ...)
          + (alet* (<binding spec> ...) body ...)
          + 
          + +@@ -406,17 +435,20 @@ and that of nu is applied to APPLY procedure with the +
        • (<binding spec1> <binding spec2> ... . <var>)
        • +
        • (() . <var>)
        • +
        • (and (<var1> <expr1> [<test1>]) (<var2> <expr2> [<test2>]) ...)
        • +-
        • (opt <rest list>
          ++
        • ++(opt <rest list>
          +     (<var1> <default1> [<test1> [<true substitute1> [<false substitute1>]]])
          +     ...
          +     (<varn> <defaultn> [<testn> [<true substituten> [<false substituten>]]])
          +     . [<rest var>])
        • +-
        • (cat <rest list>
          ++
        • ++(cat <rest list>
          +      (<var1> <default1> [<test1> [<true substitute1> [<false substitute1>]]])
          +      ...
          +      (<varn> <defaultn> [<testn> [<true substituten> [<false substituten>]]])
          +      . [<rest var>])
        • +-
        • (key <rest list>
          ++
        • ++(key <rest list>
          +  (<var spec1> <default1> [<test1> [<true substitute1> [<false substitute1>]]])
          +  ...
          +  (<var specn> <defaultn> [<testn> [<true substituten> [<false substituten>]]])
          +@@ -527,7 +559,8 @@ instead of signaling an error.  If it returns a true value and there is a
          + substitute>.
          +       
        • + +-
        • (cat <rest list>
          ++
        • ++(cat <rest list>
          +      (<var1> <default1> [<test1> [<true substitute1> [<false substitute1>]]])
          +      ...
          +      (<varn> <defaultn> [<testn> [<true substituten> [<false substituten>]]])
          +@@ -549,7 +582,8 @@ and <test> returns a true value, <var> is finally bound to
          + the result of evaluating <true substitute>.
          +       
        • + +-
        • (key <rest list>
          ++
        • ++(key <rest list>
          +  (<var spec1> <default1> [<test1> [<true substitute1> [<false substitute1>]]])
          +  ...
          +  (<var specn> <defaultn> [<testn> [<true substituten> [<false substituten>]]])
          +@@ -642,7 +676,8 @@ This works as an intervening external environment in
          +       
        • + + +-
          (alet  name (<binding spec> ...) body ...)
          ++
          ++(alet  name (<binding spec> ...) body ...)
          + (alet* name (<binding spec> ...) body ...)
          + 
          + +@@ -651,9 +686,10 @@ These are the same as the named-let (R5RS, 4.2.4) except + binding specification. These allow all sorts of bindings in <binding + spec>.

          + +-

          Examples

          ++

          Examples

          + +-
          (alet ((a (begin (display "1st") 1))
          ++
          ++(alet ((a (begin (display "1st") 1))
          +        ((b c) 2 (begin (display "2nd") 3))
          +        (() (define m #f) (define n (list 8)))
          +        ((d (begin (display "3rd") 4))
          +@@ -749,14 +785,15 @@ spec>.

          + "cdefghi" +
          + +-

          Implementation

          ++

          Implementation

          + +

          + The following implementation is written in R5RS hygienic macros and + requires SRFI 23 (Error reporting mechanism). +

          + +-
          ;;; mu & nu
          ++
          ++;;; mu & nu
          + (define-syntax mu
          +   (syntax-rules ()
          +     ((mu argument ...)
          +@@ -1888,7 +1925,7 @@ requires SRFI 23 (Error reporting mechanism).
          +      (let ((e z)) bd ...))))
          + 
          + +-

          References

          ++

          References

          + +
            +
          • [R5RS] Richard Kelsey, William Clinger, and Jonathan Rees: Revised(5) +@@ -1896,20 +1933,21 @@ requires SRFI 23 (Error reporting mechanism). + Link
          • +
          • [SRFI 2] Oleg Kiselyov: and-let*: and and with local bindings, a guarded + let* special form. +- Link
          • ++ Link +
          • [SRFI 11] Lars T. Hansen: Syntax for receiving multiple values. +- Link
          • ++ Link +
          • [SRFI 51] Joo ChurlSoo: Handling rest list. +- Link
          • ++ Link +
          • [SRFI 71] Sebastian Egner: Extended let-syntax for multiple values. +- Link
          • ++ Link +
          • [Scsh] Olin Shivers, Brian Carlstrom, Martin Gasbichler, Mike Sperber +- Link
          • ++ Link +
          + +-

          Copyright

          +- ++

          Copyright

          ++

          + Copyright (c) 2006 Joo ChurlSoo. ++

          +

          + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), +@@ -1917,10 +1955,12 @@ to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: +-

          ++

          ++

          + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +-

          ++

          ++

          + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +@@ -1928,10 +1968,8 @@ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +- +-


          ++

          ++
          +
          Editor: Mike + Sperber
          +- +- + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-87.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-87.html +index 73986bb..7920a28 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-87.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-87.html +@@ -1,44 +1,63 @@ +- +-SRFI 87: => in case clauses ++ ++ ++ ++ ++ ++ SRFI 87: => in case clauses ++ ++ ++ ++ + +-

          Title

          ++ + +-=> in case clauses ++

          SRFI 87: => in case clauses

          + +-

          Author

          ++

          by Chongkai Zhu

          ++

          This copy of the SRFI 87 specification document ++is distributed as part of the Racket package ++srfi-doc.

          The canonical source of this document is ++https://srfi.schemers.org/srfi-87/srfi-87.html.

          + +-Chongkai Zhu ++

          Status

          + +-

          Status

          +- +-This SRFI is currently in ``final'' status. To see an explanation of each +-status that a SRFI can hold, see +-here. +-To provide input on this SRFI, please +-mailto:srfi-87@srfi.schemers.org. +-See instructions +-here to subscribe to the list. You can access the discussion via +-the +-archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +-

          +-

            +-
          • Received: 2006/04/10
          • +-
          • Revised: 2006/05/08
          • +-
          • Draft: 2006/04/10 - 2006/06/08
          • +-
          • Final: 2006/10/18
          • ++

            This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-87@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

            ++ + +-

            Abstract

            This SRFI proposes an extension to the case syntax ++

            Abstract

            ++

            ++This SRFI proposes an extension to the case syntax + to allow the => clauses as in cond. +-

            Rationale

            case is introduced as a syntax sugar based on ++

            ++ ++

            Rationale

            ++

            ++case is introduced as a syntax sugar based on + cond, which helps to save a explicit calling to let. + But without the => clause, if the result expression + needs the value of key, the let can't be saved. For an + easy example, suppose we want the following: ++

            +
            (case (get-symbol)
            +   ((true) #t)
            +   ((false) #f)
            +@@ -49,14 +68,15 @@ write:

            + (cond ((eq? key 'true) #t) + ((eq? key 'false) #f) + (else key)))
            +-

            Specification

            ++ ++

            Specification

            +

            (Based on R5RS section 4.2.1 Conditionals)

            +
            +-
            library syntax: case <key> <clause1> +- <clause2> ... ++
            library syntax: case <key> <clause1> ++ <clause2> ... +
            Syntax: <Key> may be any expression. Each <clause> + should have the form
            ((<datum1> ...) <expression1> <expression2> ...),
            +-

            where each <datum> is an external representation of some object. All ++

            where each <datum> is an external representation of some object. All + the <datum>s must be distinct. The last <clause> may be an "else + clause," which has the form

            (else <expression1> <expression2> ...).
            +

            Alternatively, a <clause> may be of the form +@@ -66,7 +86,7 @@ write:

            +

            Semantics: A `case' expression is evaluated as + follows. <Key> is evaluated and its result is compared against each + <datum>. If the result of evaluating <key> is equivalent (in the +- sense of `eqv?'; see section see section 6.1 Equivalence ++ sense of `eqv?'; see section see section 6.1 Equivalence + predicates) to a <datum>, then the expressions in the corresponding + <clause> are evaluated from left to right and the result(s) of the last + expression in the <clause> is(are) returned as the result(s) of the +@@ -79,13 +99,14 @@ write:

            + <expression> is evaluated. Its value must be a procedure that accepts + one argument; this procedure is then called on the value of <Key> and + the value(s) returned by this procedure is(are) returned by the +- `case' expression.

            ++ `case' expression.

            +

            (Based on R5RS section 3.5 Proper tail recursion)

            +-
            If a cond or case expression is in a tail context, and has a clause of the ++

            If a cond or case expression is in a tail context, and has a clause of the + form (<expression1> => <expression2>) then the + (implied) call to the procedure that results from the evaluation of <expression2> +-is in a tail context. <expression2> itself is not in a tail context.

            +-

            Implementation

            ++is in a tail context. <expression2> itself is not in a tail context.

            ++ ++

            Implementation

            +
            (define-syntax case
            +   (syntax-rules (else =>)
            +     ((case (key ...)
            +@@ -118,24 +139,31 @@ is in a tail context. <expression2> itself is not in a tail con
            +      (if (memv key '(atoms ...))
            +          (begin result1 result2 ...)
            +          (case key clause clauses ...)))))
            +-

            Copyright

            Copyright (C) 2006 Chongkai Zhu. All Rights Reserved. ++

            Copyright

            ++

            ++Copyright (C) 2006 Chongkai Zhu. All Rights Reserved. ++

            +

            Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + the Software, and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: +-

            The above copyright notice and this permission notice shall be included in ++

            ++

            ++The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. +-

            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++

            ++

            ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +-


            ++

            ++
            + +-
            Editor: Mike ++
            Editor: Mike + Sperber
            Last +-modified: Mon Apr 10 21:20:25 CEST 2006 +- ++modified: Mon Apr 10 21:20:25 CEST 2006 +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-9.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-9.html +index 0bf112a..4a64ddb 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-9.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-9.html +@@ -1,63 +1,90 @@ +- +- ++ ++ + ++ ++ + SRFI 9: Defining Record Types ++ ++ ++ + + + + +-

            Title

            ++

            SRFI 9: Defining Record Types

            + +-SRFI 9: Defining Record Types ++

            by Richard Kelsey

            ++

            This copy of the SRFI 9 specification document ++is distributed as part of the Racket package ++srfi-doc.

            The canonical source of this document is ++https://srfi.schemers.org/srfi-9/srfi-9.html.

            + +-

            Author

            ++

            Status

            + +-Richard Kelsey +- +-

            Status

            +- +-This SRFI is currently in ``final'' status. To see an explanation of each status that a SRFI can hold, see here. +-You can access the discussion via the archive of the mailing list. +-

              +-
            • Received: 1999/07/01 +-
            • Revised: 1999/08/25 +-
            • Draft: 1999/07/07-1999/09/06 +-
            • Final: 1999/09/09 +-
            +- +-

            Abstract

            ++

            This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-9@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

            ++
              ++
            • Received: 1999-07-01
            • ++
            • Revised: 1999-08-25
            • ++
            • Draft: 1999-07-07--1999-09-06
            • ++
            • Final: 1999-09-09
            • ++
            + ++

            Abstract

            ++

            + This SRFI describes syntax for creating new data types, called record types. + A predicate, constructor, and field accessors and modifiers are defined for + each record type. Each new record type is distinct from all existing types, + including other record types and Scheme's predefined types. ++

            + +-

            Rationale

            +- ++

            Rationale

            ++

            + Many Scheme implementations provide means for creating new types, + usually called either records or structures. + The DEFINE-RECORD-TYPE syntax described here is a slight +- simplification of one written for Scheme 48 by Jonathan Rees. ++ simplification of one written for Scheme 48 by Jonathan Rees. + Unlike many record-defining macros or special forms, it + does not create any new identifiers. + Instead, the names of the + record type, predicate, constructor, and so on are all listed explicitly + in the source. + This has the following advantages: +-

              +-
            • It can be defined using a simple SYNTAX-RULES macro ++

              ++
                ++
              • ++ It can be defined using a simple SYNTAX-RULES macro + in Scheme implementations that provide a procedural interface + for creating record types. +-
              • It does not restrict users to a particular naming convention. +-
              • Tools like grep and GNU Emacs's tag facility will see the ++
              • ++
              • ++ It does not restrict users to a particular naming convention. ++
              • ++
              • ++ Tools like grep and GNU Emacs's tag facility will see the + defining occurrence of each identifier. +-
              +- +-

              Specification

              ++
            • ++
            + ++

            Specification

            ++

            + The syntax of a record-type definition is: +- +-

            ++

            ++
            +  <command or definition>           
            +    -> <record type definition>           ; addition to 8.1.6 in R5RS
            + 
            +@@ -72,70 +99,80 @@ The syntax of a record-type definition is:
            + 
            +  <field tag> -> <identifier>
            +  <... name>  -> <identifier>
            +-
            +- ++
            ++

            + DEFINE-RECORD-TYPE is generative: + each use creates a new record type that is distinct from all existing types, + including other record types and Scheme's predefined types. +- ++

            ++

            + Record-type definitions may only occur at top-level (there are two + possible semantics for `internal' record-type definitions, generative + and nongenerative, and no consensus as to which is better). +- +-

            ++

            ++

            + An instance of DEFINE-RECORD-TYPE is equivalent to the following + definitions: +-

              +-
            • <type name> is bound to a representation of the record ++

              ++
                ++
              • ++ <type name> is bound to a representation of the record + type itself. Operations on record types, such as defining print + methods, reflection, etc. are left to other SRFIs. +- +-
              • <constructor name> is bound to a procedure that takes ++
              • ++
              • ++ <constructor name> is bound to a procedure that takes + as many arguments as there are <field tag>s in the + (<constructor name> ...) + subform and returns a new <type name> record. + Fields whose tags are listed with <constructor name> + have the corresponding argument as their + initial value. The initial values of all other fields are unspecified. +- +-
              • <predicate name> is a predicate that returns #T when ++
              • ++
              • ++ <predicate name> is a predicate that returns #T when + given a value returned by <constructor name> and #F + for everything else. +- +-
              • Each <accessor name> is a procedure that takes a record ++
              • ++
              • ++ Each <accessor name> is a procedure that takes a record + of type <type name> and returns the current value of the + corresponding field. + It is an error to pass an accessor a value which is not a record of + the appropriate type. +- +-
              • Each <modifier name> is a procedure that takes a record ++
              • ++
              • ++ Each <modifier name> is a procedure that takes a record + of type <type name> and a value which becomes the new + value of the corresponding field; an unspecified value is returned. + It is an error to pass a modifier a first + argument which is not a record of the appropriate type. +-
              ++
            • ++
            + +-

            ++

            + Records are disjoint from the types listed in Section 4.2 of R5RS. +- +-

            ++

            ++

            + Set!ing the value of any of these identifiers has no + effect on the behavior of any of their original values. +- +-

            ++

            ++

            + The following +-

            ++

            ++
            +   (define-record-type :pare
            +     (kons x y)
            +     pare?
            +     (x kar set-kar!)
            +     (y kdr))
            +-
            ++
            ++

            + defines KONS to be a constructor, KAR and + KDR to be accessors, SET-KAR! to be a modifier, + and PARE? to be a predicate for :PAREs. +- +-

            ++

            ++
            +   (pare? (kons 1 2))        --> #t
            +   (pare? (cons 1 2))        --> #f
            +   (kar (kons 1 2))          --> 1
            +@@ -143,27 +180,33 @@ and PARE? to be a predicate for :PAREs.
            +   (let ((k (kons 1 2)))
            +     (set-kar! k 3)
            +     (kar k))                --> 3
            +-
            +- +-

            Implementation

            ++
            + ++

            Implementation

            ++

            + This code is divided into three layers. In top-down order these are: +-

              +-
            1. Syntax definitions for DEFINE-RECORD-TYPE and an auxiliary +- macro. +-
            2. An implementation of record types with a procedural interface. ++

              ++
                ++
              1. ++Syntax definitions for DEFINE-RECORD-TYPE and an auxillary macro. ++
              2. ++
              3. ++An implementation of record types with a procedural interface. + Some Scheme implementations already have something close to this. +-
              4. Vector-like records implemented in R5RS. This redefines some standard ++
              5. ++
              6. ++Vector-like records implemented in R5RS. This redefines some standard + Scheme procedures and therefor must be loaded before any other code, including + part 2 above. Note that these procedures can be used to break the + record-type abstraction (for example, RECORD-SET! can be used + to modify the type of a record). Access to these procedures should be + restricted. +-
              ++
            3. ++
            + +-

            Syntax definitions

            ++

            Syntax definitions

            + +-
            ++
            + ; Definition of DEFINE-RECORD-TYPE
            + 
            + (define-syntax define-record-type
            +@@ -193,23 +236,23 @@ restricted.
            +      (begin
            +        (define accessor (record-accessor type 'field-tag))
            +        (define modifier (record-modifier type 'field-tag))))))
            +-
            ++
            + +-

            Record types

            ++

            Record types

            + +-
            ++
            + ; We define the following procedures:
            + ; 
            +-; (make-record-type <type-name <field-names>)    -> <record-type>
            +-; (record-constructor <record-type<field-names>) -> <constructor>
            +-; (record-predicate <record-type>)               -> <predicate>
            +-; (record-accessor <record-type <field-name>)    -> <accessor>
            +-; (record-modifier <record-type <field-name>)    -> <modifier>
            ++; (make-record-type <type-name <field-names>)    -> <record-type>
            ++; (record-constructor <record-type<field-names>) -> <constructor>
            ++; (record-predicate <record-type>)               -> <predicate>
            ++; (record-accessor <record-type <field-name>)    -> <accessor>
            ++; (record-modifier <record-type <field-name>)    -> <modifier>
            + ;   where
            +-; (<constructor> <initial-value> ...)         -> <record>
            +-; (<predicate> <value>)                       -> <boolean>
            +-; (<accessor> <record>)                       -> <value>
            +-; (<modifier> <record> <value>)         -> <unspecific>
            ++; (<constructor> <initial-value> ...)         -> <record>
            ++; (<predicate> <value>)                       -> <boolean>
            ++; (<accessor> <record>)                       -> <value>
            ++; (<modifier> <record> <value>)         -> <unspecific>
            + 
            + ; Record types are implemented using vector-like records.  The first
            + ; slot of each record contains the record's type, which is itself a
            +@@ -308,19 +351,19 @@ restricted.
            +                     type))
            +           (record-set! thing index value)
            +           (error "modifier applied to bad value" type tag thing)))))
            +-
            ++
            + +-

            Records

            ++

            Records

            + +-
            ++
            + ; This implements a record abstraction that is identical to vectors,
            + ; except that they are not vectors (VECTOR? returns false when given a
            + ; record and RECORD? returns false when given a vector).  The following
            + ; procedures are provided:
            +-;   (record? <value>)                -> <boolean>
            +-;   (make-record <size>)             -> <record>
            +-;   (record-ref <record> <index>)    -> <value>
            +-;   (record-set! <record> <index> <value>) -> <unspecific>
            ++;   (record? <value>)                -> <boolean>
            ++;   (make-record <size>)             -> <record>
            ++;   (record-ref <record> <index>)    -> <value>
            ++;   (record-set! <record> <index> <value>) -> <unspecific>
            + ;
            + ; These can implemented in R5RS Scheme as vectors with a distinguishing
            + ; value at index zero, providing VECTOR? is redefined to be a procedure
            +@@ -366,9 +409,9 @@ restricted.
            + 
            + (define (record-set! record index value)
            +   (vector-set! record (+ index 1) value))
            +-
            ++
            + +-

            Copyright

            ++

            Copyright

            + +

            Copyright (C) Richard Kelsey (1999). All Rights Reserved.

            + +@@ -395,9 +438,9 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

            + +-
            ++
            + +-
            Editor: Mike Sperber
            ++
            Editor: Mike Sperber
            + + + +diff --git a/srfi-doc/srfi/scribblings/srfi-std/srfi-98.html b/srfi-doc/srfi/scribblings/srfi-std/srfi-98.html +index 8ff8dfb..f5edd0e 100644 +--- a/srfi-doc/srfi/scribblings/srfi-std/srfi-98.html ++++ b/srfi-doc/srfi/scribblings/srfi-std/srfi-98.html +@@ -1,57 +1,63 @@ +- +- +- +- +- +- ++ ++ ++ ++ ++ + SRFI 98: An interface to access environment variables. +- +- +-

            Title

            +- +-An interface to access environment variables. +- +-

            Author

            +- +-Taro Minowa(Higepon) +- +-

            Status

            +- +-This SRFI is currently in ``final'' status. To see an explanation of +-each status that a SRFI can hold, see here. +- +-To provide input on this SRFI, please send email to +- +-<srfi minus 98 at srfi dot schemers dot org>. See +-instructions here to subscribe to +-the list. You can access the discusssion via +-the archive of the mailing list. +-You can access +-post-finalization messages via +- +-the archive of the mailing list. +-

              +- +-
            • Received: 2008/07/06
            • +-
            • Draft: 2008/07/06 - 2008/09/06
            • +-
            • Revised: 2008/07/18
            • +-
            • Revised: 2008/07/18
            • +-
            • Revised: 2008/08/14
            • +-
            • Final: 2008/09/19
            • +-
            • R6RS library name: 2009/02/16
            • ++ ++ ++ ++ ++ ++ ++ ++

              SRFI 98: An interface to access environment variables.

              ++ ++

              by Taro Minowa (Higepon)

              ++

              This copy of the SRFI 98 specification document ++is distributed as part of the Racket package ++srfi-doc.

              The canonical source of this document is ++https://srfi.schemers.org/srfi-98/srfi-98.html.

              ++ ++

              Status

              ++ ++

              This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-98@nospamsrfi.schemers.org. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.

              ++ + +-

              Abstract

              ++

              Abstract

              + This SRFI specifies the procedure get-environment-variable, which gets + the value of the specified environment variable, and the procedure + get-environment-variables, which gets an association list of all + environment variables. + +-

              Rationale

              ++

              Rationale

              +

              Most operating systems provide a mechanism for passing auxiliary + parameters implicitly to child processes. Usually, this mechanism is + called "the environment", and is conceptually a map from string names +-to string values. The string names are called environment ++to string values. The string names are called enviornment + variables.

              + +

              Some applications rely on environment variables to modify their +@@ -60,9 +66,8 @@ protocols rely on environment variables as a form of interprocess + communication. For example, most implementations of the common + gateway interface (CGI) use environment variables to pass + Meta-Variables from the server to the script [1]. +-Environment variables are also required +-by SRFI 96: SLIB Prerequisites. ++Environment variables are also required by ++SRFI 96: SLIB Prerequisites. + Providing a means to access environment variables is therefore + indispensable for writing practical programs in Scheme. +

              +@@ -83,10 +88,10 @@ Meta-Variables "QUERY_STRING", "CONTENT_LENGTH" and +
          + +

          [1] The Common Gateway Interface (CGI) Version 1.1, RFC3875, http://www.ietf.org/rfc/rfc3875.

          +-

          Specification

          ++

          Specification

          +
          R6RS library name
          + The following two procedures belong to the R6RS library named (srfi :98 os-environment-variables). +-
          Function: get-environment-variable name
          Returns the value of ++
          Function: get-environment-variable name
          Returns the value of + the named environment variable as a string, or #f if the named + environment variable is not found. The name argument is expected to be + a string. +@@ -96,19 +101,21 @@ the environment variable. + If get-environment-variable can't decode the value, get-environment-variable may raise an exception. +
          (get-environment-variable "PATH") => "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
          + 
          +-
          Function: get-environment-variables
          ++
          Function: get-environment-variables
          + Returns names and values of all the environment variables as an a-list. + The same decoding considerations as for get-environment-variable apply. +
          (get-environment-variables) => (("PATH" . "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin") ("USERNAME" . "taro"))
          + 
          + +-

          Implementation

          +-

          Gauche

          +-
          (define get-environment-variable sys-getenv)
          ++

          Implementation

          ++

          Gauche

          ++
          ++(define get-environment-variable sys-getenv)
          + (define get-environment-variables sys-environ->alist)
          + 
          +-

          Scheme48

          +-
          (define (get-environment-variable name)
          ++

          Scheme48

          ++
          ++(define (get-environment-variable name)
          +   (cond
          +     ((lookup-environment-variable name) => os-string->string)
          +     (else #f)))
          +@@ -117,17 +124,19 @@ The same decoding considerations as for get-environment-variable apply.
          +         (cons (os-string->string (car p)) (os-string->string (cdr p))))
          +        (environment-alist)))
          + 
          +-

          scsh

          +-
          (define get-environment-variable getenv)
          ++

          scsh

          ++
          ++(define get-environment-variable getenv)
          + (define get-environment-variables env->alist)
          + 
          + +-

          SCM

          +-
          (define get-environment-variable getenv)
          ++

          SCM

          ++
          ++(define get-environment-variable getenv)
          + (define get-environment-variables getenv)
          + 
          + +-

          Issues

          ++

          Issues

          +

          get-environment-variable is expected to return a "Scheme string". + Unfortunately, many current platforms, including POSIX-like ones, do + not require environment variables to be interpretable as sequences of +@@ -143,7 +152,7 @@ implementations, and captures the semantically desirable behavior in + the common case that the byte sequence is interpretable as a string.

          + + +-

          Appendix: Existing implementations

          ++

          Appendix: Existing implementations

          + + + +@@ -161,10 +170,10 @@ the common case that the byte sequence is interpretable as a string.

          + + +
          Scheme implementationget environment variableget all the environment variables as an a-list
          Bigloo(getenv name) => (or string? false) name:string? 
          STklos(getenv name) => (or string? false) name:string?(getenv)
          SCM(getenv name) => (or string? false) name:string?(getenv)
          +-

          Acknowledgements

          ++

          Acknowledgements

          + Thanks to Shiro Kawai, Alexey Radul, jmuk, Kokosabu, leque and all the members of the #Lisp_Scheme IRC channel on Freenode. +-

          Copyright

          +-Copyright (C) Taro Minowa(Higepon) (2008). All Rights Reserved. ++

          Copyright

          ++Copyright (C) Taro Minowa (Higepon) (2008). All Rights Reserved. +

          + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the +@@ -185,7 +194,7 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +

          +-
          ++
          +
          Editor: Mike Sperber
          + + +diff --git a/srfi-doc/srfi/scribblings/srfi.scrbl b/srfi-doc/srfi/scribblings/srfi.scrbl +index 4ab1397..3b1807d 100644 +--- a/srfi-doc/srfi/scribblings/srfi.scrbl ++++ b/srfi-doc/srfi/scribblings/srfi.scrbl +@@ -1,12 +1,23 @@ + #lang scribble/doc +-@(require srfi/scribblings/util ++@(require "util.rkt" + scribble/manual + scribble/eval + scriblib/render-cond + scribble/core + scribble/html-properties + (for-syntax scheme/base) +- (for-label scheme/base ++ (for-label (except-in scheme/base ++ make-date ;; but we DO want `date` ++ date? ++ date-second ++ date-minute ++ date-hour ++ date-day ++ date-month ++ date-year ++ date-week-day ++ date-year-day) ++ srfi/19 + racket/stream)) + + @; ---------------------------------------------------------------------- +@@ -27,7 +38,7 @@ which can be implemented as libraries. To import the bindings of SRFI + ] + + This document lists the SRFIs that are supported by Racket and +-provides a link to the original SRFI specification (which is also ++provides links to the original SRFI specifications (which are also + distributed as part of Racket's documentation). + + @table-of-contents[] +@@ -95,7 +106,7 @@ functions. + (concatenate #f "concatenate") + (concatenate! #f "concatenate!") + (reverse #f "reverse") +- (reverse! #f "srfi-1.html") ++ (reverse! #f "reverse!") + (append-reverse #f "append-reverse") + (append-reverse! #f "append-reverse!") + (zip #f "zip") +@@ -114,7 +125,7 @@ functions. + (unfold #f "unfold") + (unfold-right #f "unfold-right") + (map #f "map") +- (for-each #f "srfi-1.html") ++ (for-each #f "for-each") + (append-map #f "append-map") + (append-map! #f "append-map!") + (map! #f "map!") +@@ -153,7 +164,6 @@ functions. + (alist-copy #f "alist-copy") + (alist-delete #f "alist-delete") + (alist-delete! #f "alist-delete!") +- (lset #f "lset") + (lset= #f "lset=") + (lset-adjoin #f "lset-adjoin") + (lset-union #f "lset-union") +@@ -198,6 +208,11 @@ are also available from @racketmodname[scheme/foreign]. + + @; ---------------------------------------- + ++@; special case for historical license reasons ++@include-section["srfi-5-doc-free.scrbl"] ++ ++@; ---------------------------------------- ++ + @srfi[6]{Basic String Ports} + + @redirect[6 '( +@@ -430,7 +445,7 @@ are also available from @racketmodname[scheme/foreign]. + @srfi[17]{Generalized set!} + + @redirect[17 '( +- (set! #t "set!") ++ (set! #t "!set") + (getter-with-setter #f "getter-with-setter") + )] + +@@ -439,13 +454,13 @@ are also available from @racketmodname[scheme/foreign]. + @srfi[19]{Time Data Types and Procedures} + + @redirect[19 '( +- (time-duration #f "") ++ (time-duration #f "time-duration") + (time-monotonic #f "time-monotonic") + (time-process #f "time-process") + (time-tai #f "time-tai") + (time-thread #f "time-thread") + (time-utc #f "time-utc") +- (current-date #f "") ++ (current-date #f "current-date") + (current-julian-day #f "current-julian-day") + (current-modified-julian-day #f "current-modified-julian-day") + (current-time #f "current-time") +@@ -526,20 +541,31 @@ to the one provided by @racketmodname[racket/base] in most cases + (see @racket[date]). + + For backwards compatibility, when an invalid date field value is +-provided to the SRFI constructor, the constructor will produce a lax +-date structure. A lax date structure is @emph{not} compatible with +-functions from @racketmodname[racket/base] or ++provided to the SRFI constructor, the constructor will produce a ++@deftech{lax date structure}. A lax date structure is @emph{not} ++compatible with functions from @racketmodname[racket/base] or + @racketmodname[racket/date]. SRFI functions such as + @racket[string->date] may return a lax date structure depending on the + format string. ++The predicate @racket[lax-date?] recognizes lax dat structures. ++ ++As an extension, Racket's implementation of @racket[string->date] ++supports @litchar{~?} as a conversion specifier: ++it parses one- and two-digit years like @litchar{~y} ++and three- and four-digit years like @litchar{~Y}. + + @(define srfi-19-eval (make-base-eval)) + @(srfi-19-eval '(require srfi/19)) + ++@examples[#:eval srfi-19-eval ++ (string->date "4-1-99" "~d-~m-~?") ++ (string->date "4-1-1999" "~d-~m-~?") ++] ++ + @defproc[(lax-date? [v any/c]) boolean?]{ + +-Returns @racket[#t] if @racket[_v] is a lax date structure. Otherwise +-returns @racket[#f]. ++Returns @racket[#t] if @racket[_v] is a @tech{lax date structure}. ++Otherwise, returns @racket[#f]. + + @examples[#:eval srfi-19-eval + (lax-date? (make-date 0 19 10 10 14 "bogus" "bogus" 0)) +@@ -688,8 +714,8 @@ This SRFI's syntax is part of Racket's default reader and printer. + + @redirect[40 '( + (stream-cons #t "stream-cons") +- (stream? #f "stream?") +- (stream-null? #f "stream-null?") ++ (stream? #f "streamp") ++ (stream-null? #f "stream-nullp") + (stream-car #f "stream-car") + (stream-cdr #f "stream-cdr") + (stream-delay #t "stream-delay") +@@ -787,7 +813,7 @@ same as from @racketmodname[racket/stream]. + (:real-range #t ":real-range") + (:char-range #t ":char-range") + (:port #t ":port") +- (:dispatched #t "") ++ (:dispatched #t ":dispatched") + (:generator-proc #t ":generator-proc") + (:do #t ":do") + (:let #t ":let") +@@ -814,7 +840,7 @@ from @racketmodname[scheme/base] and @mz-if from + (vector-append #f "vector-append") + (vector-concatenate #f "vector-concatenate") + (vector? #f "vector-p") +- (vector-empty? #f "vector-empty?") ++ (vector-empty? #f "vector-empty-p") + (vector= #f "vector-eq") + (vector-ref #f "vector-ref") + (vector-length #f "vector-length") +@@ -837,10 +863,10 @@ from @racketmodname[scheme/base] and @mz-if from + (vector-reverse! #f "vector-reverse-bang") + (vector-copy! #f "vector-copy-bang") + (vector-reverse-copy! #f "vector-reverse-copy-bang") +- (vector->list #f "vector->list") +- (reverse-vector->list #f "reverse-vector->list") +- (list->vector #f "list->vector") +- (reverse-list->vector #f "reverse-list->vector") ++ (vector->list #f "vector-to-list") ++ (reverse-vector->list #f "reverse-vector-to-list") ++ (list->vector #f "list-to-vector") ++ (reverse-list->vector #f "reverse-list-to-vector") + )] + + @; ---------------------------------------- +diff --git a/srfi-doc/srfi/scribblings/util.rkt b/srfi-doc/srfi/scribblings/util.rkt +index d67c82a..786fea9 100644 +--- a/srfi-doc/srfi/scribblings/util.rkt ++++ b/srfi-doc/srfi/scribblings/util.rkt +@@ -59,3 +59,20 @@ + + @(define srfi-std (style #f (list (install-resource "srfi-std")))) + ++@(define srfi-license-history-url ++ ;; explains the "historical reasons" for the restrictive license on SRFI 5 ++ "https://srfi-email.schemers.org/srfi-announce/msg/2652023/") ++@(define srfi-5-std-taglet "srfi-5-std") ++@(define srfi-5-license-taglet "srfi-5-std-license") ++ ++@(define (racket-license-link . args) ++ ;; FIXME why does this not work? ++ #; ++ (apply seclink "License" #:doc '(lib "scribblings/main/license.scrbl") args) ++ (define (link base) ++ (apply hyperlink (string-append base "license/index.html") args)) ++ (cond-element ++ [(or latex text) ++ (link "https://docs.racket-lang.org/")] ++ [else ++ (link "../")])) +diff --git a/srfi-lib/info.rkt b/srfi-lib/info.rkt +index da0d08d..56d31b7 100644 +--- a/srfi-lib/info.rkt ++++ b/srfi-lib/info.rkt +@@ -2,6 +2,8 @@ + + (define collection 'multi) + ++(define version "1.1") ++ + (define deps '("scheme-lib" + "base" + "srfi-lite-lib" +diff --git a/srfi-lib/srfi/5/let.rkt b/srfi-lib/srfi/5/let.rkt +index a1a88fb..19be931 100644 +--- a/srfi-lib/srfi/5/let.rkt ++++ b/srfi-lib/srfi/5/let.rkt +@@ -7,51 +7,62 @@ + (define-syntax (s:let stx) + (define-syntax-class loopid + #:description "loop identifier" ++ #:opaque + (pattern :id)) + (define-syntax-class binding-pair + #:description "binding pair" + (pattern [name:id arg:expr])) +- (define-syntax-class rest-binding +- #:description "\"rest\" binding" +- (pattern [rest-name:id rest-arg:expr ...])) +- (define-splicing-syntax-class let-style-bindings +- #:description "let-style bindings" +- #:attributes (loop* [name 1] [arg 1] rest-name [rest-arg 1]) +- ;; in let-style bindings, rest-binding only allowed w/ +- ;; at least one binding-pair +- (pattern (~seq (~optional loop*:loopid) +- (:binding-pair ...)) +- #:with (rest-arg ...) #'() +- #:attr rest-name #f) +- (pattern (~seq (~optional loop*:loopid) +- (:binding-pair ...+ . :rest-binding)))) +- (define-splicing-syntax-class define-style-bindings +- #:description "define-style bindings" +- #:attributes (loop* [name 1] [arg 1] rest-name [rest-arg 1]) +- (pattern (~seq (loop*:loopid :binding-pair ...)) +- #:with (rest-arg ...) #'() +- #:attr rest-name #f) +- (pattern (~seq (loop*:loopid +- :binding-pair ... +- . :rest-binding)))) +- (define-splicing-syntax-class bindings ++ (define-splicing-syntax-class maybe-rest-binding + #:description #f ++ #:no-delimit-cut ++ (pattern (~describe "\"rest\" binding" ++ (~seq (~describe #:opaque "\"rest\" identifier" ++ rest-name:id) ++ ~! ++ (~describe #:opaque "\"rest\" init expression" ++ rest-arg:expr) ++ ...))) ++ (pattern (~seq) ++ #:attr rest-name #f ++ #:with (rest-arg ...) #'())) ++ (define-splicing-syntax-class bindings ++ #:description "bindings" + #:attributes (loop* [name 1] [arg 1] rest-name [rest-arg 1]) +- (pattern :let-style-bindings) +- (pattern :define-style-bindings)) ++ (pattern ++ (~describe ++ "\"named let\"-style bindings" ++ (~seq loop*:loopid ++ ~! ++ (~describe ++ "parenthesized sequence of binding pairs with optional \"rest\" binding" ++ (:binding-pair ... :maybe-rest-binding))))) ++ (pattern ++ (~describe ++ "\"define\"-style bindings" ++ (~seq (loop*:loopid ~! :binding-pair ... :maybe-rest-binding)))) ++ (pattern ++ (~describe ++ "\"let\"-style bindings with no loop identifier" ++ (~seq ++ (~or* (~describe #:opaque "empty sequence of binding pairs" ++ (~and () (:binding-pair ... :maybe-rest-binding))) ++ (~describe ++ "parenthesized sequence of one or more binding pairs with optional \"rest\" binding" ++ (:binding-pair ...+ :maybe-rest-binding))))) ++ #:attr loop* #f)) + (syntax-parse stx +- [(_ () body:expr ...+) +- #'(let () body ...)] + [(_ :bindings +- body:expr ...+) ++ (~describe "body forms" (~seq body:expr ...+))) ++ ;; it is NOT an error for loop* to be shaddowed: ++ ;; see https://srfi-email.schemers.org/srfi-5/msg/18712014/ + #:fail-when (check-duplicate-identifier + (syntax->list #'(name ... (~? rest-name)))) + "duplicate variable name" +- #:with loop (or (attribute loop*) #'tmp-loop) +- #'(letrec ([loop (λ (~? (name ... . rest-name) +- (name ...)) +- body ...)]) ++ #:with loop (or (attribute loop*) #'anonymous-srfi-5-let) ++ #`(letrec ([loop #,(syntax-property ++ (syntax/loc stx ++ (λ (~? (name ... . rest-name) ++ (name ...)) ++ body ...)) ++ 'inferred-name (or (attribute loop*) (void)))]) + (loop arg ... rest-arg ...))])) +- +- +- +diff --git a/srfi-test/tests/srfi/5/srfi-5-test.rkt b/srfi-test/tests/srfi/5/srfi-5-test.rkt +index 47bb660..9b3ab73 100644 +--- a/srfi-test/tests/srfi/5/srfi-5-test.rkt ++++ b/srfi-test/tests/srfi/5/srfi-5-test.rkt +@@ -27,16 +27,24 @@ + (cons x y)) + '(1 2) + "rest binding w/ 1 value") ++ (check-equal? (s:let ([x 1] y 2) ++ (cons x y)) ++ '(1 2) ++ "rest binding w/ 1 value (no dot)") + (check-equal? (s:let ([x 1] . [y 2 3]) + (cons x y)) + '(1 2 3) + "rest binding w/ multiple values") ++ (check-equal? (s:let ([x 1] y 2 3) ++ (cons x y)) ++ '(1 2 3) ++ "rest binding w/ multiple values (no dot)") + (check-exn exn:fail:syntax? + (λ () (convert-syntax-error (s:let ([x 1 2]) x))) +- "rest binding alone is an error")) ++ "malformed binding pair is an error")) + + (test-case +- "let-style loop" ++ "\"named let\"-style loop" + (check-equal? (s:let loop () 1) + 1 + "loop w/ no bindings is ok") +@@ -61,6 +69,13 @@ + [else (list args)])) + '((a) (b) (c d)) + "rest binding w/ 1 initial value") ++ (check-equal? (s:let loop ([continue? 0] args 'a) ++ (case continue? ++ [(0) (cons args (loop 1 'b))] ++ [(1) (cons args (loop 2 'c 'd))] ++ [else (list args)])) ++ '((a) (b) (c d)) ++ "rest binding w/ 1 initial value (no dot)") + (check-equal? (s:let loop ([continue? 0] + . [args 'a 'a1 'a2]) + (case continue? +@@ -69,12 +84,48 @@ + [else (list args)])) + '((a a1 a2) (b) (c d)) + "rest binding w/ multiple initial values") ++ (check-equal? (s:let loop ([continue? 0] args 'a 'a1 'a2) ++ (case continue? ++ [(0) (cons args (loop 1 'b))] ++ [(1) (cons args (loop 2 'c 'd))] ++ [else (list args)])) ++ '((a a1 a2) (b) (c d)) ++ "rest binding w/ multiple initial values (no dot)") ++ (check-equal? (s:let loop (x) ++ x) ++ '() ++ "rest binding alone w/ 0 initial values") ++ (check-equal? (s:let loop (x 1) ++ x) ++ '(1) ++ "rest binding alone w/ 1 initial value") ++ (check-equal? (s:let loop (x 1 2) ++ x) ++ '(1 2) ++ "rest binding alone w/ multiple initial values") ++ (check-equal? (s:let a (b (+ 1)) ++ b) ++ '(1) ++ ;; "confusable" here means that the expression (+ 1) ++ ;; could be confused for a binding pair ++ "rest binding alone w/ confusable initial value") ++ (check-exn (λ (e) ++ (and (exn:fail:syntax? e) ++ (regexp-match? #rx"^x: unbound" (exn-message e)))) ++ (λ () ++ (convert-syntax-error ++ (s:let a (b [x 1]) 2))) ++ "rest binding alone: correct error when confused w/ define") ++ (check-pred procedure? ++ (s:let loop (args 1 2 3) ++ loop) ++ "rest binding alone: does bind procedure") + (check-exn exn:fail:syntax? + (λ () (convert-syntax-error (s:let loop ([x 1 2]) x))) +- "rest binding alone is an error")) ++ "malformed binding pair is an error")) + + (test-case +- "define-style loop" ++ "\"define\"-style loop" + (check-equal? (s:let (loop) 1) + 1 + "loop w/ no bindings is ok") +@@ -91,6 +142,20 @@ + (list x))) + '(1 2) + "loop w/ 2 normal args") ++ (check-equal? (s:let (loop [continue? 0] . [args]) ++ (case continue? ++ [(0) (cons args (loop 1 'b))] ++ [(1) (cons args (loop 2 'c 'd))] ++ [else (list args)])) ++ '(() (b) (c d)) ++ "rest binding w/ 0 initial values") ++ (check-equal? (s:let (loop [continue? 0] args) ++ (case continue? ++ [(0) (cons args (loop 1 'b))] ++ [(1) (cons args (loop 2 'c 'd))] ++ [else (list args)])) ++ '(() (b) (c d)) ++ "rest binding w/ 0 initial values (no dot)") + (check-equal? (s:let (loop [continue? 0] + . [args 'a]) + (case continue? +@@ -99,24 +164,94 @@ + [else (list args)])) + '((a) (b) (c d)) + "rest binding w/ 1 initial value") +- (check-equal? (s:let (loop [continue? 0] +- . [args 'a 'a1 'a2]) ++ (check-equal? (s:let (loop [continue? 0] args 'a) ++ (case continue? ++ [(0) (cons args (loop 1 'b))] ++ [(1) (cons args (loop 2 'c 'd))] ++ [else (list args)])) ++ '((a) (b) (c d)) ++ "rest binding w/ 1 initial value (no dot)") ++ (check-equal? (s:let (loop [continue? 0] args 'a 'a1 'a2) + (case continue? + [(0) (cons args (loop 1 'b))] + [(1) (cons args (loop 2 'c 'd))] + [else (list args)])) + '((a a1 a2) (b) (c d)) +- "rest binding w/ multiple initial values") ++ "rest binding w/ multiple initial values (no dot)") ++ (check-equal? (s:let (loop . [args]) ++ (case args ++ [(()) (cons args (loop 'b))] ++ [((b)) (cons args (loop 'c 'd))] ++ [else (list args)])) ++ '(() (b) (c d)) ++ "rest binding alone w/ 0 initial values") ++ (check-equal? (s:let (loop args) ++ (case args ++ [(()) (cons args (loop 'b))] ++ [((b)) (cons args (loop 'c 'd))] ++ [else (list args)])) ++ '(() (b) (c d)) ++ "rest binding alone w/ 0 initial values (no dot)") + (check-equal? (s:let (loop . [args 'a]) + (case args + [((a)) (cons args (loop 'b))] + [((b)) (cons args (loop 'c 'd))] + [else (list args)])) + '((a) (b) (c d)) +- "define-style loop can have only rest arg")) +- +- (check-exn exn:fail:syntax? +- (λ () +- (convert-syntax-error +- (s:let a (b [x 1]) x))) +- "combining let- and define- style loop names is an error"))) ++ "rest binding alone w/ 1 initial value") ++ (check-equal? (s:let (loop args 'a) ++ (case args ++ [((a)) (cons args (loop 'b))] ++ [((b)) (cons args (loop 'c 'd))] ++ [else (list args)])) ++ '((a) (b) (c d)) ++ "rest binding alone w/ 1 initial value (no dot)") ++ (check-equal? (s:let (loop . [args 'a1 'a2 'a3]) ++ (case args ++ [((a1 a2 a3)) (cons args (loop 'b))] ++ [((b)) (cons args (loop 'c 'd))] ++ [else (list args)])) ++ '((a1 a2 a3) (b) (c d)) ++ "rest binding alone w/ multiple initial values") ++ (check-equal? (s:let (loop args 'a1 'a2 'a3) ++ (case args ++ [((a1 a2 a3)) (cons args (loop 'b))] ++ [((b)) (cons args (loop 'c 'd))] ++ [else (list args)])) ++ '((a1 a2 a3) (b) (c d)) ++ "rest binding alone w/ multiple initial values (no dot)")) ++ (test-case ++ "shaddowing" ++ ;; See: https://srfi-email.schemers.org/srfi-5/msg/18712014/ ++ (check-equal? (s:let x ((x 1)) x) ++ 1 ++ "let-style: loop id can be shaddowed") ++ (check-equal? (s:let (x (x 1)) x) ++ 1 ++ "define-style: loop id can be shaddowed") ++ (check-eq? (object-name (s:let f () f)) ++ 'f ++ "let-style object name") ++ (check-eq? (object-name (s:let (g) g)) ++ 'g ++ "define-style object name") ++ (check-exn #rx"duplicate" ++ (λ () (convert-syntax-error (s:let loop ((x 1) x) #t))) ++ "let-style: check duplicate ids") ++ (check-exn #rx"duplicate" ++ (λ () (convert-syntax-error (s:let (loop (x 1) x) #t))) ++ "define-style: check duplicate ids") ++ (check-exn #rx"duplicate" ++ (λ () (convert-syntax-error (s:let ((x 1) (x 2)) #t))) ++ "non-loop: check duplicate ids")) ++ (test-case ++ "ambiguous \"define\"-style loop: preserve compatible behavior" ++ ;; See: https://srfi-email.schemers.org/srfi-5/msg/18709896/ ++ (check-pred procedure? ++ (s:let (ambiguous (+ 1) (- 2) (list 5)) ++ ambiguous) ++ "ambiguous is not a rest binding") ++ (check-equal? (s:let (ambiguous (+ 1) (- 2) (abs -7)) ++ (list + - abs)) ++ '(1 2 -7) ++ "binds identifiers")))) +diff --git a/srfi/info.rkt b/srfi/info.rkt +index c8d82de..45152e3 100644 +--- a/srfi/info.rkt ++++ b/srfi/info.rkt +@@ -3,11 +3,9 @@ + (define collection 'multi) + + (define deps '("srfi-lib" +- "srfi-doc" +- "srfi-doc-nonfree")) ++ ["srfi-doc" #:version "1.1"])) + (define implies '("srfi-lib" +- "srfi-doc" +- "srfi-doc-nonfree")) ++ "srfi-doc")) + + (define pkg-desc "Legacy SRFI (Scheme) libraries") + +-- +2.32.0 + diff --git a/gnu/packages/racket.scm b/gnu/packages/racket.scm index e8d016c07b..62053500cb 100644 --- a/gnu/packages/racket.scm +++ b/gnu/packages/racket.scm @@ -2,7 +2,7 @@ ;;; Copyright © 2013, 2014, 2015, 2016, 2018, 2020, 2021 Ludovic Courtès ;;; Copyright © 2017, 2018, 2019, 2020 Tobias Geerinckx-Rice ;;; Copyright © 2020 Pierre Neidhardt -;;; Copyright © 2021 Philip McGrath +;;; Copyright © 2021, 2022 Philip McGrath ;;; Copyright © 2021 jgart ;;; ;;; This file is part of GNU Guix. @@ -21,8 +21,6 @@ ;;; along with GNU Guix. If not, see . (define-module (gnu packages racket) - #:use-module ((guix licenses) - #:select (asl2.0 expat lgpl3+)) #:use-module (guix packages) #:use-module (guix download) #:use-module (guix git-download) @@ -30,7 +28,10 @@ (define-module (gnu packages racket) #:use-module (guix gexp) #:use-module (guix build-system gnu) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:use-module (ice-9 match) + #:use-module (ice-9 regex) + #:use-module (ice-9 exceptions) #:use-module (gnu packages) #:use-module (gnu packages autotools) #:use-module (gnu packages bash) @@ -47,200 +48,87 @@ (define-module (gnu packages racket) #:use-module (gnu packages multiprecision) #:use-module (gnu packages sqlite) #:use-module (gnu packages tls) - #:use-module (gnu packages xorg)) - -;; Commentary: -;; -;; Here's how bootstrapping minimal Racket works: -;; -;; - Racket BC [CGC] can be built with only a C compiler (except for -;; one caveat discussed below). -;; - Racket BC [3M] needs an existing Racket to run "xform", -;; which transforms its own C source code to add additional annotations -;; for the precise garbage collector. -;; - Racket CS needs (bootfiles for) Racket's fork of Chez Scheme. -;; It also needs an existing Racket to compile Racket-implemented -;; parts of the runtime system to R6RS libraries. -;; - Chez Scheme also needs bootfiles for itself, but Racket can simulate -;; enough of Chez Scheme to load Racket's fork of the Chez Scheme compiler -;; purely from source into Racket and apply the compiler to itself, -;; producing the needed bootfiles (albeit very slowly). -;; Any variant of Racket since version 7.1 can run the simulation. -;; -;; So, we build CGC to build 3M to build bootfiles and CS. -;; -;; One remaining bootstrapping limitation is that Racket's reader, module -;; system, and macro expander are implemented in Racket. For Racket CS, -;; they are compiled to R6RS libraries as discussed above. This note from the -;; README file applies to all such subsystems: -;; -;; The Racket version must be practically the same as the current Racket -;; verson, although it can be the Racket BC implementation (instead of -;; the Racket CS implementation). -;; -;; Unlike Chez Scheme boot files, the files generated in "schemified" -;; are human-readable and -editable Scheme code. That provides a way -;; out of bootstrapping black holes, even without BC. -;; -;; However, other Racket subsystems implemented in Racket for Racket CS -;; use older C implementations for Racket BC, whereas the reader, expander, -;; and module system were completely replaced with the Racket implementation -;; as of Racket 7.0. -;; -;; For Racket BC, the compiled "linklet" s-expressions (primitive modules) -;; are embeded in C as a static string constant. Eventually, they are further -;; compiled by the C-implemented Racket BC bytecode and JIT compilers. -;; (On platforms where Racket BC's JIT is not supported, yet another compiler -;; instead compiles the linklets to C code, but this is not a bootstrapping -;; issue.) -;; -;; Code: - -(define cfg-flag:sh-for-rktio - `(string-append "CPPFLAGS=-DGUIX_RKTIO_PATCH_BIN_SH=" - (assoc-ref %build-inputs "sh") - "/bin/sh")) -(define cfg-flag:enable-lt - `(string-append "--enable-lt=" - (assoc-ref %build-inputs "libtool") - "/bin/libtool")) -(define cfg-flag:enable-racket - `(let ((racket (assoc-ref %build-inputs "racket"))) - (string-append "--enable-racket=" - racket - "/bin/racket"))) - -(define unpack-nanopass+stex - ;; Copied from chez-scheme. - ;; TODO: Eventually, we should refactor Chez Scheme - ;; enough to share more directly, so that we can make - ;; Racket's version of Chez avalable as a Guix package, - ;; e.g. for architectures not supported upstream. - ;; For now, we let Racket drive the Chez build process - ;; other than this step. - `(for-each (lambda (dep) - (define src - (assoc-ref (or native-inputs inputs) dep)) - (copy-recursively src dep - #:keep-mtime? #t)) - '("nanopass" "stex"))) - + #:use-module (gnu packages xorg) + #:use-module ((guix licenses) + #:prefix license:)) (define-public racket-minimal (package (name "racket-minimal") - (version "8.3") ; note: remember to also update racket! - (source - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/racket/racket") - (commit (string-append "v" version)))) - (sha256 - "1i1jnv1wb0kanfg47hniafx2vhwjc33qqx66lq7wkf5hbmgsyws3") - (file-name (git-file-name name version)) - (patches (search-patches "racket-minimal-sh-via-rktio.patch")) - (modules '((guix build utils))) - (snippet - (with-imported-modules '((guix build utils)) - #~(begin - ;; Unbundle Chez submodules. - (with-directory-excursion "racket/src/ChezScheme" - ;; Remove bundled libraries (copied from 'chez-scheme'). - (for-each delete-file-recursively - '("stex" - "nanopass" - "lz4" - "zlib"))) - ;; Unbundle libffi. - (delete-file-recursively "racket/src/bc/foreign/libffi")))))) - (inputs - `(;; common to all racket-minimal variants: - ("openssl" ,openssl) - ("sqlite" ,sqlite) - ("sh" ,bash-minimal) - ;; only for CS - ("zlib" ,zlib) - ("zlib:static" ,zlib "static") - ("lz4" ,lz4) - ("lz4:static" ,lz4 "static"))) - (native-inputs - `(("bootfiles" ,racket-bootstrap-chez-bootfiles) - ,@(package-native-inputs racket-bootstrap-chez-bootfiles))) + (version (package-version (racket-vm-for-system))) + (source (package-source (racket-vm-for-system))) + ;; For cross-compilation, Matthew Flatt recommends reusing + ;; as much of `raco cross` as possible. So, put that off until + ;; we have a build system for Racket packages. + (inputs (list openssl sqlite (racket-vm-for-system))) (build-system gnu-build-system) (arguments - `(#:configure-flags - (list "--enable-csonly" - "--enable-libz" - "--enable-liblz4" - ,cfg-flag:enable-racket - ,cfg-flag:sh-for-rktio) - #:out-of-source? #true - ;; Tests are in packages like racket-test-core and - ;; main-distribution-test that aren't part of the main distribution. - #:tests? #f - #:modules ((ice-9 match) - (guix build gnu-build-system) - (guix build utils)) - #:phases - (modify-phases %standard-phases - (add-after 'unpack 'unpack-nanopass+stex - (lambda* (#:key inputs native-inputs #:allow-other-keys) - (with-directory-excursion "racket/src/ChezScheme" - ,unpack-nanopass+stex) - #t)) - (add-after 'unpack-nanopass+stex 'unpack-bootfiles - (lambda* (#:key inputs #:allow-other-keys) - (with-directory-excursion "racket/src/ChezScheme" - (copy-recursively - (string-append (assoc-ref inputs "bootfiles") "/boot") - "boot")) - #t)) - (add-before 'configure 'initialize-config.rktd - (lambda* (#:key inputs #:allow-other-keys) - (define (write-racket-hash alist) - ;; inside must use dotted pair notation - (display "#hash(") - (for-each (match-lambda - ((k . v) - (format #t "(~s . ~s)" k v))) - alist) - (display ")\n")) - (mkdir-p "racket/etc") - (with-output-to-file "racket/etc/config.rktd" - (lambda () - (write-racket-hash - `((lib-search-dirs - . (#f ,@(map (lambda (lib) - (string-append (assoc-ref inputs lib) - "/lib")) - '("openssl" - "sqlite")))) - (build-stamp . "") - (catalogs - . (,(string-append - "https://download.racket-lang.org/releases/" - ,version - "/catalog/") - #f)))))) - #t)) - (add-before 'configure 'change-directory - (lambda _ - (chdir "racket/src") - #t)) - (add-after 'install 'remove-pkgs-directory - ;; If the configured pkgs-dir exists, "pkgs.rktd" does not - ;; exist, and a lock file does not exist, commands like - ;; `raco pkg show` will try to create a lock file and fail - ;; due to the read-only store. - ;; Arguably this may be a bug in `pkg/private/lock`: - ;; see . - ;; As a workaround, remove the directory. - (lambda* (#:key outputs #:allow-other-keys) - ;; rmdir because we want an error if it isn't empty - (rmdir (string-append (assoc-ref outputs "out") - "/share/racket/pkgs")) - #t))))) + (list + #:configure-flags + #~`("--tethered" + "--extra-foreign-lib-search-dirs" + ,(format #f "~s" + (list #$(file-append (this-package-input "openssl") "/lib") + #$(file-append (this-package-input "sqlite") "/lib")))) + #:make-flags #~`("base") + #:tests? #f ;; packaged separately + #:modules '((guix build gnu-build-system) + (guix build utils) + (ice-9 match)) + #:phases + #~(modify-phases %standard-phases + (replace 'configure + (lambda* (#:key inputs configure-flags make-flags + #:allow-other-keys) + (let* ((vm-dir (search-input-directory inputs "opt/racket-vm")) + (racket (string-append vm-dir "/bin/racket"))) + (apply invoke + racket + #$make-installation-layer.rkt + `(,@(cond + ((false-if-exception + (search-input-file + inputs "etc/racket/config.rktd")) + => (lambda (file) + `("--parent" + ,(dirname (dirname (dirname file)))))) + (else + '())) + ,@configure-flags + ,vm-dir + ,#$output)) + (invoke racket + "--config" (string-append #$output "/etc/racket") + "-l" "raco" "setup" + "--no-user")))) + (replace 'build + (lambda* (#:key inputs #:allow-other-keys) + (mkdir-p (string-append #$output "/lib/racket/pkgs")) + (for-each (lambda (name) + (copy-recursively + (string-append "pkgs/" name) + (string-append #$output "/lib/racket/pkgs/" name))) + '("base" "racket-lib")))) + (replace 'install + (lambda* (#:key inputs make-flags #:allow-other-keys) + (let ((racket + (search-input-file inputs "/opt/racket-vm/bin/racket"))) + (unless (null? make-flags) + (invoke racket + "-l-" + "pkg/dirs-catalog" + "--link" + "local-catalog" + (string-append #$output "/lib/racket/pkgs")) + (apply invoke + racket + "--config" (string-append #$output "/etc/racket") + "-l" "raco" + "pkg" "install" + "--installation" + "--auto" + "--catalog" "local-catalog" + make-flags)))))))) (home-page "https://racket-lang.org") (synopsis "Racket without bundled packages such as DrRacket") (description @@ -254,280 +142,77 @@ (define (write-racket-hash alist) DrRacket IDE, are not included.") ;; https://download.racket-lang.org/license.html ;; The LGPL components are only used by Racket BC. - (license (list asl2.0 expat)))) - - -(define-public racket-minimal-bc-3m - (hidden-package - (package - (inherit racket-minimal) - (name "racket-minimal-bc-3m") - (inputs - (modify-inputs (package-inputs racket-minimal) - (delete "zlib" "zlib:static" "lz4" "lz4:static") - (prepend libffi ;; <- only for BC variants - ))) - (native-inputs - `(("libtool" ,libtool) - ("racket" ,(if (%current-target-system) - racket-minimal - racket-minimal-bc-cgc)))) - (arguments - (substitute-keyword-arguments (package-arguments racket-minimal) - ((#:configure-flags _ '()) - `(list "--enable-bconly" - ,cfg-flag:enable-racket - ,cfg-flag:enable-lt - ,cfg-flag:sh-for-rktio)) - ((#:phases usual-phases) - `(modify-phases ,usual-phases - (delete 'unpack-nanopass+stex) - (delete 'unpack-bootfiles))))) - (synopsis "Minimal Racket with the BC [3M] runtime system") - (description "The Racket BC (``before Chez'' or ``bytecode'') -implementation was the default before Racket 8.0. It uses a compiler written -in C targeting architecture-independent bytecode, plus a JIT compiler on most -platforms. Racket BC has a different C API and supports a slightly different -set of architectures than the current default runtime system, Racket CS (based -on ``Chez Scheme''). - -This package is the normal implementation of Racket BC with a precise garbage -collector, 3M (``Moving Memory Manager'').") - ;; https://download.racket-lang.org/license.html - ;; The LGPL components are only used by Racket BC. - (license (list lgpl3+ asl2.0 expat))))) - - -(define-public racket-minimal-bc-cgc - (package - (inherit racket-minimal-bc-3m) - (name "racket-minimal-bc-cgc") - (native-inputs - (alist-delete "racket" (package-native-inputs racket-minimal-bc-3m))) - (arguments - (substitute-keyword-arguments (package-arguments racket-minimal-bc-3m) - ((#:configure-flags _ '()) - `(list "--enable-cgcdefault" - ,cfg-flag:enable-lt - ,cfg-flag:sh-for-rktio)))) - (synopsis "Old Racket implementation used for bootstrapping") - (description "This variant of the Racket BC (``before Chez'' or -``bytecode'') implementation is not recommended for general use. It uses -CGC (a ``Conservative Garbage Collector''), which was succeeded as default in -PLT Scheme version 370 (which translates to 3.7 in the current versioning -scheme) by the 3M variant, which in turn was succeeded in version 8.0 by the -Racket CS implementation. - -Racket BC [CGC] is primarily used for bootstrapping Racket BC [3M]. It may -also be used for embedding applications without the annotations needed in C -code to use the 3M garbage collector."))) - - -(define-public racket-bootstrap-chez-bootfiles - (hidden-package - (package - (inherit racket-minimal) - (name "racket-bootstrap-chez-bootfiles") - (inputs `()) - (native-inputs - `(("racket" ,(if (%current-target-system) - racket-minimal - racket-minimal-bc-3m)) - ("stex" ,(package-source stex)) - ("nanopass" ,(package-source chez-nanopass)))) - (arguments - `(#:phases - (modify-phases %standard-phases - (add-after 'unpack 'unpack-nanopass+stex - (lambda* (#:key inputs native-inputs #:allow-other-keys) - (with-directory-excursion "racket/src/ChezScheme" - ,unpack-nanopass+stex) - #t)) - (delete 'configure) - (delete 'patch-generated-file-shebangs) - (replace 'build - (lambda* (#:key inputs outputs #:allow-other-keys) - (with-directory-excursion "racket/src/ChezScheme" - (invoke (string-append (assoc-ref inputs "racket") - "/bin/racket") - "rktboot/main.rkt" - "--dest" (assoc-ref outputs "out"))) - #t)) - (delete 'check) - (delete 'install)))) - (synopsis "Chez Scheme bootfiles bootstrapped by Racket") - (description "Chez Scheme is a self-hosting compiler: building it -requires ``bootfiles'' containing the Scheme-implemented portions compiled for -the current platform. (Chez can then cross-compile bootfiles for all other -supported platforms.) - -The Racket package @code{cs-bootstrap} (part of the main Racket Git -repository) implements enough of a Chez Scheme simulation to load the Chez -Scheme compiler purely from source into Racket and apply the compiler to -itself, thus bootstrapping Chez Scheme. Bootstrapping takes about 10 times as -long as using an existing Chez Scheme, but @code{cs-bootstrap} supports Racket -7.1 and later, including the Racket BC variant. - -Note that the generated bootfiles are specific to Racket's fork of Chez -Scheme, and @code{cs-bootstrap} does not currently support building upstream -Chez Scheme.") - (license (list asl2.0))))) - - -(define %installer-mirrors - ;; Source: - ;; https://github.com/racket/racket-lang-org/blob/master/download/data.rkt#L58 - ;; Matthew Flatt says: "note that many are commented out" - ;; INVARIANT: End with a trailing "/"! - '("https://mirror.racket-lang.org/installers/" - "https://www.cs.utah.edu/plt/installers/" - "https://plt.cs.northwestern.edu/racket-mirror/" - "https://mirror.csclub.uwaterloo.ca/racket/racket-installers/" - ;; Universität Tübingen is using a self-signed HTTPS certificate: - "http://mirror.informatik.uni-tuebingen.de/mirror/racket/" - "https://racket.infogroep.be/" - )) - -(define %main-repo-main-distribution-pkgs - ;; These are the packages developed in the main Racket Git repository - ;; that are part of the main distribution. - '("at-exp-lib" - "base" - "compiler-lib" - ;; NOT "compiler-test" - "compiler" - "net-doc" - "net-lib" - ;; NOT "net-test" - "net" - ;; NOT "plt-services" - ;; NOT "racket-benchmarks" - ;; NOT "racket-build-guide" - "racket-doc" - "racket-index" - "racket-lib" - ;; NOT "racket-test-core" - ;; NOT "racket-test-extra" - ;; NOT "racket-test" - "zo-lib")) - + (license (list license:asl2.0 license:expat)))) (define-public racket (package (inherit racket-minimal) (name "racket") - (version (package-version racket-minimal)) ; needed for origin uri to work - (source - (origin - (method url-fetch) - (uri (map (lambda (base) - (string-append base version "/racket-src.tgz")) - %installer-mirrors)) - (sha256 - (base32 - "0jdr0y7scvv2a3sq456ifrgq0yfsbiwavdf2m86zmrapp481mby4")) - (snippet - #~(begin - (use-modules (guix build utils) - (ice-9 match) - (ice-9 regex)) - ;; unbundle minimal Racket - (for-each delete-file-recursively - '("collects" - "doc" - "etc" - "README" - "src")) - ;; unbundle package sources included elsewhere - (with-directory-excursion "share/pkgs" - (for-each delete-file-recursively - '#+%main-repo-main-distribution-pkgs)) - #t)))) + (source #f) (inputs - `(("cairo" ,cairo) - ("fontconfig" ,fontconfig) - ("glib" ,glib) - ("glu" ,glu) - ("gmp" ,gmp) - ("gtk+" ,gtk+) ; propagates gdk-pixbuf+svg - ("libjpeg" ,libjpeg-turbo) - ("libpng" ,libpng) - ("libx11" ,libx11) - ("mesa" ,mesa) - ("mpfr" ,mpfr) - ("pango" ,pango) - ("unixodbc" ,unixodbc) - ("libedit" ,libedit))) - (native-inputs - `(("racket" ,racket-minimal) - ("extend-layer" ,extend-layer) - ("main-repo" ,(package-source racket-minimal)))) + (list cairo + fontconfig + glib + glu + gmp + gtk+ ;; propagates gdk-pixbuf+svg + libjpeg-turbo + libpng + libx11 ;; ?? wayland ?? + mesa + mpfr + pango + unixodbc + libedit ;; TODO reconsider in light of expeditor and readline-gpl + racket-minimal ;; <-- TODO non-tethered layer + (racket-vm-for-system))) (arguments - `(#:phases - (modify-phases %standard-phases - (add-before 'configure 'unpack-packages - (let ((unpack (assoc-ref %standard-phases 'unpack))) - (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) - (let* ((racket (assoc-ref (or native-inputs inputs) "racket")) - (prefix (assoc-ref outputs "out")) - (pkgs-dir (string-append prefix "/share/racket/pkgs"))) - (mkdir-p pkgs-dir) - (copy-recursively - "share/links.rktd" - (string-append prefix "/share/racket/links.rktd")) - (copy-recursively "share/pkgs" pkgs-dir) - ;; NOTE: unpack changes the working directory - (unpack #:source (assoc-ref (or native-inputs inputs) - "main-repo")) - (for-each (lambda (pkg) - (define dest (string-append pkgs-dir "/" pkg)) - (mkdir-p dest) - (copy-recursively (string-append "pkgs/" pkg) - dest)) - ',%main-repo-main-distribution-pkgs) - #t)))) - (replace 'configure - (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) - (let ((racket (assoc-ref (or native-inputs inputs) "racket")) - (prefix (assoc-ref outputs "out"))) - (apply invoke - (string-append racket "/bin/racket") - (assoc-ref inputs "extend-layer") - racket - prefix - (map - (lambda (lib) - (string-append (assoc-ref inputs lib) "/lib")) - '("cairo" - "fontconfig" - "glib" - "glu" - "gmp" - "gtk+" - "libjpeg" - "libpng" - "libx11" - "mesa" - "mpfr" - "pango" - "unixodbc" - "libedit"))) - #t))) - (replace 'build - (lambda* (#:key native-inputs inputs outputs #:allow-other-keys) - (invoke (string-append (assoc-ref (or native-inputs inputs) - "racket") - "/bin/racket") - "--config" - (string-append (assoc-ref outputs "out") - "/etc/racket") - "-l" - "raco" - "setup") - #t)) - (delete 'install)) - ;; we still don't have these: - #:tests? #f)) + (substitute-keyword-arguments (package-arguments racket-minimal) + ((#:configure-flags _ '()) + #~`("--tethered" + "--extra-foreign-lib-search-dirs" + ,(format #f "~s" + '(#$@(map (lambda (name) + (cond + ((this-package-input name) + => (cut file-append <> "/lib")) + (else + (raise-exception + (make-exception + (make-assertion-failure) + (make-exception-with-message + "missing input to the 'racket' package") + (make-exception-with-irritants + (list name))))))) + '("cairo" + "fontconfig-minimal" ;; aka fontconfig + "glib" + "glu" + "gmp" + "gtk+" + "libjpeg-turbo" + "libpng" + "libx11" + "mesa" + "mpfr" + "pango" + "unixodbc" + "libedit")))))) + ((#:make-flags _ '()) + #~`("main-distribution")) + ((#:phases parent-phases #~%standard-phases) + #~(modify-phases #$parent-phases + (delete 'unpack) + (replace 'build + (lambda args + (mkdir-p (string-append #$output "/lib/racket/pkgs")) + (for-each + (match-lambda + ((name src) + (copy-recursively + src + (string-append #$output "/lib/racket/pkgs/" name)))) + '(#$@main-distribution-packages)))))))) (synopsis "Programmable programming language in the Scheme family") (description "Racket is a general-purpose programming language in the Scheme family, @@ -539,82 +224,900 @@ (define dest (string-append pkgs-dir "/" pkg)) DrRacket IDE, libraries for GUI and web programming, and implementations of languages such as Typed Racket, R5RS and R6RS Scheme, Algol 60, and Datalog."))) - -(define extend-layer +(define make-installation-layer.rkt (scheme-file - "extend-layer.rkt" + "make-installation-layer.rkt" `(module - extend-layer racket/base + make-installation-layer racket/base (require racket/cmdline racket/match racket/file + racket/port racket/list racket/pretty) - (define config-file-pth - "etc/racket/config.rktd") (define (build-path-string . args) (path->string (apply build-path args))) (define rx:racket ;; Guile's reader doesn't support #rx"racket" (regexp "racket")) - (command-line - #:args (parent-layer prefix . lib-dir*) - (let* ([config - (for/fold - ([config (file->value (build-path parent-layer - config-file-pth))]) - ([spec (in-list - '((lib-dir lib-search-dirs "lib/racket") - (share-dir share-search-dirs "share/racket") - (links-file - links-search-files - "share/racket/links.rktd") - (pkgs-dir pkgs-search-dirs "share/racket/pkgs") - (bin-dir bin-search-dirs "bin") - (man-dir man-search-dirs "share/man") - (doc-dir doc-search-dirs "share/doc/racket") - (include-dir - include-search-dirs - "include/racket")))]) - (match-define (list main-key search-key pth) spec) - (hash-set* - config - main-key - (build-path-string prefix pth) - search-key - (list* #f - (hash-ref config - main-key - (build-path-string parent-layer pth)) - (filter values (hash-ref config search-key null)))))] - [config - (hash-set config - 'apps-dir - (build-path-string prefix "share/applications"))] - [config - ;; place new foreign lib-search-dirs before old - ;; foreign dirs, but after Racket layers - (let-values - ([(rkt extra) - (partition (lambda (pth) - (or (not pth) - (regexp-match? rx:racket pth))) - (hash-ref config 'lib-search-dirs))]) - (hash-set config + (define tethered? #f) + (define parent #f) + (define extra-foreign-lib-search-dirs '()) + (define-values [vm-dir prefix] + (command-line + #:once-each + [("--tethered") "create a tethered layer" + (set! tethered? #t)] + [("--parent") dir "path of parent layer, if any" + (set! parent dir)] + [("--extra-foreign-lib-search-dirs") dir-list + "foreign library directories, as a list of strings in `read` syntax" + (set! extra-foreign-lib-search-dirs + (call-with-input-string dir-list read))] + #:args (vm-dir prefix) + (values vm-dir prefix))) + (let* ([config + (for/fold + ([config (file->value + (if parent + (build-path parent "etc/racket/config.rktd") + (build-path vm-dir "etc/config.rktd")))]) + ([spec + (in-list + '((lib-dir lib-search-dirs "lib/racket" "lib") + (share-dir share-search-dirs "share/racket" "share") + (links-file links-search-files + "lib/racket/links.rktd" + "share/links.rktd") + (pkgs-dir pkgs-search-dirs "lib/racket/pkgs" "share/pkgs") + ;; Partial workaround for: + ;; https://github.com/racket/racket/issues/4133 + #;(bin-dir bin-search-dirs "bin" "bin") + (bin-dir bin-search-dirs "unused-untethered-bin" "bin") + (man-dir man-search-dirs "share/man" "share/man") + (doc-dir doc-search-dirs "share/doc/racket" "doc") + (include-dir include-search-dirs + "include/racket" + "include")))]) + (match-define (list main-key search-key pth vm-pth) spec) + (hash-set* + config + main-key + (build-path-string prefix pth) + search-key + (list* #f + (hash-ref config + main-key + (lambda () + (if parent + (build-path-string parent pth) + (build-path-string vm-dir vm-pth)))) + (filter values (hash-ref config search-key null)))))] + [config + (hash-update config 'lib-search-dirs - (append rkt - lib-dir* - extra)))] - [bin-dir - (hash-ref config 'bin-dir)] - [config - (hash-set* config - 'config-tethered-console-bin-dir bin-dir - 'config-tethered-gui-bin-dir bin-dir)] - [new-config-pth - (build-path prefix config-file-pth)]) - (make-parent-directory* new-config-pth) - (call-with-output-file* - new-config-pth - (lambda (out) - (pretty-write config out)))))))) + (lambda (dirs) + ;; add after other layers, but before older + ;; foreign lib search directories + (define-values [rkt old-foreign-dirs] + (partition (lambda (pth) + (or (not pth) + (regexp-match? rx:racket pth))) + dirs)) + (append rkt + extra-foreign-lib-search-dirs + old-foreign-dirs)))] + [config + (hash-set* config + 'apps-dir + (build-path-string prefix "share/applications") + 'absolute-installation? #t + ;; Let Guix coexist with other installation + ;; methods without clobbering user-specific packages + ;; This could be set in various places, but doing + ;; it here is convienient, at least until we support + ;; cross-compilation. + 'installation-name + (string-append (version) + "-guix" + (match (system-type 'gc) + ['cgc "-cgc"] + ;; workaroung Guile reader/printer: + ['|3m| "-bc"] + [_ ""])))] + [config + (cond + [tethered? + ;; Partial workaround for: + ;; https://github.com/racket/racket/issues/4133 + #;(define bin-dir (hash-ref config 'bin-dir)) + (define bin-dir (build-path-string prefix "bin")) + (hash-set* config + 'config-tethered-apps-dir (hash-ref config 'apps-dir) + 'config-tethered-console-bin-dir bin-dir + 'config-tethered-gui-bin-dir bin-dir)] + [else + config])]) + (define new-config-pth + (build-path prefix "etc/racket/config.rktd")) + (make-parent-directory* new-config-pth) + (call-with-output-file* + new-config-pth + (lambda (out) + (pretty-write config out))))))) + +(define-public main-distribution-packages + (let* ((%racket-version (package-version (racket-vm-for-system))) + (%racket-commit (string-append "v" %racket-version))) + ;; on release, commit will be %racket-commit + (append-map + (match-lambda + ((source . pkgs) + (map (match-lambda + ((? string? name) + (list name (file-append source (string-append "/" name)))) + ((name ".") + (list name source)) + ((name rel-path) + (list name (file-append source (string-append "/" rel-path))))) + pkgs))) + `((,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/2d") + (commit %racket-commit))) + (sha256 (base32 + "1zzcz5qyjv7syi41vb8jkxjp1rqgj61zbsdrg0nlc4qy9qsafzgr")) + (file-name + (git-file-name "racket-2d" %racket-version))) + "2d" "2d-doc" "2d-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/algol60") + (commit %racket-commit))) + (sha256 (base32 + "09kj6asypmc24n29w0izc9p0q8hpga2hpkchsypfwn5c8zpvihlx")) + (file-name + (git-file-name "racket-algol60" %racket-version))) + ("algol60" ".")) + (,(package-source (racket-vm-for-system)) + ("at-exp-lib" "pkgs/at-exp-lib") + ("compiler" "pkgs/compiler") + ("compiler-lib" "pkgs/compiler-lib") + ("net" "pkgs/net") + ("net-doc" "pkgs/net-doc") + ("net-lib" "pkgs/net-lib") + ("racket-doc" "pkgs/racket-doc") + ("racket-index" "pkgs/racket-index") + ("sandbox-lib" "pkgs/sandbox-lib") + ("zo-lib" "pkgs/zo-lib")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/cext-lib") + (commit %racket-commit))) + (sha256 (base32 + "00w38jpv88fpl4pgj6ndnysvn0s21rjvj0xhznay80msan0vc341")) + (file-name (git-file-name "racket-cext-lib" %racket-version))) + "cext-lib" "dynext-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/class-iop") + (commit %racket-commit))) + (sha256 (base32 + "08z57q83cr7wnh6g8ah3hdhmsmf9zp1jfs7yvxv188l3hzvygy5l")) + (file-name (git-file-name "racket-class-iop" %racket-version))) + "class-iop-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/compatibility") + (commit "37f11132cdad7ef27386b68383d073f275d67c31"))) + (sha256 (base32 + "0bfqwscjpyi325br5pa6g62g9c8lq18a80zp5g3d2qzn3n3mi6x0")) + (file-name (git-file-name "racket-compatibility" %racket-version))) + "compatibility" "compatibility-doc" "compatibility-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/contract-profile") + (commit "95d980a076126b8e4e4284e912f2a7d9d3ab6860"))) + (sha256 (base32 + "1xm2z8g0dpv5d9h2sg680vx1a8ix9gbsdpxxb8qv1w7akp73paj3")) + (file-name + (git-file-name "racket-contract-profile" %racket-version))) + ("contract-profile" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/data") + (commit "e32d012b394e32e102e8a9adfcc885bb0541ab51"))) + (sha256 (base32 + "10iabgrk9alaggvksnyb0hdq7f1p30pq6pq2bcakvhzpxwiv1f55")) + (file-name (git-file-name "racket-data" %racket-version))) + "data" "data-doc" "data-enumerate-lib" "data-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/datalog") + (commit "7d160a86451af8298093d07674a2eb0e1a0161a4"))) + (sha256 (base32 + "0n5j5gnqh7g31mvgx19ggl18hirzbvq2r189lbngmnrmbc7b73fp")) + (file-name (git-file-name "racket-datalog" %racket-version))) + ("datalog" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/db") + (commit %racket-commit))) + (sha256 (base32 + "1n02ja0yj3mjjhmz0yv04yfhyvrsznbljn8bjviyfxnm4xf9rcc5")) + (file-name (git-file-name "racket-db" %racket-version))) + "db" "db-doc" "db-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/deinprogramm") + (commit %racket-commit))) + (sha256 (base32 + "1is6fapgv6rxfjz47nh6qf3kh7y7sjdinakaxqffi46gf1al8prd")) + (file-name (git-file-name "racket-deinprogramm" %racket-version))) + "deinprogramm" "deinprogramm-signature") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/distributed-places") + (commit %racket-commit))) + (sha256 (base32 + "1dajpkj9balqcpv6cdk9hwjz592h1vq8rrx5vncariiac4vbdpa0")) + (file-name + (git-file-name "racket-distributed-places" %racket-version))) + "distributed-places" "distributed-places-doc" "distributed-places-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/draw") + (commit %racket-commit))) + (sha256 (base32 + "1xgjfbh70hqw67z88iqqajg98d04qwbzn6im2wj47rs28jxlm9ly")) + (file-name (git-file-name "racket-draw" %racket-version))) + "draw" "draw-doc" "draw-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/drracket") + (commit %racket-commit))) + (sha256 (base32 + "0m3l4an3nq2ycd1h287s1az2v2zprjbzd8if2x7d5r71vaj4i00c")) + (file-name (git-file-name "racket-drracket" %racket-version))) + "drracket" + "drracket-plugin-lib" + "drracket-tool" + "drracket-tool-doc" + "drracket-tool-lib" + "drracket-tool-text-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/ds-store") + (commit "949ca63dd00522b3ab8aec2d71c543ece8266872"))) + (sha256 (base32 + "0ajr27kipp4dr1qlisaghsb3h7lhhjwrfw2r79b5myczsa1mp661")) + (file-name (git-file-name "racket-ds-store" %racket-version))) + "ds-store" "ds-store-doc" "ds-store-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/eli-tester") + (commit "036e07d43a1f478ea1750881d5591d983ce1ffaf"))) + (sha256 (base32 + "0icx6wn14gjm8kdmq1jppqgq87sxkras4qb5xmdr6wigxafhjqyk")) + (file-name (git-file-name "racket-eli-tester" %racket-version))) + ("eli-tester" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/eopl") + (commit %racket-commit))) + (sha256 (base32 + "1fmiixj6rxsgzwvgva8lvrvv0gl49v2405mp3s0i7ipis5c4n27s")) + (file-name (git-file-name "racket-eopl" %racket-version))) + ("eopl" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/errortrace") + (commit %racket-commit))) + (sha256 (base32 + "14m7rhaxngj36070iw15am434hm438pfgmwjfsiqhsglz4pcxhip")) + (file-name (git-file-name "racket-errortrace" + (package-version (racket-vm-for-system))))) + "errortrace" "errortrace-doc" "errortrace-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/expeditor") + (commit %racket-commit))) + (sha256 (base32 + "07djzxs6307l51mcsk3yr2g4g47ayxa3878g7sf5xhqdr4hd9vxf")) + (file-name (git-file-name "racket-expeditor" %racket-version))) + "expeditor" "expeditor-doc" "expeditor-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/frtime") + (commit %racket-commit))) + (sha256 (base32 + "0ydz2yn8vvv6z7brwlswcyx0f31a6y6d443i89rysfvd2xkhpfd5")) + (file-name (git-file-name "racket-frtime" %racket-version))) + ("frtime" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/future-visualizer") + (commit %racket-commit))) + (sha256 (base32 + "1758qq769m0r14xf64sl2ix2l9z340kvapar0j7s5kdg42lmvnhm")) + (file-name + (git-file-name "racket-future-visualizer" %racket-version))) + "future-visualizer" "future-visualizer-pict" "future-visualizer-typed") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/games") + + (commit %racket-commit))) + (sha256 (base32 + "0kpn3izlx1ccd0pj0dnvmnrhny51b85xy418a7psj70lz8j8415d")) + (file-name (git-file-name "racket-games" %racket-version))) + ("games" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/gui") + (commit %racket-commit))) + (sha256 (base32 + "1x33jgrx3r32k7hgwr591z3xqv1m2r5nc4km2fnxv0ak2xa0j3gj")) + (patches + ;; remove in Racket 8.5 + ;; see https://github.com/racket/racket/issues/4133 + (search-patches "racket-gui-tethered-launcher-backport.patch")) + (file-name (git-file-name "racket-gui" %racket-version))) + "gui" "gui-doc" "gui-lib" "tex-table") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/gui-pkg-manager") + (commit %racket-commit))) + (sha256 (base32 + "1ji9448d723nklqvycwdswj0ni28sabrncag14f9mx47did5myb5")) + (file-name + (git-file-name "racket-gui-pkg-manager" %racket-version))) + "gui-pkg-manager-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/htdp") + (commit %racket-commit))) + (sha256 (base32 + "0r4ykybcpr10y2db9rlza9pr0xh58nd7ac389mjcxp8g386hgihl")) + (file-name (git-file-name "racket-htdp" %racket-version))) + "htdp" "htdp-doc" "htdp-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/html") + (commit %racket-commit))) + (sha256 (base32 + "18n1jnjgzfknc8nv8dppi85nb8q08gqdwkg6hfjk08x0p00anx2x")) + (file-name (git-file-name "racket-html" %racket-version))) + "html" "html-doc" "html-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/icons") + (commit %racket-commit))) + (sha256 (base32 + "1s5a6j11fg3fdr6b7vm2q7q178d7q8b8igy73bs211r27qrd1gg7")) + (file-name (git-file-name "racket-icons" %racket-version))) + ("icons" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/images") + (commit %racket-commit))) + (sha256 (base32 + "0rpjxqw34bq5m08kh1ldl1mr7s9z1lyydxxcyzb292kqh9qiqvfl")) + (file-name (git-file-name "racket-images" %racket-version))) + "images" "images-doc" "images-gui-lib" "images-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/lazy") + (commit %racket-commit))) + (sha256 (base32 + "176ylzgbdsbmqknpihaz519afq71pyjkv1h87j5v8jfbpbddyfsf")) + (file-name (git-file-name "racket-lazy" %racket-version))) + ("lazy" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/macro-debugger") + (commit %racket-commit))) + (sha256 (base32 + "14hyrwbkffr61fk44l02xb47bhv5zccw0ymaa9kxld86hvyqhqbm")) + (file-name (git-file-name "racket-macro-debugger" %racket-version))) + "macro-debugger" "macro-debugger-text-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/main-distribution") + (commit %racket-commit))) + (sha256 (base32 + "0m2n9s32s8a4a2gn4ywrm9l8jycdm5ayi5w9kh5wchhrrw7qzq7y")) + (file-name + (git-file-name "racket-main-distribution" %racket-version))) + ("main-distribution" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/make") + (commit %racket-commit))) + (sha256 (base32 + "10852fj30bz5r46c3d99s37fkgy5yh44gb01j29sf3kxnhi0g2sa")) + (file-name (git-file-name "racket-make" %racket-version))) + ("make" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/math") + (commit %racket-commit))) + (sha256 (base32 + "02sqbnvxvmvslk33b44fx4v93zafcvhva0cx8z21jqbl5wp217ac")) + (file-name (git-file-name "racket-math" %racket-version))) + "math" "math-doc" "math-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/mysterx") + (commit %racket-commit))) + (sha256 (base32 + "11p9jzrafw0hizhl0cs4sxx7rv281185q8hryic2rpk0kzjdyr48")) + (file-name (git-file-name "racket-mysterx" %racket-version))) + ("mysterx" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/mzcom") + (commit %racket-commit))) + (sha256 (base32 + "0rc9pfj7gwm5azghqvcibz6si1x5s2v8mr2yngk7ssq9gzfbi6a4")) + (file-name (git-file-name "racket-mzcom" %racket-version))) + ("mzcom" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/mzscheme") + (commit %racket-commit))) + (sha256 (base32 + "192c52zi726h5wjamxrhivjw2waq1im0zpyxhbrkrxknm8x84bs9")) + (file-name (git-file-name "racket-mzscheme" %racket-version))) + "mzscheme" "mzscheme-doc" "mzscheme-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/RenaissanceBug/racket-cookies") + (commit %racket-commit))) + (sha256 (base32 + "0k0hifxhywl5c3hjcaiizc098dpyk001d981p572gly116yvjxc1")) + (file-name + (git-file-name "RenaissanceBug-racket-cookies" %racket-version))) + "net-cookies" "net-cookies-doc" "net-cookies-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/stamourv/optimization-coach") + (commit %racket-commit))) + (sha256 (base32 + "0b27sw48d7rhz0hin88c7rbr9vpg1c23sn82nd4jkmq54h6gasr1")) + (file-name + (git-file-name "stamourv-optimization-coach" %racket-version))) + ("optimization-coach" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/option-contract") + (commit %racket-commit))) + (sha256 (base32 + "026b7n5l0c3024nymshz8zp1yhn493rdzgpflzfd52hj7awafqhk")) + (file-name + (git-file-name "racket-option-contract" %racket-version))) + "option-contract" "option-contract-doc" "option-contract-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/parser-tools") + (commit %racket-commit))) + (sha256 (base32 + "08pvz4zramirzm3j64hbhjm0mmh5zfy37iv4s3vmq0rj49cr8fl3")) + (file-name (git-file-name "racket-parser-tools" %racket-version))) + "parser-tools" "parser-tools-doc" "parser-tools-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/pconvert") + (commit %racket-commit))) + (sha256 (base32 + "00czi0p399mmyrvxyrs5kniizpkqfxyz2ncxqi2jy79a7wk79pb1")) + (file-name (git-file-name "racket-pconvert" %racket-version))) + "pconvert-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/pict") + (commit %racket-commit))) + (sha256 (base32 + "0g1iwdr6qh1xb0crhj96830vjjnbds409xbpqn7j5sh0ksy6vr5x")) + (file-name (git-file-name "racket-pict" %racket-version))) + "pict" "pict-doc" "pict-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/pict-snip") + (commit %racket-commit))) + (sha256 (base32 + "081nwiy4a0n4f7xws16hqbhf0j3kz5alizndi3nnyr3chm4kng6x")) + (file-name (git-file-name "racket-pict-snip" %racket-version))) + "pict-snip" "pict-snip-doc" "pict-snip-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/picturing-programs") + (commit %racket-commit))) + (sha256 (base32 + "1g6xr39hx1j03gb3d4dljm3v91xcj2gfpq3dgy5xvplzr6cmmxgr")) + (file-name + (git-file-name "racket-picturing-programs" %racket-version))) + ("picturing-programs" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/plai") + (commit %racket-commit))) + (sha256 (base32 + "0i983sh0r0zm2ng4j44m5aw9669kh5fhp91bzpc9jm280rfcqvyl")) + (file-name (git-file-name "racket-plai" %racket-version))) + "plai" "plai-doc" "plai-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/planet") + (commit %racket-commit))) + (sha256 (base32 + "0r2yqrzrmdjjyr14k6hhlzc5kzrcx3583m1s02mhrcmpfw0s85w9")) + (file-name (git-file-name "racket-planet" %racket-version))) + "planet" "planet-doc" "planet-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/plot") + (commit %racket-commit))) + (sha256 (base32 + "07kq32si34ybcwz8idxxcrzssg8diyrp1nfgkcj0mmvr45321zm7")) + (file-name (git-file-name "racket-plot" %racket-version))) + "plot" "plot-compat" "plot-doc" "plot-gui-lib" "plot-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/preprocessor") + (commit %racket-commit))) + (sha256 (base32 + "1p5aid58ifnjy4xl0ysh85cq39k25661v975jrpk182z3k5621mg")) + (file-name (git-file-name "racket-preprocessor" %racket-version))) + ("preprocessor" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/profile") + (commit %racket-commit))) + (sha256 (base32 + "179i86lyby29nywz60l4vnadi02w8b12h7501nm5h5g4pq9jjmbb")) + (file-name (git-file-name "racket-profile" %racket-version))) + "profile" "profile-doc" "profile-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/Metaxal/quickscript") + (commit %racket-commit))) + (sha256 (base32 + "100g3yqhbjdq06b6l6d72ywsw29awgy8crqg33wj7h12xq07nzcr")) + (file-name (git-file-name "Metaxal-quickscript" %racket-version))) + ("quickscript" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/r5rs") + (commit %racket-commit))) + (sha256 (base32 + "1g3cysj7z88r38vkzvi8g2fb2hn4yg1fdhy5smxw303jxgl3inp6")) + (file-name (git-file-name "racket-r5rs" %racket-version))) + "r5rs" "r5rs-doc" "r5rs-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/r6rs") + (commit %racket-commit))) + (sha256 (base32 + "0b1ymzdp10r0flw2acbidjsh5ma1pm5hy54jss37sxf89z3xbvm4")) + (file-name (git-file-name "racket-r6rs" %racket-version))) + "r6rs" "r6rs-doc" "r6rs-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/jeapostrophe/racket-cheat") + (commit %racket-commit))) + (sha256 (base32 + "06wcj558rzkbl2bwkmikyspya9v1f4iwlzwnwxpkc33h2xapwabr")) + (file-name + (git-file-name "jeapostrophe-racket-cheat" %racket-version))) + ("racket-cheat" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/racklog") + (commit %racket-commit))) + (sha256 (base32 + "1rgrvwy3kr9b9w5cghsffiv3ly00yfvvzr5xaaw83g1w7yin0mnb")) + (file-name (git-file-name "racket-racklog" %racket-version))) + ("racklog" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/rackunit") + (commit %racket-commit))) + (sha256 (base32 + "057z31rja6h3nabh5b2xgwfrzmlm6h1cv1qcgf3xfy4g2q5dqn5p")) + (file-name (git-file-name "racket-rackunit" %racket-version))) + "rackunit" + "rackunit-doc" + "rackunit-gui" + "rackunit-lib" + "rackunit-plugin-lib" + "rackunit-typed" + "schemeunit" + "testing-util-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/readline") + (commit %racket-commit))) + (sha256 (base32 + "13kbcn2wchv82d709mw3r8n37bk8iwq0y4kpvm9dbzx0w2pxkfwn")) + (file-name (git-file-name "racket-readline" %racket-version))) + "readline" "readline-doc" "readline-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/realm") + (commit %racket-commit))) + (sha256 (base32 + "0hxcgla08iack54j8v40fj51811chpy66ym2zq76zb52c7kzn0hi")) + (file-name (git-file-name "racket-realm" %racket-version))) + ("realm" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/redex") + (commit %racket-commit))) + (sha256 (base32 + "0vlgxbnbgrlihk1hh5zd6hsc4566ldi4q76f87z5vai54dxkwy2f")) + (file-name (git-file-name "racket-redex" %racket-version))) + "redex" + "redex-benchmark" + "redex-doc" + "redex-examples" + "redex-gui-lib" + "redex-lib" + "redex-pict-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/sasl") + (commit %racket-commit))) + (sha256 (base32 + "0ibh4wb4gn8pggx6gkv4vk4d6rwzn5nrvjibhvkzhaynf6lhb824")) + (file-name (git-file-name "racket-sasl" %racket-version))) + "sasl" "sasl-doc" "sasl-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/scheme-lib") + (commit %racket-commit))) + (sha256 (base32 + "0pcf0y8rp4qyjhaz5ww5sr5diq0wpcdfrrnask7zapyklzx1jx8x")) + (file-name (git-file-name "racket-scheme-lib" %racket-version))) + ("scheme-lib" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/scribble") + (commit %racket-commit))) + (sha256 (base32 + "0rgvnsykrxkah6s5fw1vyp9lxsb4z9w6hgwk5j6wbwjp2gsfczbm")) + (file-name (git-file-name "racket-scribble" %racket-version))) + "scribble" + "scribble-doc" + "scribble-html-lib" + "scribble-lib" + "scribble-text-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/serialize-cstruct-lib") + (commit %racket-commit))) + (sha256 (base32 + "1rq3n1fa7ldjwx3lrh9ybhig7jlsw1crpzyklbzp3xqdw6jymfnz")) + (file-name + (git-file-name "racket-serialize-cstruct-lib" %racket-version))) + ("serialize-cstruct-lib" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/sgl") + (commit %racket-commit))) + (sha256 (base32 + "0nkymhdyjrwi5h199j4w5zh7y3x3ai42gsiwxzh0hy7yqrqqg9zv")) + (file-name (git-file-name "racket-sgl" %racket-version))) + ("sgl" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/shell-completion") + (commit %racket-commit))) + (sha256 (base32 + "04m144gy2mp4fiq6rcbf12wjr8mws8k9scfhg9lc38vqppp4lxsj")) + (file-name + (git-file-name "racket-shell-completion" %racket-version))) + ("shell-completion" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/simple-tree-text-markup") + (commit %racket-commit))) + (sha256 (base32 + "0fyd9gfz6bnv0m1901wv5mnhc05rm8hw9i6ddrqx33hs6qsg2zqr")) + (file-name + (git-file-name "racket-simple-tree-text-markup" %racket-version))) + "simple-tree-text-markup" + "simple-tree-text-markup-doc" + "simple-tree-text-markup-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/slatex") + (commit "47e1d3e3e33d826bc2b26f9e8998eb235b23a9a5"))) + (sha256 (base32 + "0pkm2isbbdk63slrbsxcql7rr0wdrw5kapw1xq4ps5k8dhlzv8x0")) + (file-name (git-file-name "racket-slatex" %racket-version))) + ("slatex" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/slideshow") + (commit %racket-commit))) + (sha256 (base32 + "1znv1i2d0610hhy71q932xy7wka00q3q50in1xfnk8ibg7nzkagm")) + (file-name (git-file-name "racket-slideshow" %racket-version))) + "slideshow" "slideshow-doc" "slideshow-exe" "slideshow-lib" + "slideshow-plugin") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/snip") + (commit %racket-commit))) + (sha256 (base32 + "01r9wc5xr3q3n4yyif6j0a37rgdzmpslxn05k13ksik73b3wj6hj")) + (file-name (git-file-name "racket-snip" %racket-version))) + "snip" "snip-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/typed-racket") + (commit %racket-commit))) + (sha256 (base32 + "1462kj9yswsxbnw71casylzlvhd7cxrml2v9j7rcsnn9hmrqx4vv")) + (file-name (git-file-name "racket-typed-racket" %racket-version))) + "source-syntax" + "typed-racket" + "typed-racket-compatibility" + "typed-racket-doc" + "typed-racket-lib" + "typed-racket-more") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/srfi") + (commit %racket-commit))) + (sha256 (base32 + "0cga4ijid6lg5j68cvdfs4xr69rsyzw7d7lixr3i866kran61sys")) + (patches + ;; remove in Racket 8.5 + ;; see https://github.com/racket/srfi/pull/15 + (search-patches "racket-srfi-fsdg-backport.patch")) + (file-name (git-file-name "racket-srfi" %racket-version))) + "srfi" "srfi-doc" "srfi-lib" "srfi-lite-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/string-constants") + (commit %racket-commit))) + (sha256 (base32 + "1qizjq4n0hzdgdcjjpr94464gsywpsk2g9mnvwzqr7dcqbrsfvn6")) + (file-name + (git-file-name "racket-string-constants" %racket-version))) + "string-constants" "string-constants-doc" "string-constants-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/swindle") + (commit %racket-commit))) + (sha256 (base32 + "164gdsphjzdl2vv7zxz7dfk9jwax8njpmim6sidm8qz8a8589y67")) + (file-name (git-file-name "racket-swindle" %racket-version))) + ("swindle" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/syntax-color") + (commit %racket-commit))) + (sha256 (base32 + "1vf2fc3qvx8a1igi7swsg8gaqhx786sa0vqxd18xhbsidfgb5ywp")) + (file-name (git-file-name "racket-syntax-color" %racket-version))) + "syntax-color" "syntax-color-doc" "syntax-color-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/trace") + (commit %racket-commit))) + (sha256 (base32 + "070ihla5j796hdarn5wxdwn4xj0xnkm50shgh49jy994mribvhia")) + (file-name (git-file-name "racket-trace" %racket-version))) + ("trace" ".")) + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/unix-socket") + (commit %racket-commit))) + (sha256 (base32 + "02dfwas5ynbpyz74w9kwb4wgb37y5wys7svrlmir8k0n9ph9vq0y")) + (file-name (git-file-name "racket-unix-socket" %racket-version))) + "unix-socket" "unix-socket-doc" "unix-socket-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/web-server") + (commit %racket-commit))) + (sha256 (base32 + "1zgb6jl7zx6258ljs8f3lvryrq5n5zpd71dqzr698m92kw3x2pkn")) + (file-name (git-file-name "racket-web-server" %racket-version))) + "web-server" "web-server-doc" "web-server-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/wxme") + (commit %racket-commit))) + (sha256 (base32 + "1qp5gr9gqsakiq3alw6m4yyv5vw4i3hp4y4nhq8vl2nkjmirvn0b")) + (file-name (git-file-name "racket-wxme" %racket-version))) + "wxme" "wxme-lib") + (,(origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/racket/xrepl") + (commit %racket-commit))) + (sha256 (base32 + "12zjgsy5zqm3fck3ihg4a70wj56s2cnnjyb4jlfi5nnsfqyrnxg3")) + (file-name (git-file-name "racket-xrepl" %racket-version))) + "xrepl" "xrepl-doc" "xrepl-lib")))))