by Wolfgang Corcoran-Mathe
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.
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.
None at present.
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)).
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.
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.
(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.
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"
A sample implementation in portable R6RS Scheme is available in the SRFI repository.
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.
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.