277: Cyclic ports

by Wolfgang Corcoran-Mathe

Status

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

Abstract

Cyclic ports are like infinite string and bytevector input ports: they produce the elements of a given sequence repeatedly, forever. While their intended use is as reusable seeds for SRFI 271 random ports, they are also useful whenever a repeating sequence of one or more bytes or characters is needed.

Table of contents

Issues

None at present.

Rationale

The motivation for this SRFI was a feature missing from SRFI 271: the ability to create, on different runs of a program or test suite, a random port that produces the same sequence each time. While SRFI 271 allows the state of a random port to be retrieved and stored, there is no guarantee that state formats will be stable across libraries and versions. A state saved during one run might not be valid on another run (perhaps on a different implementation). SRFI 271 provides no solution to this problem.

But a key requirement of SRFI 271, namely that random ports initialized from identical sequences have the same initial states, makes a solution possible in the form of cyclic ports. The same sequence can be used to initialize several random ports by passing each a cyclic port for that sequence. Since cyclic ports are (conceptually) infinite, there is no danger of running out of “seed” data. Thus a cyclic port can initialize any random port, regardless of how much seed data that port’s pseudorandom generation algorithm requires.

Cyclic ports have other uses. It is sometimes useful to have an endless source of a specific byte or characters. UNIX-like systems traditionally provide a /dev/zero file which produces an infinite stream of zeros. This is emulated portably by (open-cyclic-input-bytevector #u8(0)).

Why not cyclic generators?

SRFI 158 provides circular-generator, which constructs a simple infinite generator (nullary procedure) from its arguments. Although it cannot construct a cyclic generator from a string or bytevector directly, circular-generator provides a facility similar to cyclic ports. Unlike SRFI 158 generators, however, cyclic ports have the virtue of being ordinary input ports, which makes them suitable arguments to all of the standard port-reading procedures. The interface provided by this SRFI is also much closer to the the well-known string and bytevector port interfaces of R6RS and R7RS.

Specification

The terms “must”, “may”, etc. should be interpreted according to RFC 2119. In this SRFI they are written with strong emphasis.

The phrase “the behavior is undefined” is used in the sense given it in the ISO C programming-language standards (see e.g. C23 §3.5.3). In cases of undefined behavior, this SRFI imposes no requirements. Possible behaviors include signaling an error, handling the situation with an implementation-defined extension, or failing catastrophically.

Procedures

(open-cyclic-input-string string) → textual-input-port

Returns a new textual input port that delivers characters from string in order, repeatedly, forever. More precisely, if string consists of the characters c0, …, cn, then the returned port shall produce the conceptually infinite sequence c0, …, cn, c0, …, cn, ….

Reading from the returned port must not produce an EOF object. If string is empty, then the behavior is undefined.

(open-cyclic-input-bytevector bytevector) → binary-input-port

Returns a new binary cyclic port that delivers bytes from bytevector in order, repeatedly, forever. More precisely, if bytevector consists of the numbers b0, …, bn, then the returned port shall produce the conceptually infinite sequence b0, …, bn, b0, …, bn, ….

Reading from the returned port must not produce an EOF object. If bytevector is empty, then the behavior is undefined.

Examples

This section is informational.

(let ((p (open-cyclic-input-bytevector #u8(1 2 3 4))))
  (read-bytevector 6 p))
⇒ #u8(1 2 3 4 1 2)

(let ((p (open-cyclic-input-string "frob")))
  (read-string 8 p))
⇒ "frobfrob"

Implementation

A sample implementation in portable R6RS Scheme is available in the SRFI repository.

Acknowledgements

Thanks to Peter McGoron, John Cowan, and Shiro Kawai for suggesting the cyclic port concept.

Thanks to those who provided feedback via the SRFI mailing list or on the #scheme IRC channel.

Of course, none of the above should be taken to suggest that any of these people endorse the final draft of this SRFI.

References

S. Bradner, Key words for use in RFCs to Indicate Requirement Levels (RFC 2119), 1997. https://datatracker.ietf.org/doc/html/rfc2119

Michael Sperber, R. Kent Dybvig, Matthew Flatt, & Anton van Straaten, eds., Revised6 Report on the Algorithmic Language Scheme (R6RS), 2007. https://r6rs.org.

Alex Shinn, John Cowan, & Arthur A. Gleckler, eds., Revised7 Report on the Algorithmic Language Scheme (R7RS Small), 2013. https://small.r7rs.org

ISO/IEC 9899:2024. Programming languages — C (C23). ISO/IEC, 2024.

Shiro Kawai, John Cowan, and Thomas Gilray. SRFI 158: Generators and Accumulators. https://srfi.schemers.org/srfi-158/, 2017.

Wolfgang Corcoran-Mathe. SRFI 271: Random port libraries. https://srfi.schemers.org/srfi-271/, 2026. (draft)

© 2026 Wolfgang Corcoran-Mathe.

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 (including the next paragraph) 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: Arthur A. Gleckler