本译作采用许可协议 署名非商业性使用相同方式共享 4.0 国际 (CC BYNCSA 4.0) 进行授权和传播， 转载需注明译文来源，且不得将本译作内容用于商业用途！
本书由 flytreeleft (flytreeleft@crazydan.org) 翻译并校对。
R. Kent Dybvig / Scheme 编程语言（第四版）
版权 © 2009 MIT 出版社。 经许可以电子方式复制。
插画 © 2009 JeanPierre Hébert
ISBN 9780262512985 / LOC QA76.73.S34D93
订购此书 / 关于此书
https://www.scheme.com
前言
Scheme was introduced in 1975 by Gerald J. Sussman and Guy L. Steele Jr. ([28],[29]), and was the first dialect of Lisp to fully support lexical scoping, firstclass procedures, and continuations. In its earliest form it was a small language intended primarily for research and teaching, supporting only a handful of predefined syntactic forms and procedures. Scheme is now a complete generalpurpose programming language, though it still derives its power from a small set of key concepts. Early implementations of the language were interpreterbased and slow, but some current Scheme implementations boast sophisticated compilers that generate code on par with code generated by the best optimizing compilers for lowerlevel languages such as C and Fortran.
Scheme 是由 Gerald J. Sussman 和 Guy L. Steele Jr. 于 1975 年提出的（[28]、[29]）， 是首个完全支持 词法作用域（Lexical Scoping）、处理过程优先（Firstclass Procedure） 和 延续（Continuation）的 Lisp 方言。 在最早的版本中，它只是一门小型语言，主要用于研究和教学，仅支持少数预定义的 语法形式 和 处理过程。 虽然它的强大之处仍然源自于一小部分关键概念，但 Scheme 现在已经是一门完全通用的编程语言了。 该语言的早期实现是基于解释器的，运行缓慢，而如今的一些 Scheme 实现拥有复杂巧妙的编译器， 它们生成的代码与为较低级语言（如 C 和 Fortran ）进行最佳优化的编译器所生成的代码不相上下。
译注
可以从文章 柯里化的前生今世（七）：firstclass continuation、 Scheme 的 call/cc 中初步了解 处理过程优先、延续 等概念。 
This book is intended to provide an introduction to the Scheme programming language but not an introduction to programming in general. The reader is expected to have had some experience programming and to be familiar with terms commonly associated with computers and programming languages. Readers unfamiliar with Scheme or Lisp should also consider reading The Little Schemer [13] to become familiar with the concepts of list processing and recursion. Readers new to programming should begin with an introductory text on programming.
本书旨在介绍 Scheme 编程语言，而不是一般的编程入门。 读者需具备一定的编程经验，并且熟悉与计算机和编程语言相关的常用术语。 对 Scheme 或 Lisp 不熟悉的读者，应该读一读 The Little Schemer [13] 以熟悉 列表处理 和 递归 这些概念。 而对于初学编程的读者，则应该先阅读一些编程的入门内容。
Scheme has been standardized both formally and informally. The IEEE Standard for the Scheme Programming Language [18], describes a formal ANSI/IEEE Standard for Scheme but dates back to 1991. A related series of reports, the "Revised Reports on the Algorithmic Language Scheme," document an evolving informal standard that most implementations support. The current report in this series is the "Revised^{6} Report on the Algorithmic Language Scheme" [24], which was completed in 2007.
Scheme 已经被正式和非正式地标准化了。 《Scheme 编程语言 IEEE 标准》[18] 描述了一个正式的 Scheme ANSI/IEEE 标准，但得追溯到1991年。 相关系列的报告《算法语言 Scheme 修订报告》记录了大多数实现所支持的不断演进的非正式标准。 本系列的最新报告是《算法语言 Scheme 修订报告^{6}》[24] ，于2007年完成。
This book covers the language of the Revised^{6} Report. It is not intended to supplant the Revised^{6} Report but rather to provide a more comprehensive introduction and reference manual for the language, with more explanatory text and examples, suitable more for users than for implementors. Features specific to particular implementations of Scheme are not included. In particular, features specific to the author’s Chez Scheme and Petite Chez Scheme implementations are described separately in the Chez Scheme User’s Guide [9]. On the other hand, no book on Scheme would be complete without some coverage of the interactive top level, since nearly every Scheme system supports interactive use in one form or another, even though the behavior is not standardized by the Revised^{6} Report. Chapters 2 and 3 are thus written assuming that the reader has available a Scheme implementation that supports an interactive top level, with behavior consistent with the description of the toplevel environment in earlier reports and the IEEE/ANSI standard.
本书涵盖了《修订报告^{6}》的内容，但它并不是要取代《修订报告^{6}》，而是通过更多的说明性文字和示例， 为该语言提供更全面的介绍，并作为参考手册使用。所以，比起语言实现者，本书更适合该语言的使用者。 针对 Scheme 实现的特定的特性，不包含在本书内，特别是针对作者的 Chez Scheme 和 Petite Chez Scheme 的实现的那些特性， 它们会在《Chez Scheme 用户指南》[9] （译注：该书第九版译作在 这里）中单独描述。 另外，若没有包含对 交互顶层 的介绍，那么，任何关于 Scheme 的书都是不完整的，因为，即使《修订报告^{6}》没有对交互方式进行标准化， 但几乎每个 Scheme 系统都会以这种或那种形式支持交互操作。 因此，在撰写 第二 和 第三 章时，便假定读者已经拥有一个支持 交互顶层 的 Scheme 实现， 并且其操作方式与在早期报告以及 IEEE/ANSI 标准中对 顶层环境 的描述一致。
A large number of small to mediumsized examples are spread throughout the text, and one entire chapter is dedicated to the presentation of a set of longer examples. Many of the examples show how a standard Scheme syntactic form or procedure might be implemented; others implement useful extensions. All of the examples can be entered directly from the keyboard into an interactive Scheme session.
本书全文中散布了大量中小型示例，并且一个完整的篇章会专门介绍一组较长的例子。 许多示例展示了标准的 Scheme 语法形式 和 处理过程 是如何实现的，其他的还实现了一些有用的扩展。 所有示例都可以直接从键盘输入到交互式 Scheme 会话中。
This book is organized into twelve chapters, plus back matter. Chapter 1 describes the properties and features of Scheme that make it a useful and enjoyable language to use. Chapter 1 also describes Scheme’s notational conventions and the typographical conventions employed in this book.
Chapter 2 is an introduction to Scheme programming for the novice Scheme programmer that leads the reader through a series of examples, beginning with simple Scheme expressions and working toward progressively more difficult ones. Each section of Chapter 2 introduces a small set of related features, and the end of each section contains a set of exercises for further practice. The reader will learn the most from Chapter 2 by sitting at the keyboard and typing in the examples and trying the exercises.
第二章 是针对 Scheme 新手程序员的 Scheme 编程简介， 它从简单的 Scheme 表达式开始，引导读者接触一系列示例，并逐步深入更难的表达式。 第二章 的每个章节都会介绍一小部分相关的特性，并在每个章节的末尾安排一组习题，以供进一步练习。 通过在键盘上输入这些示例并尝试这些习题，读者将从 第二章 中获益匪浅。
Chapter 3 continues the introduction but covers more advanced features and concepts. Even readers with prior Scheme experience may wish to work through the examples and exercises found there.
第三章 会继续介绍 Scheme，但涵盖了更高级的特性和概念。 即使是先前已经有 Scheme 经验的读者，也会希望去研究里面的示例和习题的。
Chapter 4 through 11 make up the reference portion of the text. They present each of Scheme’s primitive procedures and syntactic forms in turn, grouping them into short sections of related procedures and forms. Chapter 4 describes operations for creating procedures and variable bindings; Chapter 5, program control operations; Chapter 6, operations on the various object types (including lists, numbers, and strings); Chapter 7, input and output operations; Chapter 8, syntactic extension; Chapter 9, recordtype definitions; Chapter 10, libraries and toplevel programs; and Chapter 11, exceptions and conditions.
第 四章 到 十一章 为本书的参考章节。 他们依次介绍了 Scheme 的每个原始（Primitive） 处理过程 和 语法形式， 并将相关联的 处理过程 和 语法形式 组织在较短的章节中。 第四章  创建 处理过程 和 变量绑定 的操作； 第五章  程序控制操作； 第六章  对各种对象类型（包括 列表、数字、字符串）的操作； 第七章  输入与输出操作； 第八章  扩展语法； 第九章  记录类型 的定义； 第十章  库和高级程序； 第十一章  异常和条件。
Chapter 12 contains a collection of example procedures, libraries, and programs, each with a short overview, some examples of its use, the implementation with brief explanation, and a set of exercises for further work. Each of these programs demonstrates a particular set of features, and together they illustrate an appropriate style for programming in Scheme.
第十二章 包含一组处理过程、库和程序的示例， 每一个示例都有一个简短的概述、一些使用例子、简要的实现说明，以及一系列用于进一步展开的习题。 每一个程序都演示了一组特定的特性，并一起展示了 Scheme 中一种恰当的编程风格。
Following Chapter 12 are bibliographical references, answers to selected exercises, a detailed description of the formal syntax of Scheme programs and data, a concise summary of Scheme syntactic forms and procedures, and the index. The summary of forms and procedures is a useful first stop for programmers unsure of the structure of a syntactic form or the arguments expected by a primitive procedure. The page numbers appearing in the summary of forms and procedures and the italicized page numbers appearing in the index indicate the locations in the text where forms and procedures are defined.
在 第十二章 后面的是参考文献、习题答案、对 Scheme 程序和数据的正式语法的详细描述、 对 Scheme 语法形式 和 处理过程 的简要总结，以及索引。 对 语法形式 和 处理过程 的总结，对于不确定 语法形式 的结构或原始 处理过程 的期望参数的程序员来说， 是一个有益的开始。在 <对语法形式和处理过程的总结> 中出现的页码，和在 <索引> 中出现的斜体页码， 表示 语法形式 和 处理过程 在本书中定义的位置。
Because the reference portion describes a number of aspects of the language not covered by the introductory chapters along with a number of interesting short examples, most readers will find it profitable to read through most of the material to become familiar with each feature and how it relates to other features. Chapter 6 is lengthy, however, and may be skimmed and later referenced as needed.
通过一些有趣的简短示例，参考章节描述了在入门章节中未涵盖到的该语言的许多方面， 因此，大多数读者会发现，通读大部分材料以熟悉每个特性及其与其他特性之间的联系，将会获益良多。 但是，第六章 的篇幅很长，可以略读一下，以后再根据需要查阅。
An online version of this book is available at http://www.scheme.com/tspl/. The summary of forms and index in the online edition include page numbers for the printed version and are thus useful as searchable indexes.
本书的在线版本可从 http://www.scheme.com/tspl/ 获得。 在线版本的 <语法形式总结> 和 <索引> 章节中包含印刷版的页码，因此可作为可查询的索引使用。
About the illustrations: The cover illustration and the illustration at the front of each chapter are algorithmic line fields created by artist JeanPierre Hébert, based on an idea inspired by the writings of John Cage. Each line field is created by the composition of any number of grids of parallel lines. The grids are regular, but they are not. For instance, the lines are of irregular length, which creates ragged edges. Their tone and thickness vary slightly. They are not exactly equidistant. They intersect with each other at a certain angle. When this angle is small, patterns of interference develop. The lines are first steeped into various scalar fields that perturb their original straight shape, then projected on the plane of the paper. Masks introduce holes in some layers. For the cover illustration, the grids are colored in different hues.
关于插图 : 封面插画和每章开头的插图是艺术家 JeanPierre Hébert 受 John Cage 的著作启发而创建的算法 线场。 每个线场都是由任意数量的平行线网格组成的。网格是规则的，但线场不是。 比如，线条的长度不规则，会出现参差不齐的边缘； 它们的色调和宽度略有不同；它们不是完全等距的； 它们以一定角度彼此相交，当该角度较小时，会产生干涉图案。 这些线条首先浸入各种标量场以扰乱其原始的笔直形状，然后投射到纸面上， 遮罩则会在层中造成空洞。在封面插画中，网格是以不同的颜色着色的。
All the images are created by a single Scheme program that makes most of the decisions, based heavily on chance. The artist controls only canvas size, aspect ratio, the overall palette of colors, and levels of chance and fuzziness. The task of the artist is to introduce just enough chance at the right place so that the results are at the same time surprising, interesting, and in line with the artist’s sense of aesthetics. This is a game of uncertainty, chaos, and harmony.
所有图像都是由单个 Scheme 程序创建的，该程序在很大程度上是基于偶然性来做出大多数决策的。 艺术家仅需控制画布的大小、宽高比、整体色彩以及偶然性和模糊性的程度。 艺术家的任务则是在适当的地方引入足够的偶然性，以使结果能够同时让人感到惊奇、有趣且又符合艺术家的审美观。 这是一个充满不确定性的、混乱的、和谐的游戏。
Acknowledgments: Many individuals contributed in one way or another to the preparation of one or more editions of this book, including Bruce Smith, Eugene Kohlbecker, Matthias Felleisen, Dan Friedman, Bruce Duba, Phil Dybvig, Guy Steele, Bob Hieb, Chris Haynes, Dave Plaisted, Joan Curry, Frank Silbermann, Pavel Curtis, John Wait, Carl Bruggeman, Sam Daniel, Oscar Waddell, Mike Ashley, John LaLonde, John Zuckerman, John Simmons, Bob Prior, Bob Burger, and Aziz Ghuloum. Many others have offered minor corrections and suggestions. Oscar Waddell helped create the typesetting system used to format the printed and online versions of this book. A small amount of text and a few examples have been adapted from the Revised^{6} Report for this book, for which credit goes to the editors of that report and many others who contributed to it. Finally and most importantly, my wife, Susan Dybvig, suggested that I write this book in the first place and lent her expertise and assistance to the production and publication of this and the previous editions.
致谢 : 许多人以这种或那种方式为本书的一个或多个版本的准备工作做出了贡献，包括 Bruce Smith、Eugene Kohlbecker、Matthias Felleisen、Dan Friedman、Bruce Duba、Phil Dybvig、 Guy Steele、Bob Hieb、Chris Haynes、Dave Plaisted、Joan Curry、Frank Silbermann、Pavel Curtis、 John Wait、Carl Bruggeman、Sam Daniel、Oscar Waddell、Mike Ashley、John LaLonde、John Zuckerman、 John Simmons、Bob Prior、Bob Burger 和 Aziz Ghuloum。 许多其他人也提出了一些小的更正和建议。 Oscar Waddell 帮助创建了用于对本书的印刷版和在线版进行格式化的排版系统。 本书改编了《修订报告^{6}》中的少量内容和一些示例，该报告的编辑者们和许多对其做出过贡献的人都对此表示赞赏。 最后也是最重要的一点，是我的妻子 Susan Dybvig 建议我先写这本书， 并借用她的专业技能和协助来完成了该版本及其先前版本的制作和发行。
第一章: 简介
Scheme is a generalpurpose computer programming language. It is a highlevel language, supporting operations on structured data such as strings, lists, and vectors, as well as operations on more traditional data such as numbers and characters. While Scheme is often identified with symbolic applications, its rich set of data types and flexible control structures make it a truly versatile language. Scheme has been employed to write text editors, optimizing compilers, operating systems, graphics packages, expert systems, numerical applications, financial analysis packages, virtual reality systems, and practically every other type of application imaginable. Scheme is a fairly simple language to learn, since it is based on a handful of syntactic forms and semantic concepts and since the interactive nature of most implementations encourages experimentation. Scheme is a challenging language to understand fully, however; developing the ability to use its full potential requires careful study and practice.
Scheme 是一门通用的计算机编程语言。 它是一门高级语言，支持对字符串、列表和向量等结构化数据的操作， 也支持对数字和字符等更为传统的数据的操作。 虽然 Scheme 经常被等同于符号化应用程序，但它丰富的数据类型和灵活的控制结构使得它成为了一门真正通用的语言。 Scheme 已经被用于编写文本编辑器、优化的编译器、操作系统、图形软件包、专家系统、数字应用程序、 财务分析软件包、虚拟现实系统以及几乎所有可以想到的其他类型的应用程序。
Scheme programs are highly portable across versions of the same Scheme implementation on different machines, because machine dependencies are almost completely hidden from the programmer. They are also portable across different implementations because of the efforts of a group of Scheme language designers who have published a series of reports, the "Revised Reports" on Scheme. The most recent, the "Revised^{6} Report" [24], emphasizes portability through a set of standard libraries and a standard mechanism for defining new portable libraries and toplevel programs.
Scheme 程序在不同机器上的相同 Scheme 实现的版本之间具有高度的可移植性， 因为，对程序员来说，机器的依赖性几乎是完全隐藏的。 由于 Scheme 语言设计者团队（他们已经发布了一系列关于 Scheme 的《修订报告》）的努力， 它们还可以在不同的实现之间移植。 最新的《修订报告^{6}》[24] 通过一组标准库以及用于定义新的可移植库和顶层程序的标准机制来强化了可移植性。
Although some early Scheme systems were inefficient and slow, many newer compilerbased implementations are fast, with programs running on par with equivalent programs written in lowerlevel languages. The relative inefficiency that sometimes remains results from runtime checks that support generic arithmetic and help programmers detect and correct various common programming errors. These checks may be disabled in many implementations.
Scheme supports many types of data values, or objects, including characters, strings, symbols, lists or vectors of objects, and a full set of numeric data types, including complex, real, and arbitraryprecision rational numbers.
The storage required to hold the contents of an object is dynamically allocated as necessary and retained until no longer needed, then automatically deallocated, typically by a garbage collector that periodically recovers the storage used by inaccessible objects. Simple atomic values, such as small integers, characters, booleans, and the empty list, are typically represented as immediate values and thus incur no allocation or deallocation overhead.
Regardless of representation, all objects are firstclass data values; because they are retained indefinitely, they may be passed freely as arguments to procedures, returned as values from procedures, and combined to form new objects. This is in contrast with many other languages where composite data values such as arrays are either statically allocated and never deallocated, allocated on entry to a block of code and unconditionally deallocated on exit from the block, or explicitly allocated and deallocated by the programmer.
Scheme is a callbyvalue language, but for at least mutable objects (objects that can be modified), the values are pointers to the actual storage. These pointers remain behind the scenes, however, and programmers need not be conscious of them except to understand that the storage for an object is not copied when an object is passed to or returned from a procedure.
At the heart of the Scheme language is a small core of syntactic forms from which all other forms are built. These core forms, a set of extended syntactic forms derived from them, and a set of primitive procedures make up the full Scheme language. An interpreter or compiler for Scheme can be quite small and potentially fast and highly reliable. The extended syntactic forms and many primitive procedures can be defined in Scheme itself, simplifying the implementation and increasing reliability.
Scheme programs share a common printed representation with Scheme data structures. As a result, any Scheme program has a natural and obvious internal representation as a Scheme object. For example, variables and syntactic keywords correspond to symbols, while structured syntactic forms correspond to lists. This representation is the basis for the syntactic extension facilities provided by Scheme for the definition of new syntactic forms in terms of existing syntactic forms and procedures. It also facilitates the implementation of interpreters, compilers, and other program transformation tools for Scheme directly in Scheme, as well as program transformation tools for other languages in Scheme.
Scheme variables and keywords are lexically scoped, and Scheme programs are blockstructured. Identifiers may be imported into a program or library or bound locally within a given block of code such as a library, program, or procedure body. A local binding is visible only lexically, i.e., within the program text that makes up the particular block of code. An occurrence of an identifier of the same name outside this block refers to a different binding; if no binding for the identifier exists outside the block, then the reference is invalid. Blocks may be nested, and a binding in one block may shadow a binding for an identifier of the same name in a surrounding block. The scope of a binding is the block in which the bound identifier is visible minus any portions of the block in which the identifier is shadowed. Block structure and lexical scoping help create programs that are modular, easy to read, easy to maintain, and reliable. Efficient code for lexical scoping is possible because a compiler can determine before program evaluation the scope of all bindings and the binding to which each identifier reference resolves. This does not mean, of course, that a compiler can determine the values of all variables, since the actual values are not computed in most cases until the program executes.
In most languages, a procedure definition is simply the association of a name with a block of code. Certain variables local to the block are the parameters of the procedure. In some languages, a procedure definition may appear within another block or procedure so long as the procedure is invoked only during execution of the enclosing block. In others, procedures can be defined only at top level. In Scheme, a procedure definition may appear within another block or procedure, and the procedure may be invoked at any time thereafter, even if the enclosing block has completed its execution. To support lexical scoping, a procedure carries the lexical context (environment) along with its code.
Furthermore, Scheme procedures are not always named. Instead, procedures are firstclass data objects like strings or numbers, and variables are bound to procedures in the same way they are bound to other objects.
As with procedures in most other languages, Scheme procedures may be recursive. That is, any procedure may invoke itself directly or indirectly. Many algorithms are most elegantly or efficiently specified recursively. A special case of recursion, called tail recursion, is used to express iteration, or looping. A tail call occurs when one procedure directly returns the result of invoking another procedure; tail recursion occurs when a procedure recursively tailcalls itself, directly or indirectly. Scheme implementations are required to implement tail calls as jumps (gotos), so the storage overhead normally associated with recursion is avoided. As a result, Scheme programmers need master only simple procedure calls and recursion and need not be burdened with the usual assortment of looping constructs.
Scheme supports the definition of arbitrary control structures with continuations. A continuation is a procedure that embodies the remainder of a program at a given point in the program. A continuation may be obtained at any time during the execution of a program. As with other procedures, a continuation is a firstclass object and may be invoked at any time after its creation. Whenever it is invoked, the program immediately continues from the point where the continuation was obtained. Continuations allow the implementation of complex control mechanisms including explicit backtracking, multithreading, and coroutines.
Scheme also allows programmers to define new syntactic forms, or syntactic extensions, by writing transformation procedures that determine how each new syntactic form maps to existing syntactic forms. These transformation procedures are themselves expressed in Scheme with the help of a convenient highlevel pattern language that automates syntax checking, input deconstruction, and output reconstruction. By default, lexical scoping is maintained through the transformation process, but the programmer can exercise control over the scope of all identifiers appearing in the output of a transformer. Syntactic extensions are useful for defining new language constructs, for emulating language constructs found in other languages, for achieving the effects of inline code expansion, and even for emulating entire languages in Scheme. Most large Scheme programs are built from a mix of syntactic extensions and procedure definitions.
Scheme evolved from the Lisp language and is considered to be a dialect of Lisp. Scheme inherited from Lisp the treatment of values as firstclass objects, several important data types, including symbols and lists, and the representation of programs as objects, among other things. Lexical scoping and block structure are features taken from Algol 60 [21]. Scheme was the first Lisp dialect to adopt lexical scoping and block structure, firstclass procedures, the treatment of tail calls as jumps, continuations, and lexically scoped syntactic extensions.
Common Lisp [27] and Scheme are both contemporary Lisp languages, and the development of each has been influenced by the other. Like Scheme but unlike earlier Lisp languages, Common Lisp adopted lexical scoping and firstclass procedures, although Common Lisp’s syntactic extension facility does not respect lexical scoping. Common Lisp’s evaluation rules for procedures are different from the evaluation rules for other objects, however, and it maintains a separate namespace for procedure variables, thereby inhibiting the use of procedures as firstclass objects. Also, Common Lisp does not support continuations or require proper treatment of tail calls, but it does support several less general control structures not found in Scheme. While the two languages are similar, Common Lisp includes more specialized constructs, while Scheme includes more generalpurpose building blocks out of which such constructs (and others) may be built.
The remainder of this chapter describes Scheme’s syntax and naming conventions and the typographical conventions used throughout this book.
Section 1.1. Scheme Syntax
Scheme programs are made up of keywords, variables, structured forms, constant data (numbers, characters, strings, quoted vectors, quoted lists, quoted symbols, etc.), whitespace, and comments.
Keywords, variables, and symbols are collectively called identifiers. Identifiers may be formed from letters, digits, and certain special characters, including ?
, !
, .
, +
, 
, *
, /
, <
, =
, >
, :
, $
, %
, ^
, &
, _
, ~
, and @
, as well as a set of additional Unicode characters. Identifiers cannot start with an at sign ( @
) and normally cannot start with any character that can start a number, i.e., a digit, plus sign ( +
), minus sign ( 
), or decimal point ( .
). Exceptions are +
, 
, and ...
, which are valid identifiers, and any identifier starting with >
. For example, hi
, Hello
, n
, x
, x3
, x+2
, and ?$&*!!!
are all identifiers. Identifiers are delimited by whitespace, comments, parentheses, brackets, string (double) quotes ( "
), and hash marks( #
). A delimiter or any other Unicode character may be included anywhere within the name of an identifier as an escape of the form \xsv;
, where sv
is the scalar value of the character in hexadecimal notation.
There is no inherent limit on the length of a Scheme identifier; programmers may use as many characters as necessary. Long identifiers are no substitute for comments, however, and frequent use of long identifiers can make a program difficult to format and consequently difficult to read. A good rule is to use short identifiers when the scope of the identifier is small and longer identifiers when the scope is larger.
Identifiers may be written in any mix of upper and lowercase letters, and case is significant, i.e., two identifiers are different even if they differ only in case. For example, abcde
, Abcde
, AbCdE
, and ABCDE
all refer to different identifiers. This is a change from previous versions of the Revised Report.
Structured forms and list constants are enclosed within parentheses, e.g., (a b c)
or (* ( x 2) y)
. The empty list is written ()
. Matched sets of brackets ( [
]
) may be used in place of parentheses and are often used to set off the subexpressions of certain standard syntactic forms for readability, as shown in examples throughout this book. Vectors are written similarly to lists, except that they are preceded by #(
and terminated by )
, e.g., #(this is a vector of symbols)
. Bytevectors are written as sequences of unsigned byte values (exact integers in the range 0 through 255) bracketed by #vu8(
and )
, e.g., #vu8(3 250 45 73)
.
Strings are enclosed in double quotation marks, e.g., "I am a string"
. Characters are preceded by #\
, e.g., #\a
. Case is important within character and string constants, as within identifiers. Numbers may be written as integers, e.g., 123, as ratios, e.g., 1/2, in floatingpoint or scientific notation, e.g., 1.3 or 1e23, or as complex numbers in rectangular or polar notation, e.g., 1.32.7i or 1.2@73. Case is not important in the syntax of a number. The boolean values representing true and false are written #t
and #f
. Scheme conditional expressions actually treat #f
as false and all other objects as true, so 3
, 0
, ()
, "false"
, and nil
all count as true.
Details of the syntax for each type of constant data are given in the individual sections of Chapter 6 and in the formal syntax of Scheme starting on page 455.
Scheme expressions may span several lines, and no explicit terminator is required. Since the number of whitespace characters (spaces and newlines) between expressions is not significant, Scheme programs should be indented to show the structure of the code in a way that makes the code as readable as possible. Comments may appear on any line of a Scheme program, between a semicolon ( ;
) and the end of the line. Comments explaining a particular Scheme expression are normally placed at the same indentation level as the expression, on the line before the expression. Comments explaining a procedure or group of procedures are normally placed before the procedures, without indentation. Multiple comment characters are often used to set off the latter kind of comment, e.g., ;;; The following procedures ...
.
Two other forms of comments are supported: block comments and datum comments. Block comments are delimited by #
and #
pairs, and may be nested. A datum comment consists of a #;
prefix and the datum (printed data value) that follows it. Datum comments are typically used to comment out individual definitions or expressions. For example, (three #;(not four) element list)
is just what it says. Datum comments may also be nested, though #;#;(a)(b)
has the somewhat nonobvious effect of commenting out both (a)
and (b)
.
Some Scheme values, such as procedures and ports, do not have standard printed representations and can thus never appear as a constant in the printed syntax of a program. This book uses the notation #<description>
when showing the output of an operation that returns such a value, e.g., #<procedure>
or #<port>
.
Section 1.2. Scheme Naming Conventions
Scheme’s naming conventions are designed to provide a high degree of regularity. The following is a list of these naming conventions:

Predicate names end in a question mark (
?
). Predicates are procedures that return a true or false answer, such aseq?
,zero?
, andstring=?
. The common numeric comparators=
,<
,>
,<=
, and>=
are exceptions to this naming convention. 
Type predicates, such as
pair?
, are created from the name of the type, in this casepair
, and the question mark. 
The names of most character, string, and vector procedures start with the prefix
char
,string
, andvector
, e.g.,stringappend
. (The names of some list procedures start withlist
, but most do not.) 
The names of procedures that convert an object of one type into an object of another type are written as
type_{1}>type_{2}
, e.g.,vector>list
. 
The names of procedures and syntactic forms that cause side effects end with an exclamation point (
!
). These includeset!
andvectorset!
. Procedures that perform input or output technically cause side effects, but their names are exceptions to this rule.
Programmers should employ these same conventions in their own code whenever possible.
Section 1.3. Typographical and Notational Conventions
A standard procedure or syntactic form whose sole purpose is to perform some side effect is said to return unspecified. This means that an implementation is free to return any number of values, each of which can be any Scheme object, as the value of the procedure or syntactic form. Do not count on these values being the same across implementations, the same across versions of the same implementation, or even the same across two uses of the procedure or syntactic form. Some Scheme systems routinely use a special object to represent unspecified values. Printing of this object is often suppressed by interactive Scheme systems, so that the values of expressions returning unspecified values are not printed.
While most standard procedures return a single value, the language supports procedures that return zero, one, more than one, or even a variable number of values via the mechanisms described in Section 5.8. Some standard expressions can evaluate to multiple values if one of their subexpressions evaluates to multiple values, e.g., by calling a procedure that returns multiple values. When this situation can occur, an expression is said to return "the values" rather than simply "the value" of its subexpression. Similarly, a standard procedure that returns the values resulting from a call to a procedure argument is said to return the values returned by the procedure argument.
This book uses the words "must" and "should" to describe program requirements, such as the requirement to provide an index that is less than the length of the vector in a call to vectorref
. If the word "must" is used, it means that the requirement is enforced by the implementation, i.e., an exception is raised, usually with condition type &assertion
. If the word "should" is used, an exception may or may not be raised, and if not, the behavior of the program is undefined.
The phrase "syntax violation" is used to describe a situation in which a program is malformed. Syntax violations are detected prior to program execution. When a syntax violation is detected, an exception of type &syntax
is raised and the program is not executed.
The typographical conventions used in this book are straightforward. All Scheme objects are printed in a typewriter
typeface, just as they are to be typed at the keyboard. This includes syntactic keywords, variables, constant objects, Scheme expressions, and example programs. An italic typeface is used to set off syntax variables in the descriptions of syntactic forms and arguments in the descriptions of procedures. Italics are also used to set off technical terms the first time they appear. In general, names of syntactic forms and procedures are never capitalized, even at the beginning of a sentence. The same is true for syntax variables written in italics.
In the description of a syntactic form or procedure, one or more prototype patterns show the syntactic form or forms or the correct number or numbers of arguments for an application of the procedure. The keyword or procedure name is given in typewriter font, as are parentheses. The remaining pieces of the syntax or arguments are shown in italics, using a name that implies the type of expression or argument expected by the syntactic form or procedure. Ellipses are used to specify zero or more occurrences of a subexpression or argument. For example, (or expr ...)
describes the or
syntactic form, which has zero or more subexpressions, and (member obj list)
describes the member
procedure, which expects two arguments, an object and a list.
A syntax violation occurs if the structure of a syntactic form does not match its prototype. Similarly, an exception with condition type &assertion
is raised if the number of arguments passed to a standard procedure does not match what it is specified to receive. An exception with condition type &assertion
is also raised if a standard procedure receives an argument whose type is not the type implied by its name or does not meet other criteria given in the description of the procedure. For example, the prototype for vectorset!
is
(vectorset! vector n obj)
and the description says that n
must be an exact nonnegative integer strictly less than the length of vector
. Thus, vectorset!
must receive three arguments, the first of which must be a vector, the second of which must be an exact nonnegative integer less than the length of the vector, and the third of which may be any Scheme value. Otherwise, an exception with condition type &assertion
is raised.
In most cases, the type of argument required is obvious, as with vector
, obj
, or binaryinputport
. In others, primarily within the descriptions of numeric routines, abbreviations are used, such as int
for integer, exint
for exact integer, and fx
for fixnum. These abbreviations are explained at the start of the sections containing the affected entries.
Chapter 2. Getting Started
This chapter is an introduction to Scheme for programmers who are new to the language. You will get more from this chapter if you are sitting in front of an interactive Scheme system, trying out the examples as you go.
After reading this chapter and working the exercises, you should be able to start using Scheme. You will have learned the syntax of Scheme programs and how they are executed, along with how to use simple data structures and control mechanisms.
Section 2.1. Interacting with Scheme
Most Scheme systems provide an interactive programming environment that simplifies program development and experimentation. The simplest interaction with Scheme follows a "readevaluateprint" cycle. A program (often called a readevaluateprint loop, or REPL) reads each expression you type at the keyboard, evaluates it, and prints its value.
With an interactive Scheme system, you can type an expression at the keyboard and see its value immediately. You can define a procedure and apply it to arguments to see how it works. You can even type in an entire program consisting of a set of procedure definitions and test it without leaving the system. When your program starts getting longer, it will be more convenient to type it into a file (using a text editor), load the file and test it interactively. In most Scheme systems, a file may be loaded with the nonstandard procedure load
, which takes a string argument naming the file. Preparing your program in a file has several advantages: you have a chance to compose your program more carefully, you can correct errors without retyping the program, and you can retain a copy for later use. Most Scheme implementations treat expressions loaded from a file the same as expressions typed at the keyboard.
While Scheme provides various input and output procedures, the REPL takes care of reading expressions and printing their values. This frees you to concentrate on writing your program without worrying about how its results will be displayed.
The examples in this chapter and in the rest of the book follow a regular format. An expression you might type from your keyboard is given first, possibly spanning several lines. The value of the expression is given after the ⇒, to be read as "evaluates to." The ⇒ is omitted for definitions and when the value of an expression is unspecified.
The example programs are formatted in a style that "looks nice" and conveys the structure of the program. The code is easy to read because the relationship between each expression and its subexpressions is clearly shown. Scheme ignores indentation and line breaks, however, so there is no need to follow a particular style. The important thing is to establish one style and keep to it. Scheme sees each program as if it were on a single line, with its subexpressions ordered from left to right.
If you have access to an interactive Scheme system, it might be a good idea to start it up now and type in the examples as you read. One of the simplest Scheme expressions is a string constant. Try typing "Hi Mom!"
(including the double quotes) in response to the prompt. The system should respond with "Hi Mom!"
; the value of any constant is the constant itself.
"Hi Mom!" ⇒ "Hi Mom!"
Here is a set of expressions, each with Scheme’s response. They are explained in later sections of this chapter, but for now use them to practice interacting with Scheme.
"hello" ⇒ "hello"
42 ⇒ 42
22/7 ⇒ 22/7
3.141592653 ⇒ 3.141592653
+ ⇒ #<procedure>
(+ 76 31) ⇒ 107
(* 12 10) ⇒ 120
'(a b c d) ⇒ (a b c d)
Be careful not to miss any single quotes ( '
), double quotes, or parentheses. If you left off a single quote in the last expression, you probably received a message indicating that an exception has occurred. Just try again. If you left off a closing parenthesis or double quote, the system might still be waiting for it.
Here are a few more expressions to try. You can try to figure out on your own what they mean or wait to find out later in the chapter.
(car '(a b c)) ⇒ a
(cdr '(a b c)) ⇒ (b c)
(cons 'a '(b c)) ⇒ (a b c)
(cons (car '(a b c))
(cdr '(d e f))) ⇒ (a e f)
As you can see, Scheme expressions may span more than one line. The Scheme system knows when it has an entire expression by matching double quotes and parentheses.
Next, let’s try defining a procedure.
(define square
(lambda (n)
(* n n)))
The procedure square
computes the square \(n^2\) of any number \(n\). We say more about the expressions that make up this definition later in this chapter. For now it suffices to say that define
establishes variable bindings, lambda
creates procedures, and *
names the multiplication procedure. Note the form of these expressions. All structured forms are enclosed in parentheses and written in prefix notation, i.e., the operator precedes the arguments. As you can see, this is true even for simple arithmetic operations such as *
.
Try using square
.
(square 5) ⇒ 25
(square 200) ⇒ 40000
(square 0.5) ⇒ 0.25
(square 1/2) ⇒ 1/4
Even though the next definition is short, you might enter it into a file. Let’s assume you call the file "reciprocal.ss."
(define reciprocal
(lambda (n)
(if (= n 0)
"oops!"
(/ 1 n))))
This procedure, reciprocal
, computes the quantity \(1/n\) for any number \(n \neq 0\). For \(n = 0\), reciprocal
returns the string "oops!"
. Return to Scheme and try loading your file with the procedure load
.
(load "reciprocal.ss")
Finally, try using the procedure we have just defined.
(reciprocal 10) ⇒ 1/10
(reciprocal 1/10) ⇒ 10
(reciprocal 0) ⇒ "oops!"
(reciprocal (reciprocal 1/10)) ⇒ 1/10
In the next section we will discuss Scheme expressions in more detail. Throughout this chapter, keep in mind that your Scheme system is one of the most useful tools for learning Scheme. Whenever you try one of the examples in the text, follow it up with your own examples. In an interactive Scheme system, the cost of trying something out is relatively smallusually just the time to type it in.
Section 2.2. Simple Expressions
The simplest Scheme expressions are constant data objects, such as strings, numbers, symbols, and lists. Scheme supports other object types, but these four are enough for many programs. We saw some examples of strings and numbers in the preceding section.
Let’s discuss numbers in a little more detail. Numbers are constants. If you enter a number, Scheme echoes it back to you. The following examples show that Scheme supports several types of numbers.
123456789987654321 ⇒ 123456789987654321
3/4 ⇒ 3/4
2.718281828 ⇒ 2.718281828
2.2+1.1i ⇒ 2.2+1.1i
Scheme numbers include exact and inexact integer, rational, real, and complex numbers. Exact integers and rational numbers have arbitrary precision, i.e., they can be of arbitrary size. Inexact numbers are usually represented internally using IEEE standard floatingpoint representations.
Scheme provides the names +
, 
, *
, and /
for the corresponding arithmetic procedures. Each procedure accepts two numeric arguments. The expressions below are called procedure applications, because they specify the application of a procedure to a set of arguments.
(+ 1/2 1/2) ⇒ 1
( 1.5 1/2) ⇒ 1.0
(* 3 1/2) ⇒ 3/2
(/ 1.5 3/4) ⇒ 2.0
Scheme employs prefix notation even for common arithmetic operations. Any procedure application, whether the procedure takes zero, one, two, or more arguments, is written as (procedure arg ...)
. This regularity simplifies the syntax of expressions; one notation is employed regardless of the operation, and there are no complicated rules regarding the precedence or associativity of operators.
Procedure applications may be nested, in which case the innermost values are computed first. We can thus nest applications of the arithmetic procedures given above to evaluate more complicated formulas.
(+ (+ 2 2) (+ 2 2)) ⇒ 8
( 2 (* 4 1/3)) ⇒ 2/3
(* 2 (* 2 (* 2 (* 2 2)))) ⇒ 32
(/ (* 6/7 7/2) ( 4.5 1.5)) ⇒ 1.0
These examples demonstrate everything you need to use Scheme as a fourfunction desk calculator. While we will not discuss them in this chapter, Scheme supports many other arithmetic procedures. Now might be a good time to turn to Section 6.4 and experiment with some of them.
Simple numeric objects are sufficient for many tasks, but sometimes aggregate data structures containing two or more values are needed. In many languages, the basic aggregate data structure is the array. In Scheme, it is the list. Lists are written as sequences of objects surrounded by parentheses. For instance, (1 2 3 4 5)
is a list of numbers, and ("this" "is" "a" "list")
is a list of strings. Lists need not contain only one type of object, so (4.2 "hi")
is a valid list containing a number and a string. Lists may be nested (may contain other lists), so ((1 2) (3 4))
is a valid list with two elements, each of which is a list of two elements.
You might notice that lists look just like procedure applications and wonder how Scheme tells them apart. That is, how does Scheme distinguish between a list of objects, (obj_{1} obj_{2} ...)
, and a procedure application, (procedure arg ...)
?
In some cases, the distinction might seem obvious. The list of numbers (1 2 3 4 5)
could hardly be confused with a procedure application, since 1 is a number, not a procedure. So, the answer might be that Scheme looks at the first element of the list or procedure application and makes its decision based on whether that first element is a procedure or not. This answer is not good enough, since we might even want to treat a valid procedure application such as (+ 3 4)
as a list. The answer is that we must tell Scheme explicitly to treat a list as data rather than as a procedure application. We do this with quote
.
(quote (1 2 3 4 5)) ⇒ (1 2 3 4 5)
(quote ("this" "is" "a" "list")) ⇒ ("this" "is" "a" "list")
(quote (+ 3 4)) ⇒ (+ 3 4)
The quote
forces the list to be treated as data. Try entering the above expressions without the quote; you will likely receive a message indicating that an exception has occurred for the first two and an incorrect answer (7
) for the third.
Because quote
is required fairly frequently in Scheme code, Scheme recognizes a single quotation mark ( '
) preceding an expression as an abbreviation for quote
.
'(1 2 3 4) ⇒ (1 2 3 4)
'((1 2) (3 4)) ⇒ ((1 2) (3 4))
'(/ (* 2 1) 3) ⇒ (/ (* 2 1) 3)
Both forms are referred to as quote
expressions. We often say an object is quoted when it is enclosed in a quote
expression.
A quote
expression is not a procedure application, since it inhibits the evaluation of its subexpression. It is an entirely different syntactic form. Scheme supports several other syntactic forms in addition to procedure applications and quote
expressions. Each syntactic form is evaluated differently. Fortunately, the number of different syntactic forms is small. We will see more of them later in this chapter.
Not all quote
expressions involve lists. Try the following expression with and without the quote
wrapper.
(quote hello) ⇒ hello
The symbol hello
must be quoted in order to prevent Scheme from treating hello
as a variable. Symbols and variables in Scheme are similar to symbols and variables in mathematical expressions and equations. When we evaluate the mathematical expression \(1  x\) for some value of \(x\), we think of \(x\) as a variable. On the other hand, when we consider the algebraic equation \(x^2  1 = (x  1)(x + 1)\), we think of \(x\) as a symbol (in fact, we think of the whole equation symbolically). Just as quoting a list tells Scheme to treat a parenthesized form as a list rather than as a procedure application, quoting an identifier tells Scheme to treat the identifier as a symbol rather than as a variable. While symbols are commonly used to represent variables in symbolic representations of equations or programs, symbols may also be used, for example, as words in the representation of natural language sentences.
You might wonder why applications and variables share notations with lists and symbols. The shared notation allows Scheme programs to be represented as Scheme data, simplifying the writing of interpreters, compilers, editors, and other tools in Scheme. This is demonstrated by the Scheme interpreter given in Section 12.7, which is itself written in Scheme. Many people believe this to be one of the most important features of Scheme.
Numbers and strings may be quoted, too.
'2 ⇒ 2
'2/3 ⇒ 2/3
(quote "Hi Mom!") ⇒ "Hi Mom!"
Numbers and strings are treated as constants in any case, however, so quoting them is unnecessary.
Now let’s discuss some Scheme procedures for manipulating lists. There are two basic procedures for taking lists apart: car
and cdr
(pronounced coulder). car
returns the first element of a list, and cdr
returns the remainder of the list. (The names "car" and "cdr" are derived from operations supported by the first computer on which a Lisp language was implemented, the IBM 704.) Each requires a nonempty list as its argument.
(car '(a b c)) ⇒ a
(cdr '(a b c)) ⇒ (b c)
(cdr '(a)) ⇒ ()
(car (cdr '(a b c))) ⇒ b
(cdr (cdr '(a b c))) ⇒ (c)
(car '((a b) (c d))) ⇒ (a b)
(cdr '((a b) (c d))) ⇒ ((c d))
The first element of a list is often called the "car" of the list, and the rest of the list is often called the "cdr" of the list. The cdr of a list with one element is ()
, the empty list.
The procedure cons
constructs lists. It takes two arguments. The second argument is usually a list, and in that case cons
returns a list.
(cons 'a '()) ⇒ (a)
(cons 'a '(b c)) ⇒ (a b c)
(cons 'a (cons 'b (cons 'c '()))) ⇒ (a b c)
(cons '(a b) '(c d)) ⇒ ((a b) c d)
(car (cons 'a '(b c))) ⇒ a
(cdr (cons 'a '(b c))) ⇒ (b c)
(cons (car '(a b c))
(cdr '(d e f))) ⇒ (a e f)
(cons (car '(a b c))
(cdr '(a b c))) ⇒ (a b c)
Just as "car" and "cdr" are often used as nouns, "cons" is often used as a verb. Creating a new list by adding an element to the beginning of a list is referred to as consing the element onto the list.
Notice the word "usually" in the description of cons
's second argument. The procedure cons
actually builds pairs, and there is no reason that the cdr of a pair must be a list. A list is a sequence of pairs; each pair’s cdr is the next pair in the sequence.
The cdr of the last pair in a proper list is the empty list. Otherwise, the sequence of pairs forms an improper list. More formally, the empty list is a proper list, and any pair whose cdr is a proper list is a proper list.
An improper list is printed in dottedpair notation, with a period, or dot, preceding the final element of the list.
(cons 'a 'b) ⇒ (a . b)
(cdr '(a . b)) ⇒ b
(cons 'a '(b . c)) ⇒ (a b . c)
Because of its printed notation, a pair whose cdr is not a list is often called a dotted pair. Even pairs whose cdrs are lists can be written in dottedpair notation, however, although the printer always chooses to write proper lists without dots.
'(a . (b . (c . ()))) ⇒ (a b c)
The procedure list
is similar to cons
, except that it takes an arbitrary number of arguments and always builds a proper list.
(list 'a 'b 'c) ⇒ (a b c)
(list 'a) ⇒ (a)
(list) ⇒ ()
Section 6.3 provides more information on lists and the Scheme procedures for manipulating them. This might be a good time to turn to that section and familiarize yourself with the other procedures given there.
Exercise 2.2.1
Convert the following arithmetic expressions into Scheme expressions and evaluate them.

\(1.2 × (2  1/3) + 8.7\)

\((2/3 + 4/9) ÷ (5/11  4/3)\)

\(1 + 1 ÷ (2 + 1 ÷ (1 + 1/2))\)

\(1 × 2 × 3 × 4 × 5 × 6 × 7\)
Exercise 2.2.2
Experiment with the procedures +
, 
, *
, and /
to determine Scheme’s rules for the type of value returned by each when given different types of numeric arguments.
Exercise 2.2.3
Determine the values of the following expressions. Use your Scheme system to verify your answers.

(cons 'car 'cdr)

(list 'this '(is silly))

(cons 'is '(this silly?))

(quote (+ 2 3))

(cons '+ '(2 3))

(car '(+ 2 3))

(cdr '(+ 2 3))

cons

(quote cons)

(quote (quote cons))

car (quote (quote cons)))

(+ 2 3)

(+ '2 '3)

(+ (car '(2 3)) (car (cdr '(2 3))))

((car (list +  * /)) 2 3)
Exercise 2.2.4
(car (car '((a b) (c d))))
yields a
. Determine which compositions of car
and cdr
applied to ((a b) (c d))
yield b
, c
, and d
.
Exercise 2.2.5
Write a Scheme expression that evaluates to the following internal list structure.
Exercise 2.2.6
Draw the internal list structure produced by the expression below.
(cons 1 (cons '(2 . ((3) . ())) (cons '(()) (cons 4 5))))
Exercise 2.2.7
The behavior of (car (car (car '((a b) (c d)))))
is undefined because (car '((a b) (c d)))
is (a b)
, (car '(a b))
is a
, and (car 'a)
is undefined. Determine all legal compositions of car
and cdr
applied to ((a b) (c d))
.
Exercise 2.2.8
Try to explain how Scheme expressions are evaluated. Does your explanation cover the last example in Exercise 2.2.3?
Section 2.3. Evaluating Scheme Expressions
Let’s turn to a discussion of how Scheme evaluates the expressions you type. We have already established the rules for constant objects such as strings and numbers: the object itself is the value. You have probably also worked out in your mind a rule for evaluating procedure applications of the form (procedure arg_{1} ... arg_{n})
. Here, procedure
is an expression representing a Scheme procedure, and arg_{1} ... arg_{n}
are expressions representing its arguments. One possibility is the following.

Find the value of
procedure
. 
Find the value of
arg_{1}
.
… 
Find the value of
arg_{n}
. 
Apply the value of
procedure
to the values ofarg_{1} ... arg_{n}
.
For example, consider the simple procedure application (+ 3 4)
. The value of +
is the addition procedure, the value of 3 is the number 3, and the value of 4 is the number 4. Applying the addition procedure to 3 and 4 yields 7, so our value is the object 7.
By applying this process at each level, we can find the value of the nested expression (* (+ 3 4) 2)
. The value of *
is the multiplication procedure, the value of (+ 3 4)
we can determine to be the number 7, and the value of 2 is the number 2. Multiplying 7 by 2 we get 14, so our answer is 14.
This rule works for procedure applications but not for quote
expressions because the subexpressions of a procedure application are evaluated, whereas the subexpression of a quote
expression is not. The evaluation of a quote
expression is more similar to the evaluation of constant objects. The value of a quote
expression of the form (quote object)
is simply object
.
Constant objects, procedure applications, and quote
expressions are only three of the many syntactic forms provided by Scheme. Fortunately, only a few of the other syntactic forms need to be understood directly by a Scheme programmer; these are referred to as core syntactic forms. The remaining syntactic forms are syntactic extensions defined, ultimately, in terms of the core syntactic forms. We will discuss the remaining core syntactic forms and a few syntactic extensions in the remaining sections of this chapter. Section 3.1 summarizes the core syntactic forms and introduces the syntactic extension mechanism.
Before we go on to more syntactic forms and procedures, two points related to the evaluation of procedure applications are worthy of note. First, the process given above is overspecified, in that it requires the subexpressions to be evaluated from left to right. That is, procedure
is evaluated before arg_{1}
, arg_{1}
is evaluated before arg_{2}
, and so on. This need not be the case. A Scheme evaluator is free to evaluate the expressions in any orderleft to right, right to left, or any other sequential order. In fact, the subexpressions may be evaluated in different orders for different applications, even in the same implementation.
The second point is that procedure
is evaluated in the same way as arg_{1} ... arg_{n}
. While procedure
is often a variable that names a particular procedure, this need not be the case. Exercise 2.2.3 had you determine the value of the expression ((car (list +  * /)) 2 3)
. Here, procedure
is (car (list +  * /))
. The value of (car (list +  * /))
is the addition procedure, just as if procedure
were simply the variable +
.
Exercise 2.3.1
Write down the steps necessary to evaluate the expression below.
((car (cdr (list +  * /))) 17 5)
Section 2.4. Variables and Let Expressions
Suppose expr
is a Scheme expression that contains a variable var
. Suppose, additionally, that we would like var
to have the value val
when we evaluate expr
. For example, we might like x
to have the value 2 when we evaluate (+ x 3)
. Or, we might want y
to have the value 3 when we evaluate (+ 2 y)
. The following examples demonstrate how to do this using Scheme’s let
syntactic form.
(let ((x 2))
(+ x 3)) ⇒ 5
(let ((y 3))
(+ 2 y)) ⇒ 5
(let ((x 2) (y 3))
(+ x y)) ⇒ 5
The let
syntactic form includes a list of variableexpression pairs, along with a sequence of expressions referred to as the body of the let
. The general form of a let
expression is
(let ((var expr) ...) body_{1} body_{2} ...)
We say the variables are bound to the values by the let
. We refer to variables bound by let
as let
bound variables.
A let
expression is often used to simplify an expression that would contain two identical subexpressions. Doing so also ensures that the value of the common subexpression is computed only once.
(+ (* 4 4) (* 4 4)) ⇒ 32
(let ((a (* 4 4))) (+ a a)) ⇒ 32
Brackets are often used in place of parentheses to delimit the bindings of a let
expression.
(let ([list1 '(a b c)] [list2 '(d e f)])
(cons (cons (car list1)
(car list2))
(cons (car (cdr list1))
(car (cdr list2))))) ⇒ ((a . d) b . e)
Scheme treats forms enclosed in brackets just like forms enclosed in parentheses. An open bracket must be matched by a close bracket, and an open parenthesis must be matched by a close parenthesis. We use brackets for let
(and, as we’ll see, several other standard syntactic forms) to improve readability, especially when we might otherwise have two or more consecutive open parentheses.
Since expressions in the first position of a procedure application are evaluated no differently from other expressions, a let
bound variable may be used there as well.
(let ([f +])
(f 2 3)) ⇒ 5
(let ([f +] [x 2])
(f x 3)) ⇒ 5
(let ([f +] [x 2] [y 3])
(f x y)) ⇒ 5
The variables bound by let
are visible only within the body of the let
.
(let ([+ *])
(+ 2 3)) ⇒ 6
(+ 2 3) ⇒ 5
This is fortunate, because we would not want the value of +
to be the multiplication procedure everywhere.
It is possible to nest let
expressions.
(let ([a 4] [b 3])
(let ([asquared (* a a)]
[bsquared (* b b)])
(+ asquared bsquared))) ⇒ 25
When nested let
expressions bind the same variable, only the binding created by the inner let
is visible within its body.
(let ([x 1])
(let ([x (+ x 1)])
(+ x x))) ⇒ 4
The outer let
expression binds x
to 1 within its body, which is the second let
expression. The inner let
expression binds x
to (+ x 1)
within its body, which is the expression (+ x x)
. What is the value of (+ x 1)
? Since (+ x 1)
appears within the body of the outer let
but not within the body of the inner let
, the value of x
must be 1 and hence the value of (+ x 1)
is 2. What about (+ x x)
? It appears within the body of both let
expressions. Only the inner binding for x
is visible, so x
is 2 and (+ x x)
is 4.
The inner binding for x
is said to shadow the outer binding. A let
bound variable is visible everywhere within the body of its let
expression except where it is shadowed. The region where a variable binding is visible is called its scope. The scope of the first x
in the example above is the body of the outer let
expression minus the body of the inner let
expression, where it is shadowed by the second x
. This form of scoping is referred to as lexical scoping, since the scope of each binding can be determined by a straightforward textual analysis of the program.
Shadowing may be avoided by choosing different names for variables. The expression above could be rewritten so that the variable bound by the inner let
is newx
.
(let ([x 1])
(let ([newx (+ x 1)])
(+ newx newx))) ⇒ 4
Although choosing different names can sometimes prevent confusion, shadowing can help prevent the accidental use of an "old" value. For example, with the original version of the preceding example, it would be impossible for us to mistakenly refer to the outer x
within the body of the inner let
.
Exercise 2.4.1
Rewrite the following expressions, using let
to remove common subexpressions and to improve the structure of the code. Do not perform any algebraic simplifications.

(+ ( (* 3 a) b) (+ (* 3 a) b))

(cons (car (list a b c)) (cdr (list a b c)))
Exercise 2.4.2
Determine the value of the following expression. Explain how you derived this value.
(let ([x 9])
(* x
(let ([x (/ x 3)])
(+ x x))))
Exercise 2.4.3
Rewrite the following expressions to give unique names to each different let
bound variable so that none of the variables is shadowed. Verify that the value of your expression is the same as that of the original expression.

(let ([x 'a] [y 'b]) (list (let ([x 'c]) (cons x y)) (let ([y 'd]) (cons x y))))

(let ([x '((a b) c)]) (cons (let ([x (cdr x)]) (car x)) (let ([x (car x)]) (cons (let ([x (cdr x)]) (car x)) (cons (let ([x (car x)]) x) (cdr x))))))
Section 2.5. Lambda Expressions
In the expression (let ([x (* 3 4)]) (+ x x))
, the variable x
is bound to the value of (* 3 4)
. What if we would like the value of (+ x x)
where x
is bound to the value of (/ 99 11)
? Where x
is bound to the value of ( 2 7)
? In each case we need a different let
expression. When the body of the let
is complicated, however, having to repeat it can be inconvenient.
Instead, we can use the syntactic form lambda
to create a new procedure that has x
as a parameter and has the same body as the let
expression.
(lambda (x) (+ x x)) ⇒ #<procedure>
The general form of a lambda
expression is
(lambda (var ...) body_{1} body_{2} ...)
The variables var ...
are the formal parameters of the procedure, and the sequence of expressions body_{1} body_{2} ...
is its body. (Actually, the true general form is somewhat more general than this, as you will see later.)
A procedure is just as much an object as a number, string, symbol, or pair. It does not have any meaningful printed representation as far as Scheme is concerned, however, so this book uses the notation #<procedure>
to show that the value of an expression is a procedure.
The most common operation to perform on a procedure is to apply it to one or more values.
((lambda (x) (+ x x)) (* 3 4)) ⇒ 24
This is no different from any other procedure application. The procedure is the value of (lambda (x) (+ x x))
, and the only argument is the value of (* 3 4)
, or 12. The argument values, or actual parameters, are bound to the formal parameters within the body of the lambda
expression in the same way as let
bound variables are bound to their values. In this case, x
is bound to 12, and the value of (+ x x)
is 24. Thus, the result of applying the procedure to the value 12 is 24.
Because procedures are objects, we can establish a procedure as the value of a variable and use the procedure more than once.
(let ([double (lambda (x) (+ x x))])
(list (double (* 3 4))
(double (/ 99 11))
(double ( 2 7)))) ⇒ (24 18 10)
Here, we establish a binding for double
to a procedure, then use this procedure to double three different values.
The procedure expects its actual parameter to be a number, since it passes the actual parameter on to +
. In general, the actual parameter may be any sort of object. Consider, for example, a similar procedure that uses cons
instead of +
.
(let ([doublecons (lambda (x) (cons x x))])
(doublecons 'a)) ⇒ (a . a)
Noting the similarity between double
and doublecons
, you should not be surprised to learn that they may be collapsed into a single procedure by adding an additional argument.
(let ([doubleany (lambda (f x) (f x x))])
(list (doubleany + 13)
(doubleany cons 'a))) ⇒ (26 (a . a))
This demonstrates that procedures may accept more than one argument and that arguments passed to a procedure may themselves be procedures.
As with let
expressions, lambda
expressions become somewhat more interesting when they are nested within other lambda
or let
expressions.
(let ([x 'a])
(let ([f (lambda (y) (list x y))])
(f 'b))) ⇒ (a b)
The occurrence of x
within the lambda
expression refers to the x
outside the lambda
that is bound by the outer let
expression. The variable x
is said to occur free in the lambda
expression or to be a free variable of the lambda
expression. The variable y
does not occur free in the lambda
expression since it is bound by the lambda
expression. A variable that occurs free in a lambda
expression should be bound, e.g., by an enclosing lambda
or let
expression, unless the variable is (like the names of primitive procedures) bound outside of the expression, as we discuss in the following section.
What happens when the procedure is applied somewhere outside the scope of the bindings for variables that occur free within the procedure, as in the following expression?
(let ([f (let ([x 'sam])
(lambda (y z) (list x y z)))])
(f 'i 'am)) ⇒ (sam i am)
The answer is that the same bindings that were in effect when the procedure was created are in effect again when the procedure is applied. This is true even if another binding for x
is visible where the procedure is applied.
(let ([f (let ([x 'sam])
(lambda (y z) (list x y z)))])
(let ([x 'notsam])
(f 'i 'am))) ⇒ (sam i am)
In both cases, the value of x
within the procedure named f
is sam
.
Incidentally, a let
expression is nothing more than the direct application of a lambda
expression to a set of argument expressions. For example, the two expressions below are equivalent.
(let ([x 'a]) (cons x x)) ≡ ((lambda (x) (cons x x)) 'a)
In fact, a let
expression is a syntactic extension defined in terms of lambda
and procedure application, which are both core syntactic forms. In general, any expression of the form
(let ((var expr) ...) body_{1} body_{2} ...)
is equivalent to the following.
((lambda (var ...) body_{1} body_{2} ...)
expr ...)
See Section 3.1 for more about core forms and syntactic extensions.
As mentioned above, the general form of lambda
is a bit more complicated than the form we saw earlier, in that the formal parameter specification, (var …)
, need not be a proper list, or indeed even a list at all. The formal parameter specification can be in any of the following three forms:

a proper list of variables,
(var_{1} ... var_{n})
, such as we have already seen, 
a single variable,
var_{r}
, or 
an improper list of variables,
(var_{1} ... var_{n} . var_{r})
.
In the first case, exactly n actual parameters must be supplied, and each variable is bound to the corresponding actual parameter. In the second, any number of actual parameters is valid; all of the actual parameters are put into a single list and the single variable is bound to this list. The third case is a hybrid of the first two cases. At least n actual parameters must be supplied. The variables var_{1} ... var_{n}
are bound to the corresponding actual parameters, and the variable var_{r}
is bound to a list containing the remaining actual parameters. In the second and third cases, var_{r}
is sometimes referred to as a "rest" parameter because it holds the rest of the actual parameters beyond those that are individually named.
Let’s consider a few examples to help clarify the more general syntax of lambda
expressions.
(let ([f (lambda x x)])
(f 1 2 3 4)) ⇒ (1 2 3 4)
(let ([f (lambda x x)])
(f)) ⇒ ()
(let ([g (lambda (x . y) (list x y))])
(g 1 2 3 4)) ⇒ (1 (2 3 4))
(let ([h (lambda (x y . z) (list x y z))])
(h 'a 'b 'c 'd)) ⇒ (a b (c d))
In the first two examples, the procedure named f
accepts any number of arguments. These arguments are automatically formed into a list to which the variable x
is bound; the value of f
is this list. In the first example, the arguments are 1, 2, 3, and 4, so the answer is (1 2 3 4)
. In the second, there are no arguments, so the answer is the empty list ()
. The value of the procedure named g
in the third example is a list whose first element is the first argument and whose second element is a list containing the remaining arguments. The procedure named h
is similar but separates out the second argument. While f
accepts any number of arguments, g
must receive at least one and h
must receive at least two.
Exercise 2.5.1
Determine the values of the expressions below.

(let ([f (lambda (x) x)]) (f 'a))

(let ([f (lambda x x)]) (f 'a))

(let ([f (lambda (x . y) x)]) (f 'a))

(let ([f (lambda (x . y) y)]) (f 'a))
Exercise 2.5.2
How might the primitive procedure list
be defined?
Exercise 2.5.3
List the variables that occur free in each of the lambda
expressions below. Do not omit variables that name primitive procedures such as +
or cons
.

(lambda (f x) (f x))

(lambda (x) (+ x x))

(lambda (x y) (f x y))

(lambda (x) (cons x (f x y)))

(lambda (x) (let ([z (cons x y)]) (x y z)))

(lambda (x) (let ([y (cons x y)]) (x y z)))
Section 2.6. TopLevel Definitions
The variables bound by let
and lambda
expressions are not visible outside the bodies of these expressions. Suppose you have created an object, perhaps a procedure, that must be accessible anywhere, like +
or cons
. What you need is a toplevel definition, which may be established with define
. Toplevel definitions, which are supported by most interactive Scheme systems, are visible in every expression you enter, except where shadowed by another binding.
Let’s establish a toplevel definition of the doubleany
procedure of the last section.
(define doubleany
(lambda (f x)
(f x x)))
The variable doubleany
now has the same status as cons
or the name of any other primitive procedure. We can use doubleany
as if it were a primitive procedure.
(doubleany + 10) ⇒ 20
(doubleany cons 'a) ⇒ (a . a)
A toplevel definition may be established for any object, not just for procedures.
(define sandwich "peanutbutterandjelly")
sandwich ⇒ "peanutbutterandjelly"
Most often, though, toplevel definitions are used for procedures.
As suggested above, toplevel definitions may be shadowed by let
or lambda
bindings.
(define xyz '(x y z))
(let ([xyz '(z y x)])
xyz) ⇒ (z y x)
Variables with toplevel definitions act almost as if they were bound by a let
expression enclosing all of the expressions you type.
Given only the simple tools you have read about up to this point, it is already possible to define some of the primitive procedures provided by Scheme and described later in this book. If you completed the exercises from the last section, you should already know how to define list
.
(define list (lambda x x))
Also, Scheme provides the abbreviations cadr
and cddr
for the compositions of car
with cdr
and cdr
with cdr
. That is, (cadr list)
is equivalent to (car (cdr list))
, and, similarly, (cddr list)
is equivalent to (cdr (cdr list))
. They are easily defined as follows.
(define cadr
(lambda (x)
(car (cdr x))))
(define cddr
(lambda (x)
(cdr (cdr x))))
(cadr '(a b c)) ⇒ b
(cddr '(a b c)) ⇒ (c)
Any definition (define var expr)
where expr
is a lambda
expression can be written in a shorter form that suppresses the lambda
. The exact syntax depends upon the format of the lambda
expression’s formal parameter specifier, i.e., whether it is a proper list of variables, a single variable, or an improper list of variables. A definition of the form
(define var_{0}
(lambda (var_{1} ... var_{n})
e_{1} e_{2} ...))
may be abbreviated
(define (var_{0} var_{1} ... var_{n})
e_{1} e_{2} ...)
while
(define var_{0}
(lambda var_{r}
e_{1} e_{2} ...))
may be abbreviated
(define (var_{0} . var_{r})
e_{1} e_{2} ...)
and
(define var_{0}
(lambda (var_{1} ... var_{n} . var_{r})
e_{1} e_{2} ...))
may be abbreviated
(define (var_{0} var_{1} ... var_{n} . var_{r})
e_{1} e_{2} ...)
For example, the definitions of cadr
and list
might be written as follows.
(define (cadr x)
(car (cdr x)))
(define (list . x) x)
This book does not often employ this alternative syntax. Although it is shorter, it tends to mask the reality that procedures are not intimately tied to variables, or names, as they are in many other languages. This syntax is often referred to, somewhat pejoratively, as the "defun" syntax for define
, after the defun
form provided by Lisp languages in which procedures are more closely tied to their names.
Toplevel definitions make it easier for us to experiment with a procedure interactively because we need not retype the procedure each time it is used. Let’s try defining a somewhat more complicated variation of doubleany
, one that turns an "ordinary" twoargument procedure into a "doubling" oneargument procedure.
(define doubler
(lambda (f)
(lambda (x) (f x x))))
doubler
accepts one argument, f
, which must be a procedure that accepts two arguments. The procedure returned by doubler
accepts one argument, which it uses for both arguments in an application of f
. We can define, with doubler
, the simple double
and doublecons
procedures of the last section.
(define double (doubler +))
(double 13/2) ⇒ 13
(define doublecons (doubler cons))
(doublecons 'a) ⇒ (a . a)
We can also define doubleany
with doubler
.
(define doubleany
(lambda (f x)
((doubler f) x)))
Within double
and doublecons
, f
has the appropriate value, i.e., +
or cons
, even though the procedures are clearly applied outside the scope of f
.
What happens if you attempt to use a variable that is not bound by a let
or lambda
expression and that does not have a toplevel definition? Try using the variable iamnotdefined
to see what happens.
(iamnotdefined 3)
Most Scheme systems print a message indicating that an unbound or undefinedvariable exception has occurred.
The system should not, however, complain about the appearance of an undefined variable within a lambda
expression, until and unless the resulting procedure is applied. The following should not cause an exception, even though we have not yet established a toplevel definition of proc2
.
(define proc1
(lambda (x y)
(proc2 y x)))
If you try to apply proc1
before defining proc2
, you should get a undefined exception message. Let’s give proc2
a toplevel definition and try proc1
.
(define proc2 cons)
(proc1 'a 'b) ⇒ (b . a)
When you define proc1
, the system accepts your promise to define proc2
, and does not complain unless you use proc1
before defining proc2
. This allows you to define procedures in any order you please. This is especially useful when you are trying to organize a file full of procedure definitions in a way that makes your program more readable. It is necessary when two procedures defined at top level depend upon each other; we will see some examples of this later.
Exercise 2.6.1
What would happen if you were to type
(doubleany doubleany doubleany)
given the definition of doubleany
from the beginning of this section?
Exercise 2.6.2
A more elegant (though possibly less efficient) way to define cadr
and cddr
than given in this section is to define a procedure that composes two procedures to create a third. Write the procedure compose
, such that (compose p_{1} p_{2})
is the composition of p_{1}
and p_{2}
(assuming both take one argument). That is, (compose p_{1} p_{2})
should return a new procedure of one argument that applies p_{1}
to the result of applying p_{2}
to the argument. Use compose
to define cadr
and cddr
.
Exercise 2.6.3
Scheme also provides caar
, cdar
, caaar
, caadr
, and so on, with any combination of up to four a
's (representing car
) and d
's (representing cdr
) between the c
and the r
(see Section 6.3). Define each of these with the compose
procedure of the preceding exercise.
Section 2.7. Conditional Expressions
So far we have considered expressions that perform a given task unconditionally. Suppose that we wish to write the procedure abs
. If its argument x is negative, abs
returns x; otherwise, it returns x. The most straightforward way to write abs
is to determine whether the argument is negative and if so negate it, using the if
syntactic form.
(define abs
(lambda (n)
(if (< n 0)
( 0 n)
n)))
(abs 77) ⇒ 77
(abs 77) ⇒ 77
An if
expression has the form (if test consequent alternative)
, where consequent
is the expression to evaluate if test
is true and alternative
is the expression to evaluate if test
is false. In the expression above, test
is (< n 0)
, consequent
is ( 0 n)
, and alternative
is n
.
The procedure abs
could be written in a variety of other ways. Any of the following are valid definitions of abs
.
(define abs
(lambda (n)
(if (>= n 0)
n
( 0 n))))
(define abs
(lambda (n)
(if (not (< n 0))
n
( 0 n))))
(define abs
(lambda (n)
(if (or (> n 0) (= n 0))
n
( 0 n))))
(define abs
(lambda (n)
(if (= n 0)
0
(if (< n 0)
( 0 n)
n))))
(define abs
(lambda (n)
((if (>= n 0) + )
0
n)))
The first of these definitions asks if n
is greater than or equal to zero, inverting the test. The second asks if n
is not less than zero, using the procedure not
with <
. The third asks if n
is greater than zero or n
is equal to zero, using the syntactic form or
. The fourth treats zero separately, though there is no benefit in doing so. The fifth is somewhat tricky; n
is either added to or subtracted from zero, depending upon whether n
is greater than or equal to zero.
Why is if
a syntactic form and not a procedure? In order to answer this, let’s revisit the definition of reciprocal
from the first section of this chapter.
(define reciprocal
(lambda (n)
(if (= n 0)
"oops!"
(/ 1 n))))
The second argument to the division procedure should not be zero, since the result is mathematically undefined. Our definition of reciprocal
avoids this problem by testing for zero before dividing. Were if
a procedure, its arguments (including (/ 1 n)
) would be evaluated before it had a chance to choose between the consequent and alternative. Like quote
, which does not evaluate its only subexpression, if
does not evaluate all of its subexpressions and so cannot be a procedure.
The syntactic form or
operates in a manner similar to if
. The general form of an or
expression is (or expr ...)
. If there are no subexpressions, i.e., the expression is simply (or)
, the value is false. Otherwise, each expr
is evaluated in turn until either (a) one of the expressions evaluates to true or (b) no more expressions are left. In case (a), the value is true; in case (b), the value is false.
To be more precise, in case (a), the value of the or
expression is the value of the last subexpression evaluated. This clarification is necessary because there are many possible true values. Usually, the value of a test expression is one of the two objects #t
, for true, or #f
, for false.
(< 1 0) ⇒ #t
(> 1 0) ⇒ #f
Every Scheme object, however, is considered to be either true or false by conditional expressions and by the procedure not
. Only #f
is considered false; all other objects are considered true.
(if #t 'true 'false) ⇒ true
(if #f 'true 'false) ⇒ false
(if '() 'true 'false) ⇒ true
(if 1 'true 'false) ⇒ true
(if '(a b c) 'true 'false) ⇒ true
(not #t) ⇒ #f
(not "false") ⇒ #f
(not #f) ⇒ #t
(or) ⇒ #f
(or #f) ⇒ #f
(or #f #t) ⇒ #t
(or #f 'a #f) ⇒ a
The and
syntactic form is similar in form to or
, but an and
expression is true if all its subexpressions are true, and false otherwise. In the case where there are no subexpressions, i.e., the expression is simply (and)
, the value is true. Otherwise, the subexpressions are evaluated in turn until either no more subexpressions are left or the value of a subexpression is false. The value of the and
expression is the value of the last subexpression evaluated.
Using and
, we can define a slightly different version of reciprocal
.
(define reciprocal
(lambda (n)
(and (not (= n 0))
(/ 1 n))))
(reciprocal 3) ⇒ 1/3
(reciprocal 0.5) ⇒ 2.0
(reciprocal 0) ⇒ #f
In this version, the value is #f
if n
is zero and 1/n
otherwise.
The procedures =
, <
, >
, <=
, and >=
are called predicates. A predicate is a procedure that answers a specific question about its arguments and returns one of the two values #t
or #f
. The names of most predicates end with a question mark ( ?
); the common numeric procedures listed above are exceptions to this rule. Not all predicates require numeric arguments, of course. The predicate null?
returns true if its argument is the empty list ()
and false otherwise.
(null? '()) ⇒ #t
(null? 'abc) ⇒ #f
(null? '(x y z)) ⇒ #f
(null? (cdddr '(x y z))) ⇒ #t
The procedure cdr
must not be passed anything other than a pair, and an exception is raised when this happens. Common Lisp, however, defines (cdr '())
to be ()
. The following procedure, lispcdr
, is defined using null?
to return ()
if its argument is ()
.
(define lispcdr
(lambda (x)
(if (null? x)
'()
(cdr x))))
(lispcdr '(a b c)) ⇒ (b c)
(lispcdr '(c)) ⇒ ()
(lispcdr '()) ⇒ ()
Another useful predicate is eqv?
, which requires two arguments. If the two arguments are equivalent, eqv?
returns true. Otherwise, eqv?
returns false.
(eqv? 'a 'a) ⇒ #t
(eqv? 'a 'b) ⇒ #f
(eqv? #f #f) ⇒ #t
(eqv? #t #t) ⇒ #t
(eqv? #f #t) ⇒ #f
(eqv? 3 3) ⇒ #t
(eqv? 3 2) ⇒ #f
(let ([x "Hi Mom!"])
(eqv? x x)) ⇒ #t
(let ([x (cons 'a 'b)])
(eqv? x x)) ⇒ #t
(eqv? (cons 'a 'b) (cons 'a 'b)) ⇒ #f
As you can see, eqv?
returns true if the arguments are the same symbol, boolean, number, pair, or string. Two pairs are not the same by eqv?
if they are created by different calls to cons
, even if they have the same contents. Detailed equivalence rules for eqv?
are given in Section 6.2.
Scheme also provides a set of type predicates that return true or false depending on the type of the object, e.g., pair?
, symbol?
, number?
, and string?
. The predicate pair?
, for example, returns true only if its argument is a pair.
(pair? '(a . c)) ⇒ #t
(pair? '(a b c)) ⇒ #t
(pair? '()) ⇒ #f
(pair? 'abc) ⇒ #f
(pair? "Hi Mom!") ⇒ #f
(pair? 1234567890) ⇒ #f
Type predicates are useful for deciding if the argument passed to a procedure is of the appropriate type. For example, the following version of reciprocal
checks first to see that its argument is a number before testing against zero or performing the division.
(define reciprocal
(lambda (n)
(if (and (number? n) (not (= n 0)))
(/ 1 n)
"oops!")))
(reciprocal 2/3) ⇒ 3/2
(reciprocal 'a) ⇒ "oops!"
By the way, the code that uses reciprocal
must check to see that the returned value is a number and not a string. To relieve the caller of this obligation, it is usually preferable to report the error, using assertionviolation
, as follows.
(define reciprocal
(lambda (n)
(if (and (number? n) (not (= n 0)))
(/ 1 n)
(assertionviolation 'reciprocal
"improper argument"
n))))
(reciprocal .25) ⇒ 4.0
(reciprocal 0) ⇒ exception in reciprocal: improper argument 0
(reciprocal 'a) ⇒ exception in reciprocal: improper argument a
The first argument to assertionviolation
is a symbol identifying where the message originates, the second is a string describing the error, and the third and subsequent arguments are "irritants" to be included with the error message.
Let’s look at one more conditional expression, cond
, that is often useful in place of if
. cond
is similar to if
except that it allows multiple test and alternative expressions. Consider the following definition of sign
, which returns 1
for negative inputs, +1
for positive inputs, and 0
for zero.
(define sign
(lambda (n)
(if (< n 0)
1
(if (> n 0)
+1
0))))
(sign 88.3) ⇒ 1
(sign 0) ⇒ 0
(sign 333333333333) ⇒ 1
(* (sign 88.3) (abs 88.3)) ⇒ 88.3
The two if
expressions may be replaced by a single cond
expression as follows.
(define sign
(lambda (n)
(cond
[(< n 0) 1]
[(> n 0) +1]
[else 0])))
A cond
expression usually takes the form
(cond (test expr) ... (else expr))
though the else
clause may be omitted. This should be done only when there is no possibility that all the tests will fail, as in the new version of sign
below.
(define sign
(lambda (n)
(cond
[(< n 0) 1]
[(> n 0) +1]
[(= n 0) 0])))
These definitions of sign
do not depend on the order in which the tests are performed, since only one of the tests can be true for any value of n
. The following procedure computes the tax on a given amount of income in a progressive tax system with breakpoints at 10,000, 20,000, and 30,000 dollars.
(define incometax
(lambda (income)
(cond
[(<= income 10000) (* income .05)]
[(<= income 20000) (+ (* ( income 10000) .08) 500.00)]
[(<= income 30000) (+ (* ( income 20000) .13) 1300.00)]
[else (+ (* ( income 30000) .21) 2600.00)])))
(incometax 5000) ⇒ 250.0
(incometax 15000) ⇒ 900.0
(incometax 25000) ⇒ 1950.0
(incometax 50000) ⇒ 6800.0
In this example, the order in which the tests are performed, left to right (top to bottom), is significant.
Exercise 2.7.1
Define the predicate atom?
, which returns true if its argument is not a pair and false if it is.
Exercise 2.7.2
The procedure length
returns the length of its argument, which must be a list. For example, (length '(a b c))
is 3. Using length
, define the procedure shorter
, which returns the shorter of two list arguments. Have it return the first list if they have the same length.
(shorter '(a b) '(c d e)) ⇒ (a b)
(shorter '(a b) '(c d)) ⇒ (a b)
(shorter '(a b) '(c)) ⇒ (c)
Section 2.8. Simple Recursion
We have seen how we can control whether or not expressions are evaluated with if
, and
, or
, and cond
. We can also perform an expression more than once by creating a procedure containing the expression and invoking the procedure more than once. What if we need to perform some expression repeatedly, say for all the elements of a list or all the numbers from one to ten? We can do so via recursion. Recursion is a simple concept: the application of a procedure from within that procedure. It can be tricky to master recursion at first, but once mastered it provides expressive power far beyond ordinary looping constructs.
A recursive procedure is a procedure that applies itself. Perhaps the simplest recursive procedure is the following, which we will call goodbye
.
(define goodbye
(lambda ()
(goodbye)))
(goodbye) ⇒
This procedure takes no arguments and simply applies itself immediately. There is no value after the ⇒ because goodbye
never returns.
Obviously, to make practical use out of a recursive procedure, we must have some way to terminate the recursion. Most recursive procedures should have at least two basic elements, a base case and a recursion step. The base case terminates the recursion, giving the value of the procedure for some base argument. The recursion step gives the value in terms of the value of the procedure applied to a different argument. In order for the recursion to terminate, the different argument must be closer to the base argument in some way.
Let’s consider the problem of finding the length of a proper list recursively. We need a base case and a recursion step. The logical base argument for recursion on lists is nearly always the empty list. The length of the empty list is zero, so the base case should give the value zero for the empty list. In order to become closer to the empty list, the natural recursion step involves the cdr of the argument. A nonempty list is one element longer than its cdr, so the recursion step gives the value as one more than the length of the cdr of the list.
(define length
(lambda (ls)
(if (null? ls)
0
(+ (length (cdr ls)) 1))))
(length '()) ⇒ 0
(length '(a)) ⇒ 1
(length '(a b)) ⇒ 2
The if
expression asks if the list is empty. If so, the value is zero. This is the base case. If not, the value is one more than the length of the cdr of the list. This is the recursion step.
Many Scheme implementations allow you to trace the execution of a procedure to see how it operates. In Chez Scheme, for example, one way to trace a procedure is to type (trace name)
, where name
is the name of a procedure you have defined at top level. If you trace length
as defined above and pass it the argument '(a b c d)
, you should see something like this:
(length (a b c d))
 (length (b c d))
 (length (c d))
  (length (d))
  (length ())
  0
  1
 2
 3
4
The indentation shows the nesting level of the recursion; the vertical lines associate applications visually with their values. Notice that on each application of length
the list gets smaller until it finally reaches ()
. The value at ()
is 0, and each outer level adds 1 to arrive at the final value.
Let’s write a procedure, listcopy
, that returns a copy of its argument, which must be a list. That is, listcopy
returns a new list consisting of the elements (but not the pairs) of the old list. Making a copy might be useful if either the original list or the copy might be altered via setcar!
or setcdr!
, which we discuss later.
(listcopy '()) ⇒ ()
(listcopy '(a b c)) ⇒ (a b c)
See if you can define listcopy
before studying the definition below.
(define listcopy
(lambda (ls)
(if (null? ls)
'()
(cons (car ls)
(listcopy (cdr ls))))))
The definition of listcopy
is similar to the definition of length
. The test in the base case is the same, (null? ls)
. The value in the base case is ()
, however, not 0, because we are building up a list, not a number. The recursive call is the same, but instead of adding one, listcopy
conses the car of the list onto the value of the recursive call.
There is no reason why there cannot be more than one base case. The procedure memv
takes two arguments, an object and a list. It returns the first sublist, or tail, of the list whose car is equal to the object, or #f
if the object is not found in the list. The value of memv
may be used as a list or as a truth value in a conditional expression.
(define memv
(lambda (x ls)
(cond
[(null? ls) #f]
[(eqv? (car ls) x) ls]
[else (memv x (cdr ls))])))
(memv 'a '(a b b d)) ⇒ (a b b d)
(memv 'b '(a b b d)) ⇒ (b b d)
(memv 'c '(a b b d)) ⇒ #f
(memv 'd '(a b b d)) ⇒ (d)
(if (memv 'b '(a b b d))
"yes"
"no") ⇒ "yes"
Here there are two conditions to check, hence the use of cond
. The first cond clause checks for the base value of ()
; no object is a member of ()
, so the answer is #f
. The second clause asks if the car of the list is the object, in which case the list is returned, being the first tail whose car contains the object. The recursion step just continues down the list.
There may also be more than one recursion case. Like memv
, the procedure remv
defined below takes two arguments, an object and a list. It returns a new list with all occurrences of the object removed from the list.
(define remv
(lambda (x ls)
(cond
[(null? ls) '()]
[(eqv? (car ls) x) (remv x (cdr ls))]
[else (cons (car ls) (remv x (cdr ls)))])))
(remv 'a '(a b b d)) ⇒ (b b d)
(remv 'b '(a b b d)) ⇒ (a d)
(remv 'c '(a b b d)) ⇒ (a b b d)
(remv 'd '(a b b d)) ⇒ (a b b)
This definition is similar to the definition of memv
above, except remv
does not quit once it finds the element in the car of the list. Rather, it continues, simply ignoring the element. If the element is not found in the car of the list, remv
does the same thing as listcopy
above: it conses the car of the list onto the recursive value.
Up to now, the recursion has been only on the cdr of a list. It is sometimes useful, however, for a procedure to recur on the car as well as the cdr of the list. The procedure treecopy
defined below treats the structure of pairs as a tree rather than as a list, with the left subtree being the car of the pair and the right subtree being the cdr of the pair. It performs a similar operation to listcopy
, building new pairs while leaving the elements (leaves) alone.
(define treecopy
(lambda (tr)
(if (not (pair? tr))
tr
(cons (treecopy (car tr))
(treecopy (cdr tr))))))
(treecopy '((a . b) . c)) ⇒ ((a . b) . c)
The natural base argument for a tree structure is anything that is not a pair, since the recursion traverses pairs rather than lists. The recursive step in this case is doubly recursive, finding the value recursively for the car as well as the cdr of the argument.
At this point, readers who are familiar with other languages that provide special iteration constructs, e.g., while or for loops, might wonder whether similar constructs are required in Scheme. Such constructs are unnecessary; iteration in Scheme is expressed more clearly and succinctly via recursion. Recursion is more general and eliminates the need for the variable assignments required by many other languages' iteration constructs, resulting in code that is more reliable and easier to follow. Some recursion is essentially iteration and executes as such; Section 3.2 has more to say about this. Often, there is no need to make a distinction, however. Concentrate instead on writing clear, concise, and correct programs.
Before we leave the topic of recursion, let’s consider a special form of repetition called mapping. Consider the following procedure, absall
, that takes a list of numbers as input and returns a list of their absolute values.
(define absall
(lambda (ls)
(if (null? ls)
'()
(cons (abs (car ls))
(absall (cdr ls))))))
(absall '(1 2 3 4 5 6)) ⇒ (1 2 3 4 5 6)
This procedure forms a new list from the input list by applying the procedure abs
to each element. We say that absall
maps abs
over the input list to produce the output list. Mapping a procedure over a list is a fairly common thing to do, so Scheme provides the procedure map
, which maps its first argument, a procedure, over its second, a list. We can use map
to define absall
.
(define absall
(lambda (ls)
(map abs ls)))
We really do not need absall
, however, since the corresponding direct application of map
is just as short and perhaps clearer.
(map abs '(1 2 3 4 5 6)) ⇒ (1 2 3 4 5 6)
Of course, we can use lambda
to create the procedure argument to map
, e.g., to square the elements of a list of numbers.
(map (lambda (x) (* x x))
'(1 3 5 7)) ⇒ (1 9 25 49)
We can map a multipleargument procedure over multiple lists, as in the following example.
(map cons '(a b c) '(1 2 3)) ⇒ ((a . 1) (b . 2) (c . 3))
The lists must be of the same length, and the procedure should accept as many arguments as there are lists. Each element of the output list is the result of applying the procedure to corresponding members of the input list.
Looking at the first definition of absall
above, you should be able to derive, before studying it, the following definition of map1
, a restricted version of map
that maps a oneargument procedure over a single list.
(define map1
(lambda (p ls)
(if (null? ls)
'()
(cons (p (car ls))
(map1 p (cdr ls))))))
(map1 abs '(1 2 3 4 5 6)) ⇒ (1 2 3 4 5 6)
All we have done is to replace the call to abs
in absall
with a call to the new parameter p
. A definition of the more general map
is given in Section 5.4.
Exercise 2.8.1
Describe what would happen if you switched the order of the arguments to cons
in the definition of treecopy
.
Exercise 2.8.2
Consult Section 6.3 for the description of append
and define a twoargument version of it. What would happen if you switched the order of the arguments in the call to append
within your definition of append
?
Exercise 2.8.3
Define the procedure makelist
, which takes a nonnegative integer n
and an object and returns a new list, n
long, each element of which is the object.
(makelist 7 '()) ⇒ (() () () () () () ())
[Hint: The base test should be (= n 0)
, and the recursion step should involve ( n 1)
. Whereas ()
is the natural base case for recursion on lists, 0 is the natural base case for recursion on nonnegative integers. Similarly, subtracting 1 is the natural way to bring a nonnegative integer closer to 0.]
Exercise 2.8.4
The procedures listref
and listtail
return the nth element and nth tail of a list ls.
(listref '(1 2 3 4) 0) ⇒ 1
(listtail '(1 2 3 4) 0) ⇒ (1 2 3 4)
(listref '(a short (nested) list) 2) ⇒ (nested)
(listtail '(a short (nested) list) 2) ⇒ ((nested) list)
Define both procedures.
Exercise 2.8.5
Exercise 2.7.2 had you use length
in the definition of shorter
, which returns the shorter of its two list arguments, or the first if the two have the same length. Write shorter
without using length
. [Hint: Define a recursive helper, shorter?
, and use it in place of the length comparison.]
Exercise 2.8.6
All of the recursive procedures shown so far have been directly recursive. That is, each procedure directly applies itself to a new argument. It is also possible to write two procedures that use each other, resulting in indirect recursion. Define the procedures odd?
and even?
, each in terms of the other. [Hint: What should each return when its argument is 0?]
(even? 17) ⇒ #f
(odd? 17) ⇒ #t
Exercise 2.8.7
Use map
to define a procedure, transpose
, that takes a list of pairs and returns a pair of lists as follows.
(transpose '((a . 1) (b . 2) (c . 3))) ⇒ ((a b c) 1 2 3)
[Hint: ((a b c) 1 2 3)
is the same as ((a b c) . (1 2 3))
.]
Section 2.9. Assignment
Although many programs can be written without them, assignments to toplevel variables or let
bound and lambda
bound variables are sometimes useful. Assignments do not create new bindings, as with let
or lambda
, but rather change the values of existing bindings. Assignments are performed with set!
.
(define abcde '(a b c d e))
abcde ⇒ (a b c d e)
(set! abcde (cdr abcde))
abcde ⇒ (b c d e)
(let ([abcde '(a b c d e)])
(set! abcde (reverse abcde))
abcde) ⇒ (e d c b a)
Many languages require the use of assignments to initialize local variables, separate from the declaration or binding of the variables. In Scheme, all local variables are given a value immediately upon binding. Besides making the separate assignment to initialize local variables unnecessary, it ensures that the programmer cannot forget to initialize them, a common source of errors in most languages.
In fact, most of the assignments that are either necessary or convenient in other languages are both unnecessary and inconvenient in Scheme, since there is typically a clearer way to express the same algorithm without assignments. One common practice in some languages is to sequence expression evaluation with a series of assignments, as in the following procedure that finds the roots of a quadratic equation.
(define quadraticformula
(lambda (a b c)
(let ([root1 0] [root2 0] [minusb 0] [radical 0] [divisor 0])
(set! minusb ( 0 b))
(set! radical (sqrt ( (* b b) (* 4 (* a c)))))
(set! divisor (* 2 a))
(set! root1 (/ (+ minusb radical) divisor))
(set! root2 (/ ( minusb radical) divisor))
(cons root1 root2))))
The roots are computed according to the wellknown quadratic formula,
which yields the solutions to the equation \(0 = ax^2 + bx + c\). The let
expression in this definition is employed solely to establish the variable bindings, corresponding to the declarations required in other languages. The first three assignment expressions compute subpieces of the formula, namely \(b\), \(\sqrt{b^2  4ac}\), and \(2a\). The last two assignment expressions compute the two roots in terms of the subpieces. A pair of the two roots is the value of quadraticformula
. For example, the two roots of \(2x^2  4x  6\) are \(x = 3\) and \(x = 1\).
(quadraticformula 2 4 6) ⇒ (3 . 1)
The definition above works, but it can be written more clearly without the assignments, as shown below.
(define quadraticformula
(lambda (a b c)
(let ([minusb ( 0 b)]
[radical (sqrt ( (* b b) (* 4 (* a c))))]
[divisor (* 2 a)])
(let ([root1 (/ (+ minusb radical) divisor)]
[root2 (/ ( minusb radical) divisor)])
(cons root1 root2)))))
In this version, the set!
expressions are gone, and we are left with essentially the same algorithm. By employing two let
expressions, however, the definition makes clear the dependency of root1
and root2
on the values of minusb
, radical
, and divisor
. Equally important, the let
expressions make clear the lack of dependencies among minusb
, radical
, and divisor
and between root1
and root2
.
Assignments do have some uses in Scheme, otherwise the language would not support them. Consider the following version of cons
that counts the number of times it is called, storing the count in a variable named conscount
. It uses set!
to increment the count; there is no way to achieve the same behavior without assignments.
(define konscount 0)
(define kons
(lambda (x y)
(set! konscount (+ konscount 1))
(cons x y)))
(kons 'a '(b c)) ⇒ (a b c)
konscount ⇒ 1
(kons 'a (kons 'b (kons 'c '()))) ⇒ (a b c)
konscount ⇒ 4
Assignments are commonly used to implement procedures that must maintain some internal state. For example, suppose we would like to define a procedure that returns 0 the first time it is called, 1 the second time, 2 the third time, and so on indefinitely. We could write something similar to the definition of conscount
above:
(define next 0)
(define count
(lambda ()
(let ([v next])
(set! next (+ next 1))
v)))
(count) ⇒ 0
(count) ⇒ 1
This solution is somewhat undesirable in that the variable next
is visible at top level even though it need not be. Since it is visible at top level, any code in the system can change its value, perhaps inadvertently affecting the behavior of count
in a subtle way. We can solve this problem by let
binding next
outside of the lambda
expression:
(define count
(let ([next 0])
(lambda ()
(let ([v next])
(set! next (+ next 1))
v))))
The latter solution also generalizes easily to provide multiple counters, each with its own local counter. The procedure makecounter
, defined below, returns a new counting procedure each time it is called.
(define makecounter
(lambda ()
(let ([next 0])
(lambda ()
(let ([v next])
(set! next (+ next 1))
v)))))
Since next
is bound inside of makecounter
but outside of the procedure returned by makecounter
, each procedure it returns maintains its own unique counter.
(define count1 (makecounter))
(define count2 (makecounter))
(count1) ⇒ 0
(count2) ⇒ 0
(count1) ⇒ 1
(count1) ⇒ 2
(count2) ⇒ 1
If a state variable must be shared by more than one procedure defined at top level, but we do not want the state variable to be visible at top level, we can use let
to bind the variable and set!
to make the procedures visible at top level.
(define shhh #f)
(define tell #f)
(let ([secret 0])
(set! shhh
(lambda (message)
(set! secret message)))
(set! tell
(lambda ()
secret)))
(shhh "sally likes harry")
(tell) ⇒ "sally likes harry"
secret ⇒ exception: variable secret is not bound
Variables must be defined before they can be assigned, so we define shhh
and tell
to be #f
initially. (Any initial value would do.) We’ll see this structure again in Section 3.5 and a better way to structure code like this as a library in Section 3.6.
Local state is sometimes useful for caching computed values or allowing a computation to be evaluated lazily, i.e., only once and only on demand. The procedure lazy
below accepts a thunk, or zeroargument procedure, as an argument. Thunks are often used to "freeze" computations that must be delayed for some reason, which is exactly what we need to do in this situation. When passed a thunk t
, lazy
returns a new thunk that, when invoked, returns the value of invoking t
. Once computed, the value is saved in a local variable so that the computation need not be performed again. A boolean flag is used to record whether t
has been invoked and its value saved.
(define lazy
(lambda (t)
(let ([val #f] [flag #f])
(lambda ()
(if (not flag)
(begin (set! val (t))
(set! flag #t)))
val))))
The syntactic form begin
, used here for the first time, evaluates its subexpressions in sequence from left to right and returns the value of the last subexpression, like the body of a let
or lambda
expression. We also see that the alternative
subexpression of an if
expression can be omitted. This should be done only when the value of the if
is discarded, as it is in this case.
Lazy evaluation is especially useful for values that require considerable time to compute. By delaying the evaluation, we might avoid computing the value altogether, and by saving the value, we avoid computing it more than once.
The operation of lazy
can best be illustrated by printing a message from within a thunk passed to lazy
.
(define p
(lazy (lambda ()
(display "Ouch!")
(newline)
"got me")))
The first time p
is invoked, the message Ouch!
is printed and the string "got me"
is returned. Thereafter, "got me"
is returned but the message is not printed. The procedures display
and newline
are the first examples of explicit input/output we have seen; display
prints the string without quotation marks, and newline
prints a newline character.
To further illustrate the use of set!
, let’s consider the implementation of stack objects whose internal workings are not visible on the outside. A stack object accepts one of four messages: empty?
, which returns #t
if the stack is empty; push!
, which adds an object to the top of the stack; top
, which returns the object on the top of the stack; and pop!
, which removes the object on top of the stack. The procedure makestack
given below creates a new stack each time it is called in a manner similar to makecounter
.
(define makestack
(lambda ()
(let ([ls '()])
(lambda (msg . args)
(cond
[(eqv? msg 'empty?) (null? ls)]
[(eqv? msg 'push!) (set! ls (cons (car args) ls))]
[(eqv? msg 'top) (car ls)]
[(eqv? msg 'pop!) (set! ls (cdr ls))]
[else "oops"])))))
Each stack is stored as a list bound to the variable ls
; set!
is used to change this binding for push!
and pop!
. Notice that the argument list of the inner lambda
expression uses the improper list syntax to bind args
to a list of all arguments but the first. This is useful here because in the case of empty?
, top
, and pop!
there is only one argument (the message), but in the case of push!
there are two (the message and the object to push onto the stack).
(define stack1 (makestack))
(define stack2 (makestack))
(list (stack1 'empty?) (stack2 'empty?)) ⇒ (#t #t)
(stack1 'push! 'a)
(list (stack1 'empty?) (stack2 'empty?)) ⇒ (#f #t)
(stack1 'push! 'b)
(stack2 'push! 'c)
(stack1 'top) ⇒ b
(stack2 'top) ⇒ c
(stack1 'pop!)
(stack1 'top) ⇒ a
(list (stack1 'empty?) (stack2 'empty?)) ⇒ (#f #f)
(stack1 'pop!)
(list (stack1 'empty?) (stack2 'empty?)) ⇒ (#t #f)
As with the counters created by makecounter
, the state maintained by each stack object is directly accessible only within the object. Each reference or change to this state is made explicitly by the object itself. One important benefit is that we can change the internal structure of the stack, perhaps to use a vector (see Section 6.9) instead of a list to hold the elements, without changing its external behavior. Because the behavior of the object is known abstractly (not operationally), it is known as an abstract object. See Section 12.8 for more about creating abstract objects.
In addition to changing the values of variables, we can also change the values of the car and cdr fields of a pair, using the procedures setcar!
and setcdr!
.
(define p (list 1 2 3))
(setcar! (cdr p) 'two)
p ⇒ (1 two 3)
(setcdr! p '())
p ⇒ (1)
We can use these operators to define a queue data type, which is like a stack except that new elements are added at one end and extracted from the other. The following queue implementation uses a tconc structure. A tconc consists of a nonempty list and a header. The header is a pair whose car points to the first pair (head) of the list and whose cdr points to the last pair (end) of the list.
The last element of the list is a placeholder and not considered part of the queue.
Four operations on queues are defined below: makequeue
, which constructs a queue; putq!
, which adds an element to the end of a queue; getq
, which retrieves the element at the front of a queue; and delq!
, which removes the element at the front of a queue.
(define makequeue
(lambda ()
(let ([end (cons 'ignored '())])
(cons end end))))
(define putq!
(lambda (q v)
(let ([end (cons 'ignored '())])
(setcar! (cdr q) v)
(setcdr! (cdr q) end)
(setcdr! q end))))
(define getq
(lambda (q)
(car (car q))))
(define delq!
(lambda (q)
(setcar! q (cdr (car q)))))
All are simple operations except for putq!
, which modifies the end pair to contain the new value and adds a new end pair.
(define myq (makequeue))
(putq! myq 'a)
(putq! myq 'b)
(getq myq) ⇒ a
(delq! myq)
(getq myq) ⇒ b
(delq! myq)
(putq! myq 'c)
(putq! myq 'd)
(getq myq) ⇒ c
(delq! myq)
(getq myq) ⇒ d
Exercise 2.9.1
Modify makecounter
to take two arguments: an initial value for the counter to use in place of 0 and an amount to increment the counter by each time.
Exercise 2.9.2
Look up the description of case
in Section 5.3. Replace the cond
expression in makestack
with an equivalent case
expression. Add mt?
as a second name for the empty?
message.
Exercise 2.9.3
Modify the stack
object to allow the two messages ref
and set!
. (stack 'ref i)
should return the i
th element from the top of the stack; (stack 'ref 0)
should be equivalent to (stack 'top)
. (stack 'set! i v)
should change the i
th element from the top of the stack to v
.
(define stack (makestack))
(stack 'push! 'a)
(stack 'push! 'b)
(stack 'push! 'c)
(stack 'ref 0) ⇒ c
(stack 'ref 2) ⇒ a
(stack 'set! 1 'd)
(stack 'ref 1) ⇒ d
(stack 'top) ⇒ c
(stack 'pop!)
(stack 'top) ⇒ d
[Hint: Use listref
to implement ref
and listtail
with setcar!
to implement set!
.]
Exercise 2.9.4
Scheme supports vectors as well as lists. Like lists, vectors are aggregate objects that contain other objects. Unlike lists, vectors have a fixed size and are laid out in one flat block of memory, typically with a header containing the length of the vector, as in the tenelement vector below.
This makes vectors more suitable for applications needing fast access to any element of the aggregate but less suitable for applications needing data structures that grow and shrink as needed.
Look up the basic vector operations in Section 6.9 and reimplement the stack
object to use a vector instead of a list to hold the stack contents. Include the ref
and set!
messages of Exercise 2.9.3. Have the new makestack
accept a size argument n and make the vector length n, but do not otherwise change the external (abstract) interface.
Exercise 2.9.5
Define a predicate, emptyq?
, for determining if a queue is empty. Modify getq
and delq!
to raise an exception when an empty queue is found, using assertionviolation
.
Exercise 2.9.6
In the queue implementation, the last pair in the encapsulated list is a placeholder, i.e., it never holds anything useful. Recode the queue operators to avoid this wasted pair. Make sure that the series of queue operations given earlier works with the new implementation. Which implementation do you prefer?
Exercise 2.9.7
Using setcdr!
, it is possible to create cyclic lists. For example, the following expression evaluates to a list whose car is the symbol a
and whose cdr is the list itself.
(let ([ls (cons 'a '())])
(setcdr! ls ls)
ls)
What happens when you enter the above expression during an interactive Scheme session? What will the implementation of length
on page 42 do when given a cyclic list? What does the builtin length
primitive do?
Exercise 2.9.8
Define the predicate list?
, which returns #t
if its argument is a proper list and #f
otherwise (see Section 6.3). It should return #f
for cyclic lists as well as for lists terminated by objects other than ()
.
(list? '()) ⇒ #t
(list? '(1 2 3)) ⇒ #t
(list? '(a . b)) ⇒ #f
(list? (let ([ls (cons 'a '())])
(setcdr! ls ls)
ls)) ⇒ #f
First write a simplified version of list?
that does not handle cyclic lists, then extend this to handle cyclic lists correctly. Revise your definition until you are satisfied that it is as clear and concise as possible. [Hint: Use the following "hare and tortoise" algorithm to detect cycles. Define a recursive help procedure of two arguments, the hare and the tortoise. Start both the hare and the tortoise at the beginning of the list. Have the hare advance by two cdrs each time the tortoise advances by one cdr. If the hare catches the tortoise, there must be a cycle.]
Chapter 3. Going Further
The preceding chapter prepared you to write Scheme programs using a small set of the most useful primitive syntactic forms and procedures. This chapter introduces a number of additional features and programming techniques that will allow you to write more sophisticated and efficient programs.
Section 3.1. Syntactic Extension
As we saw in Section 2.5, the let
syntactic form is merely a syntactic extension defined in terms of a lambda
expression and a procedure application, both core syntactic forms. At this point, you might be wondering which syntactic forms are core forms and which are syntactic extensions, and how new syntactic extensions may be defined. This section provides some answers to these questions.
In truth, it is not necessary for us to draw a distinction between core forms and syntactic extensions, since once defined, a syntactic extension has exactly the same status as a core form. Drawing a distinction, however, makes understanding the language easier, since it allows us to focus attention on the core forms and to understand all others in terms of them.
It is necessary for a Scheme implementation to distinguish between core forms and syntactic extensions. A Scheme implementation expands syntactic extensions into core forms as the first step of compilation or interpretation, allowing the rest of the compiler or interpreter to focus only on the core forms. The set of core forms remaining after expansion to be handled directly by the compiler or interpreter is implementationdependent, however, and may be different from the set of forms described as core here.
The exact set of syntactic forms making up the core of the language is thus subject to debate, although it must be possible to derive all other forms from any set of forms declared to be core forms. The set described here is among the simplest for which this constraint is satisfied.
The core syntactic forms include toplevel define
forms, constants, variables, procedure applications, quote
expressions, lambda
expressions, if
expressions, and set!
expressions. The grammar below describes the core syntax of Scheme in terms of these definitions and expressions. In the grammar, vertical bars (  ) separate alternatives, and a form followed by an asterisk ( * ) represents zero or more occurrences of the form. <variable> is any Scheme identifier. <datum> is any Scheme object, such as a number, list, symbol, or vector. <boolean> is either #t
or #f
, <number> is any number, <character> is any character, and <string> is any string. We have already seen examples of numbers, strings, lists, symbols, and booleans. See Chapter 6 or the formal syntax description starting on page 455 for more on the objectlevel syntax of these and other objects.
<program> 
→ 
<form>* 
<form> 
→ 
<definition>  <expression> 
<definition> 
→ 
<variable definition>  
<variable definition> 
→ 

<expression> 
→ 
<constant> 
 
<variable> 

 


 


 


 


 
<application> 

<constant> 
→ 
<boolean>  <number>  <character>  <string> 
<formals> 
→ 
<variable> 
 


 


<application> 
→ 

The grammar is ambiguous in that the syntax for procedure applications conflicts with the syntaxes for quote
, lambda
, if
, and set!
expressions. In order to qualify as a procedure application, the first <expression> must not be one of these keywords, unless the keyword has been redefined or locally bound.
The "defun" syntax for define
given in Section 2.6 is not included in the core, since definitions in that form are straightforwardly translated into the simpler define
syntax. Similarly, the core syntax for if
does not permit the alternative
to be omitted, as did one example in Section 2.9. An if
expression lacking an alternative
can be translated into the core syntax for if
merely by replacing the missing subexpression with an arbitrary constant, such as #f
.
A begin
that contains only definitions is considered to be a definition in the grammar; this is permitted in order to allow syntactic extensions to expand into more than one definition. begin
expressions, i.e., begin
forms containing expressions, are not considered core forms. A begin
expression of the form
(begin e_{1} e_{2} ...)
is equivalent to the lambda
application
((lambda () e_{1} e_{2} ...))
and hence need not be considered core.
Now that we have established a set of core syntactic forms, let’s turn to a discussion of syntactic extensions. Syntactic extensions are so called because they extend the syntax of Scheme beyond the core syntax. All syntactic extensions in a Scheme program must ultimately be derived from the core forms. One syntactic extension, however, may be defined in terms of another syntactic extension, as long as the latter is in some sense "closer" to the core syntax. Syntactic forms may appear anywhere an expression or definition is expected, as long as the extended form expands into a definition or expression as appropriate.
Syntactic extensions are defined with definesyntax
. definesyntax
is similar to define
, except that definesyntax
associates a syntactic transformation procedure, or transformer, with a keyword (such as let
), rather than associating a value with a variable. Here is how we might define let
with definesyntax
.
(definesyntax let
(syntaxrules ()
[(_ ((x e) ...) b1 b2 ...)
((lambda (x ...) b1 b2 ...) e ...)]))
The identifier appearing after definesyntax
is the name, or keyword, of the syntactic extension being defined, in this case let
. The syntaxrules
form is an expression that evaluates to a transformer. The item following syntaxrules
is a list of auxiliary keywords and is nearly always ()
. An example of an auxiliary keyword is the else
of cond
. (Other examples requiring the use of auxiliary keywords are given in Chapter 8.) Following the list of auxiliary keywords is a sequence of one or more rules, or pattern/template pairs. Only one rule appears in our definition of let
. The pattern part of a rule specifies the form that the input must take, and the template specifies to what the input should be transformed.
The pattern should always be a structured expression whose first element is an underscore ( _
). (As we will see in Chapter 8, the use of _
is only a convention, but it is a good one to follow.) If more than one rule is present, the appropriate one is chosen by matching the patterns, in order, against the input during expansion. It is a syntax violation if none of the patterns match the input.
Identifiers other than an underscore or ellipsis appearing within a pattern are pattern variables, unless they are listed as auxiliary keywords. Pattern variables match any substructure and are bound to that substructure within the corresponding template. The notation pat ...
in the pattern allows for zero or more expressions matching the ellipsis prototype pat
in the input. Similarly, the notation expr ...
in the template produces zero or more expressions from the ellipsis prototype expr
in the output. The number of pat
s in the input determines the number of expr
s in the output; in order for this to work, any ellipsis prototype in the template must contain at least one pattern variable from an ellipsis prototype in the pattern.
The single rule in our definition of let
should be fairly selfexplanatory, but a few points are worth mentioning. First, the syntax of let
requires that the body contain at least one form; hence, we have specified b1 b2 ...
instead of b ...
, which might seem more natural. On the other hand, let
does not require that there be at least one variable/value pair, so we were able to use, simply, (x e) ...
. Second, the pattern variables x
and e
, though together within the same prototype in the pattern, are separated in the template; any sort of rearrangement or recombination is possible. Finally, the three pattern variables x
, e
, and b2
that appear in ellipsis prototypes in the pattern also appear in ellipsis prototypes in the template. This is not a coincidence; it is a requirement. In general, if a pattern variable appears within an ellipsis prototype in the pattern, it cannot appear outside an ellipsis prototype in the template.
The definition of and
below is somewhat more complex than the one for let
.
(definesyntax and
(syntaxrules ()
[(_) #t]
[(_ e) e]
[(_ e1 e2 e3 ...)
(if e1 (and e2 e3 ...) #f)]))
This definition is recursive and involves more than one rule. Recall that (and)
evaluates to #t
; the first rule takes care of this case. The second and third rules specify the base case and recursion steps of the recursion and together translate and
expressions with two or more subexpressions into nested if
expressions. For example, (and a b c)
expands first into
(if a (and b c) #f)
then
(if a (if b (and c) #f) #f)
and finally
(if a (if b c #f) #f)
With this expansion, if a
and b
evaluate to a true value, then the value is the value of c
, otherwise #f
, as desired.
The version of and
below is simpler but, unfortunately, incorrect.
(definesyntax and ; incorrect!
(syntaxrules ()
[(_) #t]
[(_ e1 e2 ...)
(if e1 (and e2 ...) #f)]))
The expression
(and (not (= x 0)) (/ 1 x))
should return the value of (/ 1 x)
when x
is not zero. With the incorrect version of and
, the expression expands as follows.
(if (not (= x 0)) (and (/ 1 x)) #f) →
(if (not (= x 0)) (if (/ 1 x) (and) #f) #f) →
(if (not (= x 0)) (if (/ 1 x) #t #f) #f)
The final answer if x
is not zero is #t
, not the value of (/ 1 x)
.
The definition of or
below is similar to the one for and
except that a temporary variable must be introduced for each intermediate value so that we can both test the value and return it if it is a true value. (A temporary variable is not needed for and
since there is only one false value, #f
.)
(definesyntax or
(syntaxrules ()
[(_) #f]
[(_ e) e]
[(_ e1 e2 e3 ...)
(let ([t e1])
(if t t (or e2 e3 ...)))]))
Like variables bound by lambda
or let
, identifiers introduced by a template are lexically scoped, i.e., visible only within expressions introduced by the template. Thus, even if one of the expressions e2 e3 ...
contains a reference to t
, the introduced binding for t
does not "capture" those references. This is typically accomplished via automatic renaming of introduced identifiers.
As with the simpler version of and
given above, the simpler version of or
below is incorrect.
(definesyntax or ; incorrect!
(syntaxrules ()
[(_) #f]
[(_ e1 e2 ...)
(let ([t e1])
(if t t (or e2 ...)))]))
The reason is more subtle, however, and is the subject of Exercise 3.2.6.
Exercise 3.1.1
Write out the expansion steps necessary to expand
(let ([x (memv 'a ls)])
(and x (memv 'b x)))
into core forms.
Exercise 3.1.2
Write out the expansion steps necessary to expand
(or (memv x '(a b c)) (list x))
into core forms.
Exercise 3.1.3
let*
is similar to let
but evaluates its bindings in sequence. Each of the righthandside expressions is within the scope of the earlier bindings.
(let* ([a 5] [b (+ a a)] [c (+ a b)])
(list a b c)) ⇒ (5 10 15)
let*
can be implemented as nested let
expressions. For example, the let*
expression above is equivalent to the nested let
expressions below.
(let ([a 5])
(let ([b (+ a a)])
(let ([c (+ a b)])
(list a b c)))) ⇒ (5 10 15)
Define let*
with definesyntax
.
Exercise 3.1.4
As we saw in Section 2.9, it is legal to omit the third, or alternative, subexpression of an if
expression. Doing so, however, often leads to confusion. Scheme provides two syntactic forms, when
and unless
, that may be used in place of such "onearmed" if
expressions.
(when test expr_{1} expr_{2} ...)
(unless test expr_{1} expr_{2} ...)
With both forms, test
is evaluated first. For when
, if test
evaluates to true, the remaining forms are evaluated in sequence as if enclosed in an implicit begin
expression. If test
evaluates to false, the remaining forms are not evaluated, and the result is unspecified. unless
is similar except that the remaining forms are evaluated only if test
evaluates to false.
(let ([x 3])
(unless (= x 0) (set! x (+ x 1)))
(when (= x 4) (set! x (* x 2)))
x) ⇒ 8
Define when
as a syntactic extension in terms of if
and begin
, and define unless
in terms of when
.
Section 3.2. More Recursion
In Section 2.8, we saw how to define recursive procedures using toplevel definitions. Before that, we saw how to create local bindings for procedures using let
. It is natural to wonder whether a let
bound procedure can be recursive. The answer is no, at least not in a straightforward way. If you try to evaluate the expression
(let ([sum (lambda (ls)
(if (null? ls)
0
(+ (car ls) (sum (cdr ls)))))])
(sum '(1 2 3 4 5)))
it will probably raise an exception with a message to the effect that sum
is undefined. This is because the variable sum
is visible only within the body of the let
expression and not within the lambda
expression whose value is bound to sum
. We can get around this problem by passing the procedure sum
to itself as follows.
(let ([sum (lambda (sum ls)
(if (null? ls)
0
(+ (car ls) (sum sum (cdr ls)))))])
(sum sum '(1 2 3 4 5))) ⇒ 15
This works and is a clever solution, but there is an easier way, using letrec
. Like let
, the letrec
syntactic form includes a set of variablevalue pairs, along with a sequence of expressions referred to as the body of the letrec
.
(letrec ((var expr) ...) body_{1} body_{2} ...)
Unlike let
, the variables var ...
are visible not only within the body of the letrec
but also within expr ...
. Thus, we can rewrite the expression above as follows.
(letrec ([sum (lambda (ls)
(if (null? ls)
0
(+ (car ls) (sum (cdr ls)))))])
(sum '(1 2 3 4 5))) ⇒ 15
Using letrec
, we can also define mutually recursive procedures, such as the procedures even?
and odd?
that were the subject of Exercise 2.8.6.
(letrec ([even?
(lambda (x)
(or (= x 0)
(odd? ( x 1))))]
[odd?
(lambda (x)
(and (not (= x 0))
(even? ( x 1))))])
(list (even? 20) (odd? 20))) ⇒ (#t #f)
In a letrec
expression, expr ...
are most often lambda
expressions, though this need not be the case. One restriction on the expressions must be obeyed, however. It must be possible to evaluate each expr
without evaluating any of the variables var ...
. This restriction is always satisfied if the expressions are all lambda
expressions, since even though the variables may appear within the lambda
expressions, they cannot be evaluated until the resulting procedures are invoked in the body of the letrec
. The following letrec
expression obeys this restriction.
(letrec ([f (lambda () (+ x 2))]
[x 1])
(f)) ⇒ 3
while the following does not.
(letrec ([y (+ x 2)]
[x 1])
y)
In this case, an exception is raised indicating that x
is not defined where it is referenced.
We can use letrec
to hide the definitions of "help" procedures so that they do not clutter the toplevel namespace. This is demonstrated by the definition of list?
below, which follows the "hare and tortoise" algorithm outlined in Exercise 2.9.8.
(define list?
(lambda (x)
(letrec ([race
(lambda (h t)
(if (pair? h)
(let ([h (cdr h)])
(if (pair? h)
(and (not (eq? h t))
(race (cdr h) (cdr t)))
(null? h)))
(null? h)))])
(race x x))))
When a recursive procedure is called in only one place outside the procedure, as in the example above, it is often clearer to use a named let
expression. Named let
expressions take the following form.
(let name ((var expr) ...)
body_{1} body_{2} ...)
Named let
is similar to unnamed let
in that it binds the variables var ...
to the values of expr ...
within the body body_{1} body_{2} ...
. As with unnamed let
, the variables are visible only within the body and not within expr ...
. In addition, the variable name
is bound within the body to a procedure that may be called to recur; the arguments to the procedure become the new values for the variables var ...
.
The definition of list?
has been rewritten below to use named let
.
(define list?
(lambda (x)
(let race ([h x] [t x])
(if (pair? h)
(let ([h (cdr h)])
(if (pair? h)
(and (not (eq? h t))
(race (cdr h) (cdr t)))
(null? h)))
(null? h)))))
Just as let
can be expressed as a simple direct application of a lambda
expression to arguments, named let
can be expressed as the application of a recursive procedure to arguments. A named let
of the form
(let name ((var expr) ...)
body_{1} body_{2} ...)
can be rewritten in terms of letrec
as follows.
((letrec ((name (lambda (var ...) body_{1} body_{2} ...)))
name)
expr ...)
Alternatively, it can be rewritten as
(letrec ((name (lambda (var ...) body_{1} body_{2} ...)))
(name expr ...))
provided that the variable name
does not appear free within expr ...
.
As we discussed in Section 2.8, some recursion is essentially iteration and executes as such. When a procedure call is in tail position (see below) with respect to a lambda
expression, it is considered to be a tail call, and Scheme systems must treat it properly, as a "goto" or jump. When a procedure tailcalls itself or calls itself indirectly through a series of tail calls, the result is tail recursion. Because tail calls are treated as jumps, tail recursion can be used for indefinite iteration in place of the more restrictive iteration constructs provided by other programming languages, without fear of overflowing any sort of recursion stack.
A call is in tail position with respect to a lambda
expression if its value is returned directly from the lambda
expression, i.e., if nothing is left to do after the call but to return from the lambda
expression. For example, a call is in tail position if it is the last expression in the body of a lambda
expression, the consequent or alternative part of an if
expression in tail position, the last subexpression of an and
or or
expression in tail position, the last expression in the body of a let
or letrec
in tail position, etc. Each of the calls to f
in the expressions below are tail calls, but the calls to g
are not.
(lambda () (f (g)))
(lambda () (if (g) (f) (f)))
(lambda () (let ([x 4]) (f)))
(lambda () (or (g) (f)))
In each case, the values of the calls to f
are returned directly, whereas the calls to g
are not.
Recursion in general and named let
in particular provide a natural way to implement many algorithms, whether iterative, recursive, or partly iterative and partly recursive; the programmer is not burdened with two distinct mechanisms.
The following two definitions of factorial
use named let
expressions to compute the factorial, \(n!\), of a nonnegative integer \(n\). The first employs the recursive definition \(n! = n × (n  1)!\), where \(0!\) is defined to be 1.
(define factorial
(lambda (n)
(let fact ([i n])
(if (= i 0)
1
(* i (fact ( i 1)))))))
(factorial 0) ⇒ 1
(factorial 1) ⇒ 1
(factorial 2) ⇒ 2
(factorial 3) ⇒ 6
(factorial 10) ⇒ 3628800
The second is an iterative version that employs the iterative definition \(n! = n × (n  1) × (n  2) × ... × 1\), using an accumulator, a
, to hold the intermediate products.
(define factorial
(lambda (n)
(let fact ([i n] [a 1])
(if (= i 0)
a
(fact ( i 1) (* a i))))))
A similar problem is to compute the nth Fibonacci number for a given n. The Fibonacci numbers are an infinite sequence of integers, 0, 1, 1, 2, 3, 5, 8, etc., in which each number is the sum of the two preceding numbers in the sequence. A procedure to compute the nth Fibonacci number is most naturally defined recursively as follows.
(define fibonacci
(lambda (n)
(let fib ([i n])
(cond
[(= i 0) 0]
[(= i 1) 1]
[else (+ (fib ( i 1)) (fib ( i 2)))]))))
(fibonacci 0) ⇒ 0
(fibonacci 1) ⇒ 1
(fibonacci 2) ⇒ 1
(fibonacci 3) ⇒ 2
(fibonacci 4) ⇒ 3
(fibonacci 5) ⇒ 5
(fibonacci 6) ⇒ 8
(fibonacci 20) ⇒ 6765
(fibonacci 30) ⇒ 832040
This solution requires the computation of the two preceding Fibonacci numbers at each step and hence is doubly recursive. For example, to compute (fibonacci 4)
requires the computation of both (fib 3)
and (fib 2)
, to compute (fib 3)
requires computing both (fib 2)
and (fib 1)
, and to compute (fib 2)
requires computing both (fib 1)
and (fib 0)
. This is very inefficient, and it becomes more inefficient as n
grows. A more efficient solution is to adapt the accumulator solution of the factorial
example above to use two accumulators, a1
for the current Fibonacci number and a2
for the preceding one.
(define fibonacci
(lambda (n)
(if (= n 0)
0
(let fib ([i n] [a1 1] [a2 0])
(if (= i 1)
a1
(fib ( i 1) (+ a1 a2) a1))))))
Here, zero is treated as a special case, since there is no preceding value. This allows us to use the single base case (= i 1)
. The time it takes to compute thennth Fibonacci number using this iterative solution grows linearly with n, which makes a significant difference when compared to the doubly recursive version. To get a feel for the difference, try computing (fibonacci 35)
and (fibonacci 40)
using both definitions to see how long each takes.
We can also get a feel for the difference by looking at a trace for each on small inputs. The first trace below shows the calls to fib
in the nontailrecursive version of fibonacci
, with input 5.
(fib 5)
 (fib 4)
 (fib 3)
  (fib 2)
  (fib 1)
  1
  (fib 0)
  0
  1
  (fib 1)
  1
 2
 (fib 2)
  (fib 1)
  1
  (fib 0)
  0
 1
 3
 (fib 3)
 (fib 2)
  (fib 1)
  1
  (fib 0)
  0
 1
 (fib 1)
 1
 2
5
Notice how there are several calls to fib
with arguments 2, 1, and 0. The second trace shows the calls to fib
in the tailrecursive version, again with input 5.
(fib 5 1 0)
(fib 4 1 1)
(fib 3 2 1)
(fib 2 3 2)
(fib 1 5 3)
5
Clearly, there is quite a difference.
The named let
examples shown so far are either tailrecursive or not tailrecursive. It often happens that one recursive call within the same expression is tailrecursive while another is not. The definition of factor
below computes the prime factors of its nonnegative integer argument. The first call to f
is not tailrecursive, but the second one is.
(define factor
(lambda (n)
(let f ([n n] [i 2])
(cond
[(>= i n) (list n)]
[(integer? (/ n i))
(cons i (f (/ n i) i))]
[else (f n (+ i 1))]))))
(factor 0) ⇒ (0)
(factor 1) ⇒ (1)
(factor 12) ⇒ (2 2 3)
(factor 3628800) ⇒ (2 2 2 2 2 2 2 2 3 3 3 3 5 5 7)
(factor 9239) ⇒ (9239)
A trace of the calls to f
, produced in Chez Scheme by replacing let
with tracelet
, in the evaluation of (factor 120)
below highlights the difference between the nontail calls and the tail calls.
(f 120 2)
 (f 60 2)
 (f 30 2)
  (f 15 2)
  (f 15 3)
  (f 5 3)
  (f 5 4)
  (f 5 5)
  (5)
  (3 5)
 (2 3 5)
 (2 2 3 5)
(2 2 2 3 5)
A nontail call to f
is shown indented relative to its caller, since the caller is still active, whereas tail calls appear at the same level of indentation.
Exercise 3.2.1
Which of the recursive procedures defined in Section 3.2 are tailrecursive, and which are not?
Exercise 3.2.2
Rewrite factor
using letrec
to bind f
in place of named let
. Which version do you prefer?
Exercise 3.2.3
Can the letrec
expression below be rewritten using named let
? If not, why not? If so, do it.
(letrec ([even?
(lambda (x)
(or (= x 0)
(odd? ( x 1))))]
[odd?
(lambda (x)
(and (not (= x 0))
(even? ( x 1))))])
(even? 20))
Exercise 3.2.4
Rewrite both definitions of fibonacci
given in this section to count the number of recursive calls to fib
, using a counter similar to the one used in the conscount
example of Section 2.9. Count the number of recursive calls made in each case for several input values. What do you notice?
Exercise 3.2.5
Augment the definition of let
given in Section 3.1 to handle named let
as well as unnamed let
, using two rules.
Exercise 3.2.6
The following definition of or
is simpler than the one given in Section 3.1.
(definesyntax or ; incorrect!
(syntaxrules ()
[(_) #f]
[(_ e1 e2 ...)
(let ([t e1])
(if t t (or e2 ...)))]))
Say why it is not correct. [Hint: Think about what would happen if this version of or
were used in the even?
and odd?
example given on page 66 for very large inputs.]
Exercise 3.2.7
The definition of factor
is not the most efficient possible. First, no factors of n besides n itself can possibly be found beyond \(\sqrt{n}\). Second, the division (/ n i)
is performed twice when a factor is found. Third, after 2, no even factors can possibly be found. Recode factor
to correct all three problems. Which is the most important problem to solve? Are there any additional improvements you can make?
Section 3.3. Continuations
During the evaluation of a Scheme expression, the implementation must keep track of two things: (1) what to evaluate and (2) what to do with the value. Consider the evaluation of (null? x)
within the expression below.
(if (null? x) (quote ()) (cdr x))
The implementation must first evaluate (null? x)
and, based on its value, evaluate either (quote ())
or (cdr x)
. "What to evaluate" is (null? x)
, and "what to do with the value" is to make the decision which of (quote ())
and (cdr x)
to evaluate and to do so. We call "what to do with the value" the continuation of a computation.
Thus, at any point during the evaluation of any expression, there is a continuation ready to complete, or at least continue, the computation from that point. Let’s assume that x
has the value (a b c)
. We can isolate six continuations during the evaluation of (if (null? x) (quote ()) (cdr x))
, the continuations waiting for

the value of
(if (null? x) (quote ()) (cdr x))
, 
the value of
(null? x)
, 
the value of
null?
, 
the value of
x
, 
the value of
cdr
, and 
the value of
x
(again).
The continuation of (cdr x)
is not listed because it is the same as the one waiting for (if (null? x) (quote ()) (cdr x))
.
Scheme allows the continuation of any expression to be captured with the procedure call/cc
. call/cc
must be passed a procedure p
of one argument. call/cc
constructs a concrete representation of the current continuation and passes it to p
. The continuation itself is represented by a procedure k
. Each time k
is applied to a value, it returns the value to the continuation of the call/cc
application. This value becomes, in essence, the value of the application of call/cc
.
If p
returns without invoking k
, the value returned by the procedure becomes the value of the application of call/cc
.
Consider the simple examples below.
(call/cc
(lambda (k)
(* 5 4))) ⇒ 20
(call/cc
(lambda (k)
(* 5 (k 4)))) ⇒ 4
(+ 2
(call/cc
(lambda (k)
(* 5 (k 4))))) ⇒ 6
In the first example, the continuation is captured and bound to k
, but k
is never used, so the value is simply the product of 5 and 4. In the second, the continuation is invoked before the multiplication, so the value is the value passed to the continuation, 4. In the third, the continuation includes the addition by 2; thus, the value is the value passed to the continuation, 4, plus 2.
Here is a less trivial example, showing the use of call/cc
to provide a nonlocal exit from a recursion.
(define product
(lambda (ls)
(call/cc
(lambda (break)
(let f ([ls ls])
(cond
[(null? ls) 1]
[(= (car ls) 0) (break 0)]
[else (* (car ls) (f (cdr ls)))]))))))
(product '(1 2 3 4 5)) ⇒ 120
(product '(7 3 8 0 1 9 5)) ⇒ 0
The nonlocal exit allows product
to return immediately, without performing the pending multiplications, when a zero value is detected.
Each of the continuation invocations above returns to the continuation while control remains within the procedure passed to call/cc
. The following example uses the continuation after this procedure has already returned.
(let ([x (call/cc (lambda (k) k))])
(x (lambda (ignore) "hi"))) ⇒ "hi"
The continuation captured by this invocation of call/cc
may be described as "Take the value, bind it to x
, and apply the value of x
to the value of (lambda (ignore) "hi")
." Since (lambda (k) k)
returns its argument, x
is bound to the continuation itself; this continuation is applied to the procedure resulting from the evaluation of (lambda (ignore) "hi")
. This has the effect of binding x
(again!) to this procedure and applying the procedure to itself. The procedure ignores its argument and returns "hi"
.
The following variation of the example above is probably the most confusing Scheme program of its size; it might be easy to guess what it returns, but it takes some thought to figure out why.
(((call/cc (lambda (k) k)) (lambda (x) x)) "HEY!") ⇒ "HEY!"
The value of the call/cc
is its own continuation, as in the preceding example. This is applied to the identity procedure (lambda (x) x)
, so the call/cc
returns a second time with this value. Then, the identity procedure is applied to itself, yielding the identity procedure. This is finally applied to "HEY!"
, yielding "HEY!"
.
Continuations used in this manner are not always so puzzling. Consider the following definition of factorial
that saves the continuation at the base of the recursion before returning 1, by assigning the toplevel variable retry
.
(define retry #f)
(define factorial
(lambda (x)
(if (= x 0)
(call/cc (lambda (k) (set! retry k) 1))
(* x (factorial ( x 1))))))
With this definition, factorial
works as we expect factorial
to work, except it has the side effect of assigning retry
.
(factorial 4) ⇒ 24
(retry 1) ⇒ 24
(retry 2) ⇒ 48
The continuation bound to retry
might be described as "Multiply the value by 1, then multiply this result by 2, then multiply this result by 3, then multiply this result by 4." If we pass the continuation a different value, i.e., not 1, we will cause the base value to be something other than 1 and hence change the end result.
(retry 2) ⇒ 48
(retry 5) ⇒ 120
This mechanism could be the basis for a breakpoint package implemented with call/cc
; each time a breakpoint is encountered, the continuation of the breakpoint is saved so that the computation may be restarted from the breakpoint (more than once, if desired).
Continuations may be used to implement various forms of multitasking. The simple "lightweight process" mechanism defined below allows multiple computations to be interleaved. Since it is nonpreemptive, it requires that each process voluntarily "pause" from time to time in order to allow the others to run.
(define lwplist '())
(define lwp
(lambda (thunk)
(set! lwplist (append lwplist (list thunk)))))
(define start
(lambda ()
(let ([p (car lwplist)])
(set! lwplist (cdr lwplist))
(p))))
(define pause
(lambda ()
(call/cc
(lambda (k)
(lwp (lambda () (k #f)))
(start)))))
The following lightweight processes cooperate to print an infinite sequence of lines containing "hey!"
.
(lwp (lambda () (let f () (pause) (display "h") (f))))
(lwp (lambda () (let f () (pause) (display "e") (f))))
(lwp (lambda () (let f () (pause) (display "y") (f))))
(lwp (lambda () (let f () (pause) (display "!") (f))))
(lwp (lambda () (let f () (pause) (newline) (f))))
(start) ⇒ hey!
hey!
hey!
hey!
…
See Section 12.11 for an implementation of engines, which support preemptive multitasking, with call/cc
.
Exercise 3.3.1
Use call/cc
to write a program that loops indefinitely, printing a sequence of numbers beginning at zero. Do not use any recursive procedures, and do not use any assignments.
Exercise 3.3.2
Rewrite product
without call/cc
, retaining the feature that no multiplications are performed if any of the list elements are zero.
Exercise 3.3.3
What would happen if a process created by lwp
as defined above were to terminate, i.e., simply return without calling pause
? Define a quit
procedure that allows a process to terminate without otherwise affecting the lwp
system. Be sure to handle the case in which the only remaining process terminates.
Exercise 3.3.4
Each time lwp
is called, the list of processes is copied because lwp
uses append
to add its argument to the end of the process list. Modify the original lwp
code to use the queue data type developed in Section 2.9 to avoid this problem.
Exercise 3.3.5
The lightweight process mechanism allows new processes to be created dynamically, although the example given in this section does not do so. Design an application that requires new processes to be created dynamically and implement it using the lightweight process mechanism.
Section 3.4. Continuation Passing Style
As we discussed in the preceding section, a continuation waits for the value of each expression. In particular, a continuation is associated with each procedure call. When one procedure invokes another via a nontail call, the called procedure receives an implicit continuation that is responsible for completing what is left of the calling procedure’s body plus returning to the calling procedure’s continuation. If the call is a tail call, the called procedure simply receives the continuation of the calling procedure.
We can make the continuations explicit by encapsulating "what to do" in an explicit procedural argument passed along on each call. For example, the continuation of the call to f
in
(letrec ([f (lambda (x) (cons 'a x))]
[g (lambda (x) (cons 'b (f x)))]
[h (lambda (x) (g (cons 'c x)))])
(cons 'd (h '()))) ⇒ (d b a c)
conses the symbol b
onto the value returned to it, then returns the result of this cons to the continuation of the call to g
. This continuation is the same as the continuation of the call to h
, which conses the symbol d
onto the value returned to it. We can rewrite this in continuationpassing style, or CPS, by replacing these implicit continuations with explicit procedures.
(letrec ([f (lambda (x k) (k (cons 'a x)))]
[g (lambda (x k)
(f x (lambda (v) (k (cons 'b v)))))]
[h (lambda (x k) (g (cons 'c x) k))])
(h '() (lambda (v) (cons 'd v))))
Like the implicit continuation of h
and g
in the preceding example, the explicit continuation passed to h
and on to g
,
(lambda (v) (cons 'd v))
conses the symbol d
onto the value passed to it. Similarly, the continuation passed to f
,
(lambda (v) (k (cons 'b v)))
conses b
onto the value passed to it, then passes this on to the continuation of g
.
Expressions written in CPS are more complicated, of course, but this style of programming has some useful applications. CPS allows a procedure to pass more than one result to its continuation, because the procedure that implements the continuation can take any number of arguments.
(define car&cdr
(lambda (p k)
(k (car p) (cdr p))))
(car&cdr '(a b c)
(lambda (x y)
(list y x))) ⇒ ((b c) a)
(car&cdr '(a b c) cons) ⇒ (a b c)
(car&cdr '(a b c a d) memv) ⇒ (a d)
(This can be done with multiple values as well; see Section 5.8.) CPS also allows a procedure to take separate "success" and "failure" continuations, which may accept different numbers of arguments. An example is integerdivide
below, which passes the quotient and remainder of its first two arguments to its third, unless the second argument (the divisor) is zero, in which case it passes an error message to its fourth argument.
(define integerdivide
(lambda (x y success failure)
(if (= y 0)
(failure "divide by zero")
(let ([q (quotient x y)])
(success q ( x (* q y)))))))
(integerdivide 10 3 list (lambda (x) x)) ⇒ (3 1)
(integerdivide 10 0 list (lambda (x) x)) ⇒ "divide by zero"
The procedure quotient
, employed by integerdivide
, returns the quotient of its two arguments, truncated toward zero.
Explicit success and failure continuations can sometimes help to avoid the extra communication necessary to separate successful execution of a procedure from unsuccessful execution. Furthermore, it is possible to have multiple success or failure continuations for different flavors of success or failure, each possibly taking different numbers and types of arguments. See Sections 12.10 and 12.11 for extended examples that employ continuationpassing style.
At this point you might be wondering about the relationship between CPS and the continuations captured via call/cc
. It turns out that any program that uses call/cc
can be rewritten in CPS without call/cc
, but a total rewrite of the program (sometimes including even systemdefined primitives) might be necessary. Try to convert the product
example on page 75 into CPS before looking at the version below.
(define product
(lambda (ls k)
(let ([break k])
(let f ([ls ls] [k k])
(cond
[(null? ls) (k 1)]
[(= (car ls) 0) (break 0)]
[else (f (cdr ls)
(lambda (x)
(k (* (car ls) x))))])))))
(product '(1 2 3 4 5) (lambda (x) x)) ⇒ 120
(product '(7 3 8 0 1 9 5) (lambda (x) x)) ⇒ 0
Exercise 3.4.1
Rewrite the reciprocal
example first given in Section 2.1 to accept both success and failure continuations, like integerdivide
above.
Exercise 3.4.2
Rewrite the retry
example from page 75 to use CPS.
Exercise 3.4.3
Rewrite the following expression in CPS to avoid using call/cc
.
(define reciprocals
(lambda (ls)
(call/cc
(lambda (k)
(map (lambda (x)
(if (= x 0)
(k "zero found")
(/ 1 x)))
ls)))))
(reciprocals '(2 1/3 5 1/4)) ⇒ (1/2 3 1/5 4)
(reciprocals '(2 1/3 0 5 1/4)) ⇒ "zero found"
[Hint: A singlelist version of map
is defined on page 46.]
Section 3.5. Internal Definitions
In Section 2.6, we discussed toplevel definitions. Definitions may also appear at the front of a lambda
, let
, or letrec
body, in which case the bindings they create are local to the body.
(define f (lambda (x) (* x x)))
(let ([x 3])
(define f (lambda (y) (+ y x)))
(f 4)) ⇒ 7
(f 4) ⇒ 16
Procedures bound by internal definitions can be mutually recursive, as with letrec
. For example, we can rewrite the even?
and odd?
example from Section 3.2 using internal definitions as follows.
(let ()
(define even?
(lambda (x)
(or (= x 0)
(odd? ( x 1)))))
(define odd?
(lambda (x)
(and (not (= x 0))
(even? ( x 1)))))
(even? 20)) ⇒ #t
Similarly, we can replace the use of letrec
to bind race
with an internal definition of race
in our first definition of list?
.
(define list?
(lambda (x)
(define race
(lambda (h t)
(if (pair? h)
(let ([h (cdr h)])
(if (pair? h)
(and (not (eq? h t))
(race (cdr h) (cdr t)))
(null? h)))
(null? h))))
(race x x)))
In fact, internal variable definitions and letrec
are practically interchangeable. The only difference, other than the obvious difference in syntax, is that variable definitions are guaranteed to be evaluated from left to right, while the bindings of a letrec may be evaluated in any order. So we cannot quite replace a lambda
, let
, or letrec
body containing internal definitions with a letrec
expression. We can, however, use letrec*
, which, like let*
, guarantees lefttoright evaluation order. A body of the form
(define var expr_{0})
…
expr_{1}
expr_{2}
…
is equivalent to a letrec*
expression binding the defined variables to the associated values in a body comprising the expressions.
(letrec* ((var expr_{0}) ...) expr_{1} expr_{2} ...)
Conversely, a letrec*
of the form
(letrec* ((var expr_{0}) ...) expr_{1} expr_{2} ...)
can be replaced with a let
expression containing internal definitions and the expressions from the body as follows.
(let ()
(define var expr_{0})
…
expr_{1}
expr_{2}
…
)
The seeming lack of symmetry between these transformations is due to the fact that letrec*
expressions can appear anywhere an expression is valid, whereas internal definitions can appear only at the front of a body. Thus, in replacing a letrec*
with internal definitions, we must generally introduce a let
expression to hold the definitions.
Another difference between internal definitions and letrec
or letrec*
is that syntax definitions may appear among the internal definitions, while letrec
and letrec*
bind only variables.
(let ([x 3])
(definesyntax setx!
(syntaxrules ()
[(_ e) (set! x e)]))
(setx! (+ x x))
x) ⇒ 6
The scope of a syntactic extension established by an internal syntax definition, as with an internal variable definition, is limited to the body in which the syntax definition appears.
Internal definitions may be used in conjunction with toplevel definitions and assignments to help modularize programs. Each module of a program should make visible only those bindings that are needed by other modules, while hiding other bindings that would otherwise clutter the toplevel namespace and possibly result in unintended use or redefinition of those bindings. A common way of structuring a module is shown below.
(define exportvar #f)
…
(let ()
(define var expr)
…
initexpr
…
(set! exportvar exportval)
…
)
The first set of definitions establish toplevel bindings for the variables we desire to export (make visible globally). The second set of definitions establish local bindings visible only within the module. The expressions initexpr ...
perform any initialization that must occur after the local bindings have been established. Finally, the set!
expressions assign the exported variables to the appropriate values.
An advantage of this form of modularization is that the bracketing let
expression may be removed or "commented out" during program development, making the internal definitions toplevel to facilitate interactive testing. This form of modularization also has several disadvantages, as we discuss in the next section.
The following module exports a single variable, calc
, which is bound to a procedure that implements a simple fourfunction calculator.
(define calc #f)
(let ()
(define docalc
(lambda (ek expr)
(cond
[(number? expr) expr]
[(and (list? expr) (= (length expr) 3))
(let ([op (car expr)] [args (cdr expr)])
(case op
[(add) (applyop ek + args)]
[(sub) (applyop ek  args)]
[(mul) (applyop ek * args)]
[(div) (applyop ek / args)]
[else (complain ek "invalid operator" op)]))]
[else (complain ek "invalid expression" expr)])))
(define applyop
(lambda (ek op args)
(op (docalc ek (car args)) (docalc ek (cadr args)))))
(define complain
(lambda (ek msg expr)
(ek (list msg expr))))
(set! calc
(lambda (expr)
; grab an error continuation ek
(call/cc
(lambda (ek)
(docalc ek expr))))))
(calc '(add (mul 3 2) 4)) ⇒ 2
(calc '(div 1/2 1/6)) ⇒ 3
(calc '(add (mul 3 2) (div 4))) ⇒ ("invalid expression" (div 4))
(calc '(mul (add 1 2) (pow 2 7))) ⇒ ("invalid operator" pow)
This example uses a case
expression to determine which operator to apply. case
is similar to cond
except that the test is always the same: (memv val (key ...))
, where val
is the value of the first case
subform and (key ...)
is the list of items at the front of each case
clause. The case
expression in the example above could be rewritten using cond
as follows.
(let ([temp op])
(cond
[(memv temp '(add)) (applyop ek + args)]
[(memv temp '(sub)) (applyop ek  args)]
[(memv temp '(mul)) (applyop ek * args)]
[(memv temp '(div)) (applyop ek / args)]
[else (complain ek "invalid operator" op)]))
Exercise 3.5.1
Redefine complain
in the calc
example as an equivalent syntactic extension.
Exercise 3.5.2
In the calc
example, the error continuation ek
is passed along on each call to applyop
, complain
, and docalc
. Move the definitions of applyop
, complain
, and docalc
inward as far as necessary to eliminate the ek
argument from the definitions and applications of these procedures.
Exercise 3.5.3
Eliminate the call/cc
from calc
and rewrite complain
to raise an exception using assertionviolation
.
Exercise 3.5.4
Extend calc
to handle unary minus expressions, e.g.,
(calc '(minus (add 2 3))) ⇒ 5
and other operators of your choice.
Section 3.6. Libraries
At the end of the preceding section, we discussed a form of modularization that involves assigning a set of toplevel variables from within a let
while keeping unpublished helpers local to the let
. This form of modularization has several drawbacks:

It is unportable, because the behavior and even existence of an interactive top level is not guaranteed by the Revised^{6} Report.

It requires assignments, which make the code appear somewhat awkward and may inhibit compiler analyses and optimizations.

It does not support the publication of keyword bindings, since there is no analogue to
set!
for keywords.
An alternative that does not share these drawbacks is to create a library. A library exports a set of identifiers, each defined within the library or imported from some other library. An exported identifier need not be bound as a variable; it may be bound as a keyword instead.
The following library exports two identifiers: the variable gpa>grade
and the keyword gpa
. The variable gpa>grade
is bound to a procedure that takes a gradepoint average (GPA), represented as a number, and returns the corresponding letter grade, based on a fourpoint scale. The keyword gpa
names a syntactic extension whose subforms must all be letter grades and whose value is the GPA computed from those letter grades.
(library (grades)
(export gpa>grade gpa)
(import (rnrs))
(define inrange?
(lambda (x n y)
(and (>= n x) (< n y))))
(definesyntax rangecase
(syntaxrules ( else)
[(_ expr ((x  y) e1 e2 ...) ... [else ee1 ee2 ...])
(let ([tmp expr])
(cond
[(inrange? x tmp y) e1 e2 ...]
...
[else ee1 ee2 ...]))]
[(_ expr ((x  y) e1 e2 ...) ...)
(let ([tmp expr])
(cond
[(inrange? x tmp y) e1 e2 ...]
...))]))
(define letter>number
(lambda (x)
(case x
[(a) 4.0]
[(b) 3.0]
[(c) 2.0]
[(d) 1.0]
[(f) 0.0]
[else (assertionviolation 'grade "invalid letter grade" x)])))
(define gpa>grade
(lambda (x)
(rangecase x
[(0.0  0.5) 'f]
[(0.5  1.5) 'd]
[(1.5  2.5) 'c]
[(2.5  3.5) 'b]
[else 'a])))
(definesyntax gpa
(syntaxrules ()
[(_ g1 g2 ...)
(let ([ls (map letter>number '(g1 g2 ...))])
(/ (apply + ls) (length ls)))])))
The name of the library is (grades)
. This may seem like a funny kind of name, but all library names are parenthesized. The library imports from the standard (rnrs)
library, which contains most of the primitive and keyword bindings we have used in this chapter and the last, and everything we need to implement gpa>grade
and gpa
.
Along with gpa>grade
and gpa
, several other syntactic extensions and procedures are defined within the library, but none of the others are exported. The ones that aren’t exported are simply helpers for the ones that are. Everything used within the library should be familiar, except for the apply
procedure, which is described on page 107.
If your Scheme implementation supports import
in the interactive top level, you can test the two exports as shown below.
(import (grades))
(gpa c a c b b) ⇒ 2.8
(gpa>grade 2.8) ⇒ b
Chapter 10 describes libraries in more detail and provides additional examples of their use.
Exercise 3.6.1
Modify gpa
to handle “x” grades, which do not count in the gradepoint average. Be careful to handle gracefully the situation where each grade is x
.
(import (grades))
(gpa a x b c) ⇒ 3.0
Exercise 3.6.2
Export from (grades)
a new syntactic form, distribution
, that takes a set of grades, like gpa
, but returns a list of the form ((n g) ...)
, where n
is the number of times g
appears in the set, with one entry for each g
. Have distribution
call an unexported procedure to do the actual work.
(import (grades))
(distribution a b a c c c a f b a) ⇒ ((4 a) (2 b) (3 c) (0 d) (1 f))
Exercise 3.6.3
Now read about output operations in Section 7.8 and define a new export, histogram
, as a procedure that takes a textual output port
and a distribution, such as might be produced by distribution
, and prints a histogram in the style illustrated by the example below.
(import (grades))
(histogram
(currentoutputport)
(distribution a b a c c a c a f b a))
prints:
a: *****
b: **
c: ***
d:
f: *
Chapter 4. Procedures and Variable Bindings
Procedures and variable bindings are the fundamental building blocks of Scheme programs. This chapter describes the small set of syntactic forms whose primary purpose is to create procedures and manipulate variable bindings. It begins with the two most fundamental building blocks of Scheme programs: variable references and lambda
expressions, and continues with descriptions of the variable binding and assignment forms such as define
, letrec
, letvalues
, and set!
.
Various other forms that bind or assign variables for which the binding or assignment is not the primary purpose (such as named let
) are found in Chapter 5.
Section 4.1. Variable References
syntax 

returns 
the value of 
Any identifier appearing as an expression in a program is a variable if a visible variable binding for the identifier exists, e.g., the identifier appears within the scope of a binding created by define
, lambda
, let
, or some other variablebinding construct.
list ⇒ #<procedure>
(define x 'a)
(list x x) ⇒ (a a)
(let ([x 'b])
(list x x)) ⇒ (b b)
(let ([let 'let]) let) ⇒ let
It is a syntax violation for an identifier reference to appear within a library
form or toplevel program if it is not bound as a variable, keyword, record name, or other entity. Since the scope of the definitions in a library
, toplevel program, lambda
, or other local body is the entire body, it is not necessary for the definition of a variable to appear before its first reference appears, as long as the reference is not actually evaluated until the definition has been completed. So, for example, the reference to g
within the definition of f
below
(define f
(lambda (x)
(g x)))
(define g
(lambda (x)
(+ x x)))
is okay, but the reference to g
in the definition of q
below is not.
(define q (g 3))
(define g
(lambda (x)
(+ x x)))
Section 4.2. Lambda
syntax 

returns 
a procedure 
libraries 

The lambda
syntactic form is used to create procedures. Any operation that creates a procedure or establishes local variable bindings is ultimately defined in terms of lambda
or caselambda
.
The variables in formals
are the formal parameters of the procedure, and the sequence of subforms body_{1} body_{2} ...
is its body.
The body may begin with a sequence of definitions, in which case the bindings created by the definitions are local to the body. If definitions are present, the keyword bindings are used and discarded while expanding the body, and the body is expanded into a letrec*
expression formed from the variable definitions and the remaining expressions, as described on page 292. The remainder of this description of lambda
assumes that this transformation has taken place, if necessary, so that the body is a sequence of expressions without definitions.
When the procedure is created, the bindings of all variables occurring free within the body, excluding the formal parameters, are retained with the procedure. Subsequently, whenever the procedure is applied to a sequence of actual parameters, the formal parameters are bound to the actual parameters, the retained bindings are restored, and the body is evaluated.
Upon application, the formal parameters defined by formals
are bound to the actual parameters as follows.

If
formals
is a proper list of variables, e.g.,(x y z)
, each variable is bound to the corresponding actual parameter. An exception with condition type&assertion
is raised if too few or too many actual parameters are supplied. 
If
formals
is a single variable (not in a list), e.g.,z
, it is bound to a list of the actual parameters. 
If
formals
is an improper list of variables terminated by a variable, e.g.,(x y . z)
, each variable but the last is bound to the corresponding actual parameter. The last variable is bound to a list of the remaining actual parameters. An exception with condition type&assertion
is raised if too few actual parameters are supplied.
When the body is evaluated, the expressions in the body are evaluated in sequence, and the procedure returns the values of the last expression.
Procedures do not have a printed representation in the usual sense. Scheme systems print procedures in different ways; this book uses the notation #<procedure>
.
(lambda (x) (+ x 3)) ⇒ #<procedure>
((lambda (x) (+ x 3)) 7) ⇒ 10
((lambda (x y) (* x (+ x y))) 7 13) ⇒ 140
((lambda (f x) (f x x)) + 11) ⇒ 22
((lambda () (+ 3 4))) ⇒ 7
((lambda (x . y) (list x y))
28 37) ⇒ (28 (37))
((lambda (x . y) (list x y))
28 37 47 28) ⇒ (28 (37 47 28))
((lambda (x y . z) (list x y z))
1 2 3 4) ⇒ (1 2 (3 4))
((lambda x x) 7 13) ⇒ (7 13)
Section 4.3. CaseLambda
A Scheme lambda
expression always produces a procedure with a fixed number of arguments or with an indefinite number of arguments greater than or equal to a certain number. In particular,
(lambda (var_{1} ... var_{n}) body_{1} body_{2} ...)
accepts exactly n
arguments,
(lambda r body_{1} body_{2} ...)
accepts zero or more arguments, and
(lambda (var_{1} ... var_{n} . r) body_{1} body_{2} ...)
accepts n
or more arguments.
lambda
cannot directly produce, however, a procedure that accepts, say, either two or three arguments. In particular, procedures that accept optional arguments are not supported directly by lambda
. The latter form of lambda
shown above can be used, in conjunction with length checks and compositions of car
and cdr
, to implement procedures with optional arguments, though at the cost of clarity and efficiency.
The caselambda
syntactic form directly supports procedures with optional arguments as well as procedures with fixed or indefinite numbers of arguments. caselambda
is based on the lambda*
syntactic form introduced in the article "A New Approach to Procedures with Variable Arity" [11].
syntax 

returns 
a procedure 
libraries 

A caselambda
expression consists of a set of clauses, each resembling a lambda
expression. Each clause
has the form below.
[formals body_{1} body_{2} ...]
The formal parameters of a clause are defined by formals
in the same manner as for a lambda
expression. The number of arguments accepted by the procedure value of a caselambda
expression is determined by the numbers of arguments accepted by the individual clauses.
When a procedure created with caselambda
is invoked, the clauses are considered in order. The first clause that accepts the given number of actual parameters is selected, the formal parameters defined by its formals
are bound to the corresponding actual parameters, and the body is evaluated as described for lambda
above. If formals
in a clause is a proper list of identifiers, then the clause accepts exactly as many actual parameters as there are formal parameters (identifiers) in formals
. As with a lambda
formals
, a caselambda
clause formals
may be a single identifier, in which case the clause accepts any number of arguments, or an improper list of identifiers terminated by an identifier, in which case the clause accepts any number of arguments greater than or equal to the number of formal parameters excluding the terminating identifier. If no clause accepts the number of actual parameters supplied, an exception with condition type &assertion
is raised.
The following definition for makelist
uses caselambda
to support an optional fill parameter.
(define makelist
(caselambda
[(n) (makelist n #f)]
[(n x)
(do ([n n ( n 1)] [ls '() (cons x ls)])
((zero? n) ls))]))
The substring
procedure may be extended with caselambda
to accept either no end
index, in which case it defaults to the end of the string, or no start
and end
indices, in which case substring
is equivalent to stringcopy
:
(define substring1
(caselambda
[(s) (substring1 s 0 (stringlength s))]
[(s start) (substring1 s start (stringlength s))]
[(s start end) (substring s start end)]))
It is also possible to default the start
index rather than the end
index when only one index is supplied:
(define substring2
(caselambda
[(s) (substring2 s 0 (stringlength s))]
[(s end) (substring2 s 0 end)]
[(s start end) (substring s start end)]))
It is even possible to require that both or neither of the start
and end
indices be supplied, simply by leaving out the middle clause:
(define substring3
(caselambda
[(s) (substring3 s 0 (stringlength s))]
[(s start end) (substring s start end)]))
Section 4.4. Local Binding
syntax 

returns 
the values of the final body expression 
libraries 

let
establishes local variable bindings. Each variable var
is bound to the value of the corresponding expression expr
. The body of the let
, in which the variables are bound, is the sequence of subforms body_{1} body_{2} ...
and is processed and evaluated like a lambda
body.
The forms let
, let*
, letrec
, and letrec*
(the others are described after let
) are similar but serve slightly different purposes. With let
, in contrast with let*
, letrec
, and letrec*
, the expressions expr ...
are all outside the scope of the variables var ...
. Also, in contrast with let*
and letrec*
, no ordering is implied for the evaluation of the expressions expr ...
. They may be evaluated from left to right, from right to left, or in any other order at the discretion of the implementation. Use let
whenever the values are independent of the variables and the order of evaluation is unimportant.
(let ([x (* 3.0 3.0)] [y (* 4.0 4.0)])
(sqrt (+ x y))) ⇒ 5.0
(let ([x 'a] [y '(b c)])
(cons x y)) ⇒ (a b c)
(let ([x 0] [y 1])
(let ([x y] [y x])
(list x y))) ⇒ (1 0)
The following definition of let
shows the typical derivation of let
from lambda
.
(definesyntax let
(syntaxrules ()
[(_ ((x e) ...) b1 b2 ...)
((lambda (x ...) b1 b2 ...) e ...)]))
Another form of let
, named let
, is described in Section 5.4, and a definition of the full let
can be found on page 312.
syntax 

returns 
the values of the final body expression 
libraries 

let*
is similar to let
except that the expressions expr ...
are evaluated in sequence from left to right, and each of these expressions is within the scope of the variables to the left. Use let*
when there is a linear dependency among the values or when the order of evaluation is important.
(let* ([x (* 5.0 5.0)]
[y ( x (* 4.0 4.0))])
(sqrt y)) ⇒ 3.0
(let ([x 0] [y 1])
(let* ([x y] [y x])
(list x y))) ⇒ (1 1)
Any let*
expression may be converted to a set of nested let
expressions. The following definition of let*
demonstrates the typical transformation.
(definesyntax let*
(syntaxrules ()
[(_ () e1 e2 ...)
(let () e1 e2 ...)]
[(_ ((x1 v1) (x2 v2) ...) e1 e2 ...)
(let ((x1 v1))
(let* ((x2 v2) ...) e1 e2 ...))]))
syntax 

returns 
the values of the final body expression 
libraries 

letrec
is similar to let
and let*
, except that all of the expressions expr ...
are within the scope of all of the variables var ...
. letrec
allows the definition of mutually recursive procedures.
(letrec ([sum (lambda (x)
(if (zero? x)
0
(+ x (sum ( x 1)))))])
(sum 5)) ⇒ 15
The order of evaluation of the expressions expr ...
is unspecified, so a program must not evaluate a reference to any of the variables bound by the letrec
expression before all of the values have been computed. (Occurrence of a variable within a lambda
expression does not count as a reference, unless the resulting procedure is applied before all of the values have been computed.) If this restriction is violated, an exception with condition type &assertion
is raised.
An expr
should not return more than once. That is, it should not return both normally and via the invocation of a continuation obtained during its evaluation, and it should not return twice via two invocations of such a continuation. Implementations are not required to detect a violation of this restriction, but if they do, an exception with condition type &assertion
is raised.
Choose letrec
over let
or let*
when there is a circular dependency among the variables and their values and when the order of evaluation is unimportant. Choose letrec*
over letrec
when there is a circular dependency and the bindings need to be evaluated from left to right.
A letrec
expression of the form
(letrec ((var expr) ...) body_{1} body_{2} ...)
may be expressed in terms of let
and set!
as
(let ((var #f) ...)
(let ((temp expr) ...)
(set! var temp) ...
(let () body_{1} body_{2} ...)))
where temp ...
are fresh variables, i.e., ones that do not already appear in the letrec
expression, one for each (var expr)
pair. The outer let
expression establishes the variable bindings. The initial value given each variable is unimportant, so any value suffices in place of #f
. The bindings are established first so that expr ...
may contain occurrences of the variables, i.e., so that the expressions are computed within the scope of the variables. The middle let
evaluates the values and binds them to the temporary variables, and the set!
expressions assign each variable to the corresponding value. The inner let
is present in case the body contains internal definitions.
A definition of letrec
that uses this transformation is shown on page 310.
This transformation does not enforce the restriction that the expr
expressions must not evaluate any references of or assignments to the variables. More elaborate transformations that enforce this restriction and actually produce more efficient code are possible [31].
syntax  
returns 
the values of the final body expression 
libraries 

letrec*
is similar to letrec
, except that letrec*
evaluates expr ...
in sequence from left to right. While programs must still not evaluate a reference to any var
before the corresponding expr
has been evaluated, references to var
may be evaluated any time thereafter, including during the evaluation of the expr
of any subsequent binding.
A letrec*
expression of the form
(letrec* ((var expr) ...) body_{1} body_{2} ...)
may be expressed in terms of let
and set!
as
(let ((var #f) ...)
(set! var expr) ...
(let () body_{1} body_{2} ...))
The outer let
expression creates the bindings, each assignment evaluates an expression and immediately sets the corresponding variable to its value, in sequence, and the inner let evaluates the body. let
is used in the latter case rather than begin
since the body may include internal definitions as well as expressions.
(letrec* ([sum (lambda (x)
(if (zero? x)
0
(+ x (sum ( x 1)))))]
[f (lambda () (cons n nsum))]
[n 15]
[nsum (sum n)])
(f)) ⇒ (15 . 120)
(letrec* ([f (lambda () (lambda () g))]
[g (f)])
(eq? (g) g)) ⇒ #t
(letrec* ([g (f)]
[f (lambda () (lambda () g))])
(eq? (g) g)) ⇒ exception: attempt to reference undefined variable f
Section 4.5. Multiple Values
syntax  
syntax 

returns 
the values of the final body expression 
libraries 

letvalues
is a convenient way to receive multiple values and bind them to variables. It is structured like let
but permits an arbitrary formals list (like lambda
) on each lefthand side. let*values
is similar but performs the bindings in lefttoright order, as with let*
. An exception with condition type &assertion
is raised if the number of values returned by an expr
is not appropriate for the corresponding formals
, as described in the entry for lambda
above. A definition of letvalues
is given on page 310.
(letvalues ([(a b) (values 1 2)] [c (values 1 2 3)])
(list a b c)) ⇒ (1 2 (1 2 3))
(let*values ([(a b) (values 1 2)] [(a b) (values b a)])
(list a b)) ⇒ (2 1)
Section 4.6. Variable Definitions
syntax 

syntax 

syntax 

syntax 

syntax 

libraries 

In the first form, define
creates a new binding of var
to the value of expr
. The expr
should not return more than once. That is, it should not return both normally and via the invocation of a continuation obtained during its evaluation, and it should not return twice via two invocations of such a continuation. Implementations are not required to detect a violation of this restriction, but if they do, an exception with condition type &assertion
is raised.
The second form is equivalent to (define var unspecified)
, where unspecified
is some unspecified value. The remaining are shorthand forms for binding variables to procedures; they are identical to the following definition in terms of lambda
.
(define var
(lambda formals
body_{1} body_{2} ...))
where formals
is (var_{1} ...)
, var_{r}
, or (var_{1} var_{2} ... . var_{r})
for the third, fourth, and fifth define
formats.
Definitions may appear at the front of a library
body, anywhere among the forms of a toplevelprogram body, and at the front of a lambda
or caselambda
body or the body of any form derived from lambda
, e.g., let
, or letrec*
. Any body that begins with a sequence of definitions is transformed during macro expansion into a letrec*
expression as described on page 292.
Syntax definitions may appear along with variable definitions wherever variable definitions may appear; see Chapter 8.
(define x 3)
x ⇒ 3
(define f
(lambda (x y)
(* (+ x y) 2)))
(f 5 4) ⇒ 18
(define (sumofsquares x y)
(+ (* x x) (* y y)))
(sumofsquares 3 4) ⇒ 25
(define f
(lambda (x)
(+ x 1)))
(let ([x 2])
(define f
(lambda (y)
(+ y x)))
(f 3)) ⇒ 5
(f 3) ⇒ 4
A set of definitions may be grouped by enclosing them in a begin
form. Definitions grouped in this manner may appear wherever ordinary variable and syntax definitions may appear. They are treated as if written separately, i.e., without the enclosing begin
form. This feature allows syntactic extensions to expand into groups of definitions.
(definesyntax multidefinesyntax
(syntaxrules ()
[(_ (var expr) ...)
(begin
(definesyntax var expr)
...)]))
(let ()
(define plus
(lambda (x y)
(if (zero? x)
y
(plus (sub1 x) (add1 y)))))
(multidefinesyntax
(add1 (syntaxrules () [(_ e) (+ e 1)]))
(sub1 (syntaxrules () [(_ e) ( e 1)])))
(plus 7 8)) ⇒ 15
Many implementations support an interactive "top level" in which variable and other definitions may be entered interactively or loaded from files. The behavior of these toplevel definitions is outside the scope of the Revised^{6} Report, but as long as toplevel variables are defined before any references or assignments to them are evaluated, the behavior is consistent across most implementations. So, for example, the reference to g
in the toplevel definition of f
below is okay if g
is not already defined, and g
is assumed to name a variable to be defined at some later point.
(define f
(lambda (x)
(g x)))
If this is then followed by a definition of g
before f
is evaluated, the assumption that g
would be defined as a variable is proven correct, and a call to f
works as expected.
(define g
(lambda (x)
(+ x x)))
(f 3) ⇒ 6
If g
were defined instead as the keyword for a syntactic extension, the assumption that g
would be bound as a variable is proven false, and if f
is not redefined before it is invoked, the implementation is likely to raise an exception.
Section 4.7. Assignment
syntax 

returns 
unspecified 
libraries 

set!
does not establish a new binding for var
but rather alters the value of an existing binding. It first evaluates expr
, then assigns var
to the value of expr
. Any subsequent reference to var
within the scope of the altered binding evaluates to the new value.
Assignments are not employed as frequently in Scheme as in most other languages, but they are useful for implementing state changes.
(define flipflop
(let ([state #f])
(lambda ()
(set! state (not state))
state)))
(flipflop) ⇒ #t
(flipflop) ⇒ #f
(flipflop) ⇒ #t
Assignments are also useful for caching values. The example below uses a technique called memoization, in which a procedure records the values associated with old input values so it need not recompute them, to implement a fast version of the otherwise exponential doubly recursive definition of the Fibonacci function (see page 69).
(define memoize
(lambda (proc)
(let ([cache '()])
(lambda (x)
(cond
[(assq x cache) => cdr]
[else
(let ([ans (proc x)])
(set! cache (cons (cons x ans) cache))
ans)])))))
(define fibonacci
(memoize
(lambda (n)
(if (< n 2)
1
(+ (fibonacci ( n 1)) (fibonacci ( n 2)))))))
(fibonacci 100) ⇒ 573147844013817084101
Chapter 5. Control Operations
This chapter introduces the syntactic forms and procedures that serve as control structures for Scheme programs, The first section covers the most basic control structure, procedure application, and the remaining sections cover sequencing, conditional evaluation, recursion, mapping, continuations, delayed evaluation, multiple values, and evaluation of programs constructed at run time.
Section 5.1. Procedure Application
syntax 

returns 
values of applying the value of 
Procedure application is the most basic Scheme control structure. Any structured form without a syntax keyword in the first position is a procedure application. The expressions expr_{0}
and expr_{1} ...
are evaluated; each should evaluate to a single value. After each of these expressions has been evaluated, the value of expr_{0}
is applied to the values of expr_{1} ...
. If expr_{0}
does not evaluate to a procedure, or if the procedure does not accept the number of arguments provided, an exception with condition type &assertion
is raised.
The order in which the procedure and argument expressions are evaluated is unspecified. It may be left to right, right to left, or any other order. The evaluation is guaranteed to be sequential, however: whatever order is chosen, each expression is fully evaluated before evaluation of the next is started.
(+ 3 4) ⇒ 7
((if (odd? 3) + ) 6 2) ⇒ 8
((lambda (x) x) 5) ⇒ 5
(let ([f (lambda (x) (+ x x))])
(f 8)) ⇒ 16
procedure  
returns 
the values of applying 
libraries 

apply
invokes procedure
, passing the first obj
as the first argument, the second obj
as the second argument, and so on for each object in obj ...
, and passing the elements of list
in order as the remaining arguments. Thus, procedure
is called with as many arguments as there are objs
plus elements of list
.
apply
is useful when some or all of the arguments to be passed to a procedure are in a list, since it frees the programmer from explicitly destructuring the list.
(apply + '(4 5)) ⇒ 9
(apply min '(6 8 3 2 5)) ⇒ 2
(apply min 5 1 3 '(6 8 3 2 5)) ⇒ 1
(apply vector 'a 'b '(c d e)) ⇒ #(a b c d e)
(define first
(lambda (ls)
(apply (lambda (x . y) x) ls)))
(define rest
(lambda (ls)
(apply (lambda (x . y) y) ls)))
(first '(a b c d)) ⇒ a
(rest '(a b c d)) ⇒ (b c d)
(apply append
'(1 2 3)
'((a b) (c d e) (f))) ⇒ (1 2 3 a b c d e f)
Section 5.2. Sequencing
syntax 

returns 
the values of the last subexpression 
libraries 

The expressions expr_{1} expr_{2} ...
are evaluated in sequence from left to right. begin
is used to sequence assignments, input/output, or other operations that cause side effects.
(define x 3)
(begin
(set! x (+ x 1))
(+ x x)) ⇒ 8
A begin
form may contain zero or more definitions in place of the expressions expr_{1} expr_{2} ...
, in which case it is considered to be a definition and may appear only where definitions are valid.
(let ()
(begin (define x 3) (define y 4))
(+ x y)) ⇒ 7
This form of begin
is primarily used by syntactic extensions that must expand into multiple definitions. (See page 101.)
The bodies of many syntactic forms, including lambda
, caselambda
, let
, let*
, letrec
, and letrec*
, as well as the result clauses of cond
, case
, and do
, are treated as if they were inside an implicit begin
; i.e., the expressions making up the body or result clause are executed in sequence, with the values of the last expression being returned.
(define swappair!
(lambda (x)
(let ([temp (car x)])
(setcar! x (cdr x))
(setcdr! x temp)
x)))
(swappair! (cons 'a 'b)) ⇒ (b . a)
Section 5.3. Conditionals
syntax 

syntax 

returns 
the values of 
libraries 

The test
, consequent
, and alternative
subforms must be expressions. If test
evaluates to a true value (anything other than #f
), consequent
is evaluated and its values are returned. Otherwise, alternative
is evaluated and its values are returned. With the second, "onearmed," form, which has no alternative
, the result is unspecified if test
evaluates to false.
(let ([ls '(a b c)])
(if (null? ls)
'()
(cdr ls))) ⇒ (b c)
(let ([ls '()])
(if (null? ls)
'()
(cdr ls))) ⇒ ()
(let ([abs
(lambda (x)
(if (< x 0)
( 0 x)
x))])
(abs 4)) ⇒ 4
(let ([x 4])
(if (< x 0)
(list 'minus ( 0 x))
(list 'plus 4))) ⇒ (minus 4)
procedure 

returns 

libraries 

not
is equivalent to (lambda (x) (if x #f #t))
.
(not #f) ⇒ #t
(not #t) ⇒ #f
(not '()) ⇒ #f
(not (< 4 5)) ⇒ #f
syntax 

returns 
see below 
libraries 

If no subexpressions are present, the and
form evaluates to #t
. Otherwise, and
evaluates each subexpression in sequence from left to right until only one subexpression remains or a subexpression returns #f
. If one subexpression remains, it is evaluated and its values are returned. If a subexpression returns #f
, and
returns #f
without evaluating the remaining subexpressions. A syntax definition of and
appears on page 62.
(let ([x 3])
(and (> x 2) (< x 4))) ⇒ #t
(let ([x 5])
(and (> x 2) (< x 4))) ⇒ #f
(and #f '(a b) '(c d)) ⇒ #f
(and '(a b) '(c d) '(e f)) ⇒ (e f)
syntax 

returns 
see below 
libraries 

If no subexpressions are present, the or
form evaluates to #f
. Otherwise, or
evaluates each subexpression in sequence from left to right until only one subexpression remains or a subexpression returns a value other than #f
. If one subexpression remains, it is evaluated and its values are returned. If a subexpression returns a value other than #f
, or
returns that value without evaluating the remaining subexpressions. A syntax definition of or
appears on page 63.
(let ([x 3])
(or (< x 2) (> x 4))) ⇒ #f
(let ([x 5])
(or (< x 2) (> x 4))) ⇒ #t
(or #f '(a b) '(c d)) ⇒ (a b)
syntax 

returns 
see below 
libraries 

Each clause
but the last must take one of the forms below.
(test)
(test expr_{1} expr_{2} ...)
(test => expr)
The last clause may be in any of the above forms, or it may be an "else
clause" of the form
(else expr_{1} expr_{2} ...)
Each test
is evaluated in order until one evaluates to a true value or until all of the tests have been evaluated. If the first clause whose test
evaluates to a true value is in the first form given above, the value of test
is returned.
If the first clause whose test
evaluates to a true value is in the second form given above, the expressions expr_{1} expr_{2} ...
are evaluated in sequence and the values of the last expression are returned.
If the first clause whose test
evaluates to a true value is in the third form given above, the expression expr
is evaluated. The value should be a procedure of one argument, which is applied to the value of test
. The values of this application are returned.
If none of the tests evaluates to a true value and an else
clause is present, the expressions expr_{1} expr_{2} ...
of the else
clause are evaluated in sequence and the values of the last expression are returned.
If none of the tests evaluates to a true value and no else
clause is present, the value or values are unspecified.
See page 305 for a syntax definition of cond
.
(let ([x 0])
(cond
[(< x 0) (list 'minus (abs x))]
[(> x 0) (list 'plus x)]
[else (list 'zero x)])) ⇒ (zero 0)
(define select
(lambda (x)
(cond
[(not (symbol? x))]
[(assq x '((a . 1) (b . 2) (c . 3))) => cdr]
[else 0])))
(select 3) ⇒ #t
(select 'b) ⇒ 2
(select 'e) ⇒ 0
syntax 

syntax 

libraries 

These identifiers are auxiliary keywords for cond
. Both also serve as auxiliary keywords for guard
, and else
also serves as an auxiliary keyword for case
. It is a syntax violation to reference these identifiers except in contexts where they are recognized as auxiliary keywords.
syntax 

syntax 

returns 
see below 
libraries 

For when
, if testexpr
evaluates to a true value, the expressions expr_{1} expr_{2} ...
are evaluated in sequence, and the values of the last expression are returned. If testexpr
evaluates to false, none of the other expressions are evaluated, and the value or values of when
are unspecified.
For unless
, if testexpr
evaluates to false, the expressions expr_{1} expr_{2} ...
are evaluated in sequence, and the values of the last expression are returned. If testexpr
evaluates to a true value, none of the other expressions are evaluated, and the value or values of unless
are unspecified.
A when
or unless
expression is usually clearer than the corresponding "onearmed" if
expression.
(let ([x 4] [sign 'plus])
(when (< x 0)
(set! x ( 0 x))
(set! sign 'minus))
(list sign x)) ⇒ (minus 4)
(define checkpair
(lambda (x)
(unless (pair? x)
(syntaxviolation 'checkpair "invalid argument" x))
x))
(checkpair '(a b c)) ⇒ (a b c)
when
may be defined as follows:
(definesyntax when
(syntaxrules ()
[(_ e0 e1 e2 ...)
(if e0 (begin e1 e2 ...))]))
unless
may be defined as follows:
(definesyntax unless
(syntaxrules ()
[(_ e0 e1 e2 ...)
(if (not e0) (begin e1 e2 ...))]))
or in terms of when
as follows:
(definesyntax unless
(syntaxrules ()
[(_ e0 e1 e2 ...)
(when (not e0) e1 e2 ...)]))
syntax 

returns 
see below 
libraries 

Each clause but the last must take the form
((key ...) expr_{1} expr_{2} ...)
where each key
is a datum distinct from the other keys. The last clause may be in the above form or it may be an else
clause of the form
(else expr_{1} expr_{2} ...)
expr_{0}
is evaluated and the result is compared (using eqv?
) against the keys of each clause in order. If a clause containing a matching key is found, the expressions expr_{1} expr_{2} ...
are evaluated in sequence and the values of the last expression are returned.
If none of the clauses contains a matching key and an else
clause is present, the expressions expr_{1} expr_{2} ...
of the else
clause are evaluated in sequence and the values of the last expression are returned.
If none of the clauses contains a matching key and no else
clause is present, the value or values are unspecified.
See page 306 for a syntax definition of case
.
(let ([x 4] [y 5])
(case (+ x y)
[(1 3 5 7 9) 'odd]
[(0 2 4 6 8) 'even]
[else 'outofrange])) ⇒ odd
Section 5.4. Recursion and Iteration
syntax 

returns 
values of the final body expression 
libraries 

This form of let
, called named
let
, is a generalpurpose iteration and recursion construct. It is similar to the more common form of let
(see Section 4.4) in the binding of the variables var ...
to the values of expr ...
within the body body_{1} body_{2} ...
, which is processed and evaluated like a lambda
body. In addition, the variable name
is bound within the body to a procedure that may be called to recur or iterate; the arguments to the procedure become the new values of the variables var ...
.
A named let
expression of the form
(let name ((var expr) ...)
body_{1} body_{2} ...)
can be rewritten with letrec
as follows.
((letrec ((name (lambda (var ...) body_{1} body_{2} ...)))
name)
expr ...)
A syntax definition of let
that implements this transformation and handles unnamed let
as well can be found on page 312.
The procedure divisors
defined below uses named let
to compute the nontrivial divisors of a nonnegative integer.
(define divisors
(lambda (n)
(let f ([i 2])
(cond
[(>= i n) '()]
[(integer? (/ n i)) (cons i (f (+ i 1)))]
[else (f (+ i 1))]))))
(divisors 5) ⇒ ()
(divisors 32) ⇒ (2 4 8 16)
The version above is nontailrecursive when a divisor is found and tailrecursive when a divisor is not found. The version below is fully tailrecursive. It builds up the list in reverse order, but this is easy to remedy, if desired, by reversing the list on exit.
(define divisors
(lambda (n)
(let f ([i 2] [ls '()])
(cond
[(>= i n) ls]
[(integer? (/ n i)) (f (+ i 1) (cons i ls))]
[else (f (+ i 1) ls)]))))
syntax 

returns 
the values of the last 
libraries 

do
allows a common restricted form of iteration to be expressed succinctly. The variables var ...
are bound initially to the values of init ...
and are rebound on each subsequent iteration to the values of update ...
. The expressions test
, update ...
, expr ...
, and result ...
are all within the scope of the bindings established for var ...
.
On each step, the test expression test
is evaluated. If the value of test
is true, iteration ceases, the expressions result ...
are evaluated in sequence, and the values of the last expression are returned. If no result expressions are present, the value or values of the do
expression are unspecified.
If the value of test
is false, the expressions expr ...
are evaluated in sequence, the expressions update ...
are evaluated, new bindings for var ...
to the values of update ...
are created, and iteration continues.
The expressions expr ...
are evaluated only for effect and are often omitted entirely. Any update
expression may be omitted, in which case the effect is the same as if the update
were simply the corresponding var
.
Although looping constructs in most languages require that the loop iterands be updated via assignment, do
requires the loop iterands var ...
to be updated via rebinding. In fact, no side effects are involved in the evaluation of a do
expression unless they are performed explicitly by its subexpressions.
See page 313 for a syntax definition of do
.
The definitions of factorial
and fibonacci
below are straightforward translations of the tailrecursive namedlet
versions given in Section 3.2.
(define factorial
(lambda (n)
(do ([i n ( i 1)] [a 1 (* a i)])
((zero? i) a))))
(factorial 10) ⇒ 3628800
(define fibonacci
(lambda (n)
(if (= n 0)
0
(do ([i n ( i 1)] [a1 1 (+ a1 a2)] [a2 0 a1])
((= i 1) a1)))))
(fibonacci 6) ⇒ 8
The definition of divisors
below is similar to the tailrecursive definition of divisors
given with the description of named let
above.
(define divisors
(lambda (n)
(do ([i 2 (+ i 1)]
[ls '()
(if (integer? (/ n i))
(cons i ls)
ls)])
((>= i n) ls))))
The definition of scalevector!
below, which scales each element of a vector v by a constant k, demonstrates a nonempty do
body.
(define scalevector!
(lambda (v k)
(let ([n (vectorlength v)])
(do ([i 0 (+ i 1)])
((= i n))
(vectorset! v i (* (vectorref v i) k))))))
(define vec (vector 1 2 3 4 5))
(scalevector! vec 2)
vec ⇒ #(2 4 6 8 10)
Section 5.5. Mapping and Folding
When a program must recur or iterate over the elements of a list, a mapping or folding operator is often more convenient. These operators abstract away from null checks and explicit recursion by applying a procedure to the elements of the list one by one. A few mapping operators are also available for vectors and strings.
procedure 

returns 
list of results 
libraries 

map
applies procedure
to corresponding elements of the lists list_{1} list_{2} ...
and returns a list of the resulting values. The lists list_{1} list_{2} ...
must be of the same length. procedure
should accept as many arguments as there are lists, should return a single value, and should not mutate the list
arguments.
(map abs '(1 2 3 4 5 6)) ⇒ (1 2 3 4 5 6)
(map (lambda (x y) (* x y))
'(1 2 3 4)
'(8 7 6 5)) ⇒ (8 14 18 20)
While the order in which the applications themselves occur is not specified, the order of the values in the output list is the same as that of the corresponding values in the input lists.
map
might be defined as follows.
(define map
(lambda (f ls . more)
(if (null? more)
(let map1 ([ls ls])
(if (null? ls)
'()
(cons (f (car ls))
(map1 (cdr ls)))))
(let mapmore ([ls ls] [more more])
(if (null? ls)
'()
(cons
(apply f (car ls) (map car more))
(mapmore (cdr ls) (map cdr more))))))))
No error checking is done by this version of map
; f
is assumed to be a procedure and the other arguments are assumed to be proper lists of the same length. An interesting feature of this definition is that map
uses itself to pull out the cars and cdrs of the list of input lists; this works because of the special treatment of the singlelist case.
procedure  
returns 
unspecified 
libraries 

foreach
is similar to map
except that foreach
does not create and return a list of the resulting values, and foreach
guarantees to perform the applications in sequence over the elements from left to right. procedure
should accept as many arguments as there are lists and should not mutate the list
arguments. foreach
may be defined without error checks as follows.
(define foreach
(lambda (f ls . more)
(do ([ls ls (cdr ls)] [more more (map cdr more)])
((null? ls))
(apply f (car ls) (map car more)))))
(let ([samecount 0])
(foreach
(lambda (x y)
(when (= x y)
(set! samecount (+ samecount 1))))
'(1 2 3 4 5 6)
'(2 3 3 4 7 6))
samecount) ⇒ 3
procedure 

returns 
see below 
libraries 

The lists list_{1} list_{2} ...
must be of the same length. procedure
should accept as many arguments as there are lists and should not mutate the list
arguments. If the lists are empty, exists
returns #f
. Otherwise, exists
applies procedure
to corresponding elements of the lists list_{1} list_{2} ...
in sequence until either the lists each have only one element or procedure
returns a true value t
. In the former case, exists
tailcalls procedure
, applying it to the remaining element of each list. In the latter case, exists
returns t
.
(exists symbol? '(1.0 #\a "hi" '())) ⇒ #f
(exists member
'(a b c)
'((c b) (b a) (a c))) ⇒ (b a)
(exists (lambda (x y z) (= (+ x y) z))
'(1 2 3 4)
'(1.2 2.3 3.4 4.5)
'(2.3 4.4 6.4 8.6)) ⇒ #t
exists
may be defined (somewhat inefficiently and without error checks) as follows:
(define exists
(lambda (f ls . more)
(and (not (null? ls))
(let exists ([x (car ls)] [ls (cdr ls)] [more more])
(if (null? ls)
(apply f x (map car more))
(or (apply f x (map car more))
(exists (car ls) (cdr ls) (map cdr more))))))))
procedure 

returns 
see below 
libraries 

The lists list_{1} list_{2} ...
must be of the same length. procedure
should accept as many arguments as there are lists and should not mutate the list
arguments. If the lists are empty, forall
returns #t
. Otherwise, forall
applies procedure
to corresponding elements of the lists list_{1} list_{2} ...
in sequence until either the lists each have only one element left or procedure
returns #f
. In the former case, forall
tailcalls procedure
, applying it to the remaining element of each list. In the latter case, forall
returns #f
.
(forall symbol? '(a b c d)) ⇒ #t
(forall =
'(1 2 3 4)
'(1.0 2.0 3.0 4.0)) ⇒ #t
(forall (lambda (x y z) (= (+ x y) z))
'(1 2 3 4)
'(1.2 2.3 3.4 4.5)
'(2.2 4.3 6.5 8.5)) ⇒ #f
forall
may be defined (somewhat inefficiently and without error checks) as follows:
(define forall
(lambda (f ls . more)
(or (null? ls)
(let forall ([x (car ls)] [ls (cdr ls)] [more more])
(if (null? ls)
(apply f x (map car more))
(and (apply f x (map car more))
(forall (car ls) (cdr ls) (map cdr more))))))))
procedure 

returns 
see below 
libraries 

The list
arguments should all have the same length. procedure
should accept one more argument than the number of list
arguments and return a single value. It should not mutate the list
arguments.
foldleft
returns obj
if the list
arguments are empty. If they are not empty, foldleft
applies procedure
to obj
and the cars of list_{1} list_{2} ...
, then recurs with the value returned by procedure
in place of obj
and the cdr of each list
in place of the list
.
(foldleft cons '() '(1 2 3 4)) ⇒ ((((() . 1) . 2) . 3) . 4)
(foldleft
(lambda (a x) (+ a (* x x)))
0 '(1 2 3 4 5)) ⇒ 55
(foldleft
(lambda (a . args) (append args a))
'(question)
'(that not to)
'(is to be)
'(the be: or)) ⇒ (to be or not to be: that is the question)
procedure 

returns 
see below 
libraries 

The list
arguments should all have the same length. procedure
should accept one more argument than the number of list
arguments and return a single value. It should not mutate the list
arguments.
foldright
returns obj
if the list
arguments are empty. If they are not empty, foldright
recurs with the cdr of each list
replacing the list
, then applies procedure
to the cars of list_{1} list_{2} ...
and the result returned by the recursion.
(foldright cons '() '(1 2 3 4)) ⇒ (1 2 3 4)
(foldright
(lambda (x a) (+ a (* x x)))
0 '(1 2 3 4 5)) ⇒ 55
(foldright
(lambda (x y a) (cons* x y a)) ⇒ (parting is such sweet sorrow
'((with apologies)) gotta go see ya tomorrow
'(parting such sorrow go ya) (with apologies))
'(is sweet gotta see tomorrow))
procedure 

returns 
vector of results 
libraries 

vectormap
applies procedure
to corresponding elements of vector_{1} vector_{2} ...
and returns a vector of the resulting values. The vectors vector_{1} vector_{2} ...
must be of the same length, and procedure
should accept as many arguments as there are vectors and return a single value.
(vectormap abs '#(1 2 3 4 5 6)) ⇒ #(1 2 3 4 5 6)
(vectormap (lambda (x y) (* x y))
'#(1 2 3 4)
'#(8 7 6 5)) ⇒ #(8 14 18 20)
While the order in which the applications themselves occur is not specified, the order of the values in the output vector is the same as that of the corresponding values in the input vectors.
procedure 

returns 
unspecified 
libraries 

vectorforeach
is similar to vectormap
except that vectorforeach
does not create and return a vector of the resulting values, and vectorforeach
guarantees to perform the applications in sequence over the elements from left to right.
(let ([samecount 0])
(vectorforeach
(lambda (x y)
(when (= x y)
(set! samecount (+ samecount 1))))
'#(1 2 3 4 5 6)
'#(2 3 3 4 7 6))
samecount) ⇒ 3
procedure 

returns 
unspecified 
libraries 

stringforeach
is similar to foreach
and vectorforeach
except that the inputs are strings rather than lists or vectors.
(let ([ls '()])
(stringforeach
(lambda r (set! ls (cons r ls)))
"abcd"
"===="
"1234")
(map list>string (reverse ls))) ⇒ ("a=1" "b=2" "c=3" "d=4")
Section 5.6. Continuations
Continuations in Scheme are procedures that represent the remainder of a computation from a given point in the computation. They may be obtained with callwithcurrentcontinuation
, which can be abbreviated to call/cc
.
procedure 

procedure 

returns 
see below 
libraries 

These procedures are the same. The shorter name is often used for the obvious reason that it requires fewer keystrokes to type.
call/cc
obtains its continuation and passes it to procedure
, which should accept one argument. The continuation itself is represented by a procedure. Each time this procedure is applied to zero or more values, it returns the values to the continuation of the call/cc
application. That is, when the continuation procedure is called, it returns its arguments as the values of the application of call/cc
.
If procedure
returns normally when passed the continuation procedure, the values returned by call/cc
are the values returned by procedure
.
Continuations allow the implementation of nonlocal exits, backtracking ([14],[29]), coroutines [16], and multitasking ([10],[32]).
The example below illustrates the use of a continuation to perform a nonlocal exit from a loop.
(define member
(lambda (x ls)
(call/cc
(lambda (break)
(do ([ls ls (cdr ls)])
((null? ls) #f)
(when (equal? x (car ls))
(break ls)))))))
(member 'd '(a b c)) ⇒ #f
(member 'b '(a b c)) ⇒ (b c)
The current continuation is typically represented internally as a stack of procedure activation records, and obtaining the continuation involves encapsulating the stack within a procedural object. Since an encapsulated stack has indefinite extent, some mechanism must be used to preserve the stack contents indefinitely. This can be done with surprising ease and efficiency and with no impact on programs that do not use continuations [17].
procedure 

returns 
values resulting from the application of 
libraries 

dynamicwind
offers "protection" from continuation invocation. It is useful for performing tasks that must be performed whenever control enters or leaves body
, either normally or by continuation application.
The three arguments in
, body
, and out
must be procedures and should accept zero arguments, i.e., they should be thunks
. Before applying body
, and each time body
is entered subsequently by the application of a continuation created within body
, the in
thunk is applied. Upon normal exit from body
and each time body
is exited by the application of a continuation created outside body
, the out
thunk is applied.
Thus, it is guaranteed that in
is invoked at least once. In addition, if body
ever returns, out
is invoked at least once.
The following example demonstrates the use of dynamicwind
to be sure that an input port is closed after processing, regardless of whether the processing completes normally.
(let ([p (openinputfile "inputfile")])
(dynamicwind
(lambda () #f)
(lambda () (process p))
(lambda () (closeport p))))
Common Lisp provides a similar facility (unwindprotect
) for protection from nonlocal exits. This is often sufficient. unwindprotect
provides only the equivalent to out
, however, since Common Lisp does not support fully general continuations. Here is how unwindprotect
might be specified with dynamicwind
.
(definesyntax unwindprotect
(syntaxrules ()
[(_ body cleanup ...)
(dynamicwind
(lambda () #f)
(lambda () body)
(lambda () cleanup ...))]))
((call/cc
(let ([x 'a])
(lambda (k)
(unwindprotect
(k (lambda () x))
(set! x 'b)))))) ⇒ b
Some Scheme implementations support a controlled form of assignment known as fluid binding, in which a variable takes on a temporary value during a given computation and reverts to the old value after the computation has completed. The syntactic form fluidlet
defined below in terms of dynamicwind
permits the fluid binding of a single variable x
to the value of an expression e
within a the body b1 b2 ...
.
(definesyntax fluidlet
(syntaxrules ()
[(_ ((x e)) b1 b2 ...)
(let ([y e])
(let ([swap (lambda () (let ([t x]) (set! x y) (set! y t)))])
(dynamicwind swap (lambda () b1 b2 ...) swap)))]))
Implementations that support fluidlet
typically extend it to allow an indefinite number of (x e)
pairs, as with let
.
If no continuations are invoked within the body of a fluidlet
, the behavior is the same as if the variable were simply assigned the new value on entry and assigned the old value on return.
(let ([x 3])
(+ (fluidlet ([x 5])
x)
x)) ⇒ 8
A fluidbound variable also reverts to the old value if a continuation created outside of the fluidlet
is invoked.
(let ([x 'a])
(let ([f (lambda () x)])
(cons (call/cc
(lambda (k)
(fluidlet ([x 'b])
(k (f)))))
(f)))) ⇒ (b . a)
If control has left a fluidlet
body, either normally or by the invocation of a continuation, and control reenters the body by the invocation of a continuation, the temporary value of the fluidbound variable is reinstated. Furthermore, any changes to the temporary value are maintained and reflected upon reentry.
(define reenter #f)
(define x 0)
(fluidlet ([x 1])
(call/cc (lambda (k) (set! reenter k)))
(set! x (+ x 1))
x) ⇒ 2
x ⇒ 0
(reenter '*) ⇒ 3
(reenter '*) ⇒ 4
x ⇒ 0
A library showing how dynamicwind
might be implemented were it not already built in is given below. In addition to defining dynamicwind
, the code defines a version of call/cc
that does its part to support dynamicwind
.
(library (dynamicwind)
(export dynamicwind call/cc
(rename (call/cc callwithcurrentcontinuation)))
(import (rename (except (rnrs) dynamicwind) (call/cc rnrs:call/cc)))
(define winders '())
(define commontail
(lambda (x y)
(let ([lx (length x)] [ly (length y)])
(do ([x (if (> lx ly) (listtail x ( lx ly)) x) (cdr x)]
[y (if (> ly lx) (listtail y ( ly lx)) y) (cdr y)])
((eq? x y) x)))))
(define dowind
(lambda (new)
(let ([tail (commontail new winders)])
(let f ([ls winders])
(if (not (eq? ls tail))
(begin
(set! winders (cdr ls))
((cdar ls))
(f (cdr ls)))))
(let f ([ls new])
(if (not (eq? ls tail))
(begin
(f (cdr ls))
((caar ls))
(set! winders ls)))))))
(define call/cc
(lambda (f)
(rnrs:call/cc
(lambda (k)
(f (let ([save winders])
(lambda (x)
(unless (eq? save winders) (dowind save))
(k x))))))))
(define dynamicwind
(lambda (in body out)
(in)
(set! winders (cons (cons in out) winders))
(letvalues ([ans* (body)])
(set! winders (cdr winders))
(out)
(apply values ans*)))))
Together, dynamicwind
and call/cc
manage a list of winders. A winder is a pair of in and out thunks established by a call to dynamicwind
. Whenever dynamicwind
is invoked, the in thunk is invoked, a new winder containing the in and out thunks is placed on the winders list, the body thunk is invoked, the winder is removed from the winders list, and the out thunk is invoked. This ordering ensures that the winder is on the winders list only when control has passed through in and not yet entered out. Whenever a continuation is obtained, the winders list is saved, and whenever the continuation is invoked, the saved winders list is reinstated. During reinstatement, the out thunk of each winder on the current winders list that is not also on the saved winders list is invoked, followed by the in thunk of each winder on the saved winders list that is not also on the current winders list. The winders list is updated incrementally, again to ensure that a winder is on the current winders list only if control has passed through its in thunk and not entered its out thunk.
The test (not (eq? save winders))
performed in call/cc
is not strictly necessary but makes invoking a continuation less costly whenever the saved winders list is the same as the current winders list.
Section 5.7. Delayed Evaluation
The syntactic form delay
and the procedure force
may be used in combination to implement lazy evaluation. An expression subject to lazy evaluation is not evaluated until its value is required and, once evaluated, is never reevaluated.
syntax 

returns 
a promise 
procedure 

returns 
result of forcing 
libraries 

The first time a promise created by delay
is forced (with force
), it evaluates expr
, "remembering" the resulting value. Thereafter, each time the promise is forced, it returns the remembered value instead of reevaluating expr
.
delay
and force
are typically used only in the absence of side effects, e.g., assignments, so that the order of evaluation is unimportant.
The benefit of using delay
and force
is that some amount of computation might be avoided altogether if it is delayed until absolutely required. Delayed evaluation may be used to construct conceptually infinite lists, or streams. The example below shows how a stream abstraction may be built with delay
and force
. A stream is a promise that, when forced, returns a pair whose cdr is a stream.
(define streamcar
(lambda (s)
(car (force s))))
(define streamcdr
(lambda (s)
(cdr (force s))))
(define counters
(let next ([n 1])
(delay (cons n (next (+ n 1))))))
(streamcar counters) ⇒ 1
(streamcar (streamcdr counters)) ⇒ 2
(define streamadd
(lambda (s1 s2)
(delay (cons
(+ (streamcar s1) (streamcar s2))
(streamadd (streamcdr s1) (streamcdr s2))))))
(define evencounters
(streamadd counters counters))
(streamcar evencounters) ⇒ 2
(streamcar (streamcdr evencounters)) ⇒ 4
delay
may be defined by
(definesyntax delay
(syntaxrules ()
[(_ expr) (makepromise (lambda () expr))]))
where makepromise
might be defined as follows.
(define makepromise
(lambda (p)
(let ([val #f] [set? #f])
(lambda ()
(unless set?
(let ([x (p)])
(unless set?
(set! val x)
(set! set? #t))))
val))))
With this definition of delay
, force
simply invokes the promise to force evaluation or to retrieve the saved value.
(define force
(lambda (promise)
(promise)))
The second test of the variable set?
in makepromise
is necessary in the event that, as a result of applying p
, the promise is recursively forced. Since a promise must always return the same value, the result of the first application of p
to complete is returned.
Whether delay
and force
handle multiple return values is unspecified; the implementation given above does not, but the following version does, with the help of callwithvalues
and apply
.
(define makepromise
(lambda (p)
(let ([vals #f] [set? #f])
(lambda ()
(unless set?
(callwithvalues p
(lambda x
(unless set?
(set! vals x)
(set! set? #t)))))
(apply values vals)))))
(define p (delay (values 1 2 3)))
(force p) ⇒ 1
2
3
(callwithvalues (lambda () (force p)) +) ⇒ 6
Neither implementation is quite right, since force
must raise an exception with condition type &assertion
if its argument is not a promise. Since distinguishing procedures created by makepromise
from other procedures is impossible, force
cannot do so reliably. The following reimplementation of makepromise
and force
represents promises as records of the type promise
to allow force
to make the required check.
(definerecordtype promise
(fields (immutable p) (mutable vals) (mutable set?))
(protocol (lambda (new) (lambda (p) (new p #f #f)))))
(define force
(lambda (promise)
(unless (promise? promise)
(assertionviolation 'promise "invalid argument" promise))
(unless (promiseset? promise)
(callwithvalues (promisep promise)
(lambda x
(unless (promiseset? promise)
(promisevalsset! promise x)
(promiseset?set! promise #t)))))
(apply values (promisevals promise))))
Section 5.8. Multiple Values
While all Scheme primitives and most userdefined procedures return exactly one value, some programming problems are best solved by returning zero values, more than one value, or even a variable number of values. For example, a procedure that partitions a list of values into two sublists needs to return two values. While it is possible for the producer of multiple values to package them into a data structure and for the consumer to extract them, it is often cleaner to use the builtin multiplevalues interface. This interface consists of two procedures: values
and callwithvalues
. The former produces multiple values and the latter links procedures that produce multiplevalue values with procedures that consume them.
procedure 

returns 

libraries 

The procedure values
accepts any number of arguments and simply passes (returns) the arguments to its continuation.
(values) ⇒
(values 1) ⇒ 1
(values 1 2 3) ⇒ 1
2
3
(define head&tail
(lambda (ls)
(values (car ls) (cdr ls))))
(head&tail '(a b c)) ⇒ a
(b c)
procedure 

returns 
see below 
libraries 

producer
and consumer
must be procedures. callwithvalues
applies consumer
to the values returned by invoking producer
without arguments.
(callwithvalues
(lambda () (values 'bond 'james))
(lambda (x y) (cons y x))) ⇒ (james . bond)
(callwithvalues values list) ⇒ '()
In the second example, values
itself serves as the producer. It receives no arguments and thus returns no values. list
is thus applied to no arguments and so returns the empty list.
The procedure dxdy
defined below computes the change in x
and y
coordinates for a pair of points whose coordinates are represented by (x . y)
pairs.
(define dxdy
(lambda (p1 p2)
(values ( (car p2) (car p1))
( (cdr p2) (cdr p1)))))
(dxdy '(0 . 0) '(0 . 5)) ⇒ 0
5
dxdy
can be used to compute the length and slope of a segment represented by two endpoints.
(define segmentlength
(lambda (p1 p2)
(callwithvalues
(lambda () (dxdy p1 p2))
(lambda (dx dy) (sqrt (+ (* dx dx) (* dy dy)))))))
(define segmentslope
(lambda (p1 p2)
(callwithvalues
(lambda () (dxdy p1 p2))
(lambda (dx dy) (/ dy dx)))))
(segmentlength '(1 . 4) '(4 . 8)) ⇒ 5
(segmentslope '(1 . 4) '(4 . 8)) ⇒ 4/3
We can of course combine these to form one procedure that returns two values.
(define describesegment
(lambda (p1 p2)
(callwithvalues
(lambda () (dxdy p1 p2))
(lambda (dx dy)
(values
(sqrt (+ (* dx dx) (* dy dy)))
(/ dy dx))))))
(describesegment '(1 . 4) '(4 . 8)) ⇒ 5
⇒ 4/3
The example below employs multiple values to divide a list nondestructively into two sublists of alternating elements.
(define split
(lambda (ls)
(if (or (null? ls) (null? (cdr ls)))
(values ls '())
(callwithvalues
(lambda () (split (cddr ls)))
(lambda (odds evens)
(values (cons (car ls) odds)
(cons (cadr ls) evens)))))))
(split '(a b c d e f)) ⇒ (a c e)
(b d f)
At each level of recursion, the procedure split
returns two values: a list of the oddnumbered elements from the argument list and a list of the evennumbered elements.
The continuation of a call to values
need not be one established by a call to callwithvalues
, nor must only values
be used to return to a continuation established by callwithvalues
. In particular, (values e)
and e
are equivalent expressions. For example:
(+ (values 2) 4) ⇒ 6
(if (values #t) 1 2) ⇒ 1
(callwithvalues
(lambda () 4)
(lambda (x) x)) ⇒ 4
Similarly, values
may be used to pass any number of values to a continuation that ignores the values, as in the following.
(begin (values 1 2 3) 4) ⇒ 4
Because a continuation may accept zero or more than one value, continuations obtained via call/cc
may accept zero or more than one argument.
(callwithvalues
(lambda ()
(call/cc (lambda (k) (k 2 3))))
(lambda (x y) (list x y))) ⇒ (2 3)
The behavior is unspecified when a continuation expecting exactly one value receives zero values or more than one value. For example, the behavior of each of the following expressions is unspecified. Some implementations raise an exception, while others silently suppress additional values or supply defaults for missing values.
(if (values 1 2) 'x 'y)
(+ (values) 5)
Programs that wish to force extra values to be ignored in particular contexts can do so easily by calling callwithvalues
explicitly. A syntactic form, which we might call first
, can be defined to abstract the discarding of more than one value when only one is desired.
(definesyntax first
(syntaxrules ()
[(_ expr)
(callwithvalues
(lambda () expr)
(lambda (x . y) x))]))
(if (first (values #t #f)) 'a 'b) ⇒ a
Since implementations are required to raise an exception with condition type &assertion
if a procedure does not accept the number of arguments passed to it, each of the following raises an exception.
(callwithvalues
(lambda () (values 2 3 4))
(lambda (x y) x))
(callwithvalues
(lambda () (call/cc (lambda (k) (k 0))))
(lambda (x y) x))
Since producer
is most often a lambda
expression, it is often convenient to use a syntactic extension that suppresses the lambda expression in the interest of readability.
(definesyntax withvalues
(syntaxrules ()
[(_ expr consumer)
(callwithvalues (lambda () expr) consumer)]))
(withvalues (values 1 2) list) ⇒ (1 2)
(withvalues (split '(1 2 3 4))
(lambda (odds evens)
evens)) ⇒ (2 4)
If the consumer
is also a lambda
expression, the multiplevalue variants of let
and let*
described in Section 4.5 are usually even more convenient.
(letvalues ([(odds evens) (split '(1 2 3 4))])
evens) ⇒ (2 4)
(letvalues ([ls (values 'a 'b 'c)])
ls) ⇒ (a b c)
Many standard syntactic forms and procedures pass along multiple values. Most of these are "automatic," in the sense that nothing special must be done by the implementation to make this happen. The usual expansion of let
into a direct lambda
call automatically propagates multiple values produced by the body of the let
. Other operators must be coded specially to pass along multiple values. The callwithport
procedure (Section 7.6), for example, calls its procedure argument, then closes the port argument before returning the procedure’s values, so it must save the values temporarily. This is easily accomplished via letvalues
, apply
, and values
:
(define callwithport
(lambda (port proc)
(letvalues ([val* (proc port)])
(closeport port)
(apply values val*))))
If this seems like too much overhead when a single value is returned, the code can use callwithvalues
and caselambda
to handle the singlevalue case more efficiently:
(define callwithport
(lambda (port proc)
(callwithvalues (lambda () (proc port))
(caselambda
[(val) (closeport port) val]
[val* (closeport port) (apply values val*)]))))
The definitions of values
and callwithvalues
(and concomitant redefinition of call/cc
) in the library below demonstrate that the multiplereturnvalues interface could be implemented in Scheme if it were not already built in. No error checking can be done, however, for the case in which more than one value is returned to a singlevalue context, such as the test part of an if
expression.
(library (mrvs)
(export callwithvalues values call/cc
(rename (call/cc callwithcurrentcontinuation)))
(import
(rename
(except (rnrs) values callwithvalues)
(call/cc rnrs:call/cc)))
(define magic (cons 'multiple 'values))
(define magic?
(lambda (x)
(and (pair? x) (eq? (car x) magic))))
(define call/cc
(lambda (p)
(rnrs:call/cc
(lambda (k)
(p (lambda args
(k (apply values args))))))))
(define values
(lambda args
(if (and (not (null? args)) (null? (cdr args)))
(car args)
(cons magic args))))
(define callwithvalues
(lambda (producer consumer)
(let ([x (producer)])
(if (magic? x)
(apply consumer (cdr x))
(consumer x))))))
Multiple values can be implemented more efficiently [2], but this code serves to illustrate the meanings of the operators and may be used to provide multiple values in older, nonstandard implementations that do not support them.
Section 5.9. Eval
Scheme’s eval
procedure allows programmers to write programs that construct and evaluate other programs. This ability to do runtime meta programming should not be overused but is handy when needed.
procedure 

returns 
values of the Scheme expression represented by 
libraries 

If obj
does not represent a syntactically valid expression, eval
raises an exception with condition type &syntax
. The environments returned by environment
, schemereportenvironment
, and nullenvironment
are immutable. Thus, eval
also raises an exception with condition type &syntax
if an assignment to any of the variables in the environment appears within the expression.
(define cons 'notcons)
(eval '(let ([x 3]) (cons x 4)) (environment '(rnrs))) ⇒ (3 . 4)
(define lambda 'notlambda)
(eval '(lambda (x) x) (environment '(rnrs))) ⇒ #<procedure>
(eval '(cons 3 4) (environment)) ⇒ exception
procedure 

returns 
an environment 
libraries 

environment
returns an environment formed from the combined bindings of the given import specifiers. Each importspec
must be an sexpression representing a valid import specifier (see Chapter 10).
(define env (environment '(rnrs) '(prefix (rnrs lists) $)))
(eval '($cons* 3 4 (* 5 8)) env) ⇒ (3 4 . 40)
procedure 

procedure 

returns 
an R5RS compatibility environment 
libraries 

version
must be the exact integer 5
.
nullenvironment
returns an environment containing bindings for the keywords whose meanings are defined by the Revised^{5} Report on Scheme, along with bindings for the auxiliary keywords else
, =>
, ...
, and _
.
schemereportenvironment
returns an environment containing the same keyword bindings as the environment returned by nullenvironment
along with bindings for the variables whose meanings are defined by the Revised^{5} Report on Scheme, except those not defined by the Revised^{6} Report: load
, interactionenvironment
, transcripton
, transcriptoff
, and charready?
.
The bindings for each of the identifiers in the environments returned by these procedures are those of the corresponding Revised^{6} Report library, so this does not provide full backward compatibility, even if the excepted identifier bindings are not used.
Chapter 6. Operations on Objects
This chapter describes the operations on objects, including lists, numbers, characters, strings, vectors, bytevectors, symbols, booleans, hashtables, and enumerations. The first section covers constant objects and quotation. The second section describes generic equivalence predicates for comparing two objects and predicates for determining the type of an object. Later sections describe procedures that deal primarily with one of the object types mentioned above. There is no section treating operations on procedures, since the only operation defined specifically for procedures is application, and this is described in Chapter 5. Operations on ports are covered in the more general discussion of input and output in Chapter 7. A mechanism for defining new data types is described in Chapter 9.
Section 6.1. Constants and Quotation
syntax 

returns 

constant
is any selfevaluating constant, i.e., a number, boolean, character, string, or bytevector. Constants are immutable; see the note in the description of quote
below.
3.2 ⇒ 3.2
#f ⇒ #f
#\c ⇒ #\c
"hi" ⇒ "hi"
#vu8(3 4 5) ⇒ #vu8(3 4 5)
syntax 

syntax 

returns 

libraries 

'obj
is equivalent to (quote obj)
. The abbreviated form is converted into the longer form by the Scheme reader (see read
).
quote
inhibits the normal evaluation rule for obj
, allowing obj
to be employed as data. Although any Scheme object may be quoted, quotation is not necessary for selfevaluating constants, i.e., numbers, booleans, characters, strings, and bytevectors.
Quoted and selfevaluating constants are immutable. That is, programs should not alter a constant via setcar!
, stringset!
, etc., and implementations are permitted to raise an exception with condition type &assertion
if such an alteration is attempted. If an attempt to alter an immutable object is undetected, the behavior of the program is unspecified. An implementation may choose to share storage among different constants to save space.
(+ 2 3) ⇒ 5
'(+ 2 3) ⇒ (+ 2 3)
(quote (+ 2 3)) ⇒ (+ 2 3)
'a ⇒ a
'cons ⇒ cons
'() ⇒ ()
'7 ⇒ 7
syntax 

syntax 

syntax 

syntax 

syntax 

syntax 

returns 
see below 
libraries 

`obj
is equivalent to (quasiquote obj)
, ,obj
is equivalent to (unquote obj)
, and ,@obj
is equivalent to (unquotesplicing obj)
. The abbreviated forms are converted into the longer forms by the Scheme reader (see read
).
quasiquote
is similar to quote
, but it allows parts of the quoted text to be "unquoted." Within a quasiquote
expression, unquote
and unquotesplicing
subforms are evaluated, and everything else is quoted, i.e., left unevaluated. The value of each unquote
subform is inserted into the output in place of the unquote
form, while the value of each unquotesplicing
subform is spliced into the surrounding list or vector structure. unquote
and unquotesplicing
are valid only within quasiquote
expressions.
quasiquote
expressions may be nested, with each quasiquote
introducing a new level of quotation and each unquote
or unquotesplicing
taking away a level of quotation. An expression nested within n quasiquote
expressions must be within n unquote
or unquotesplicing
expressions to be evaluated.
`(+ 2 3) ⇒ (+ 2 3)
`(+ 2 ,(* 3 4)) ⇒ (+ 2 12)
`(a b (,(+ 2 3) c) d) ⇒ (a b (5 c) d)
`(a b ,(reverse '(c d e)) f g) ⇒ (a b (e d c) f g)
(let ([a 1] [b 2])
`(,a . ,b)) ⇒ (1 . 2)
`(+ ,@(cdr '(* 2 3))) ⇒ (+ 2 3)
`(a b ,@(reverse '(c d e)) f g) ⇒ (a b e d c f g)
(let ([a 1] [b 2])
`(,a ,@b)) ⇒ (1 . 2)
`#(,@(list 1 2 3)) ⇒ #(1 2 3)
'`,(cons 'a 'b) ⇒ `,(cons 'a 'b)
`',(cons 'a 'b) ⇒ '(a . b)
unquote
and unquotesplicing
forms with zero or more than one subform are valid only in splicing (list or vector) contexts. (unquote obj ...)
is equivalent to (unquote obj) ...
, and (unquotesplicing obj ...)
is equivalent to (unquotesplicing obj) ...
. These forms are primarily useful as intermediate forms in the output of the quasiquote
expander. They support certain useful nested quasiquotation idioms [3], such as ,@,@
, which has the effect of a doubly indirect splicing when used within a doubly nested and doubly evaluated quasiquote
expression.
`(a (unquote) b) ⇒ (a b)
`(a (unquote (+ 3 3)) b) ⇒ (a 6 b)
`(a (unquote (+ 3 3) (* 3 3)) b) ⇒ (a 6 9 b)
(let ([x '(m n)]) ``(a ,@,@x f)) ⇒ `(a (unquotesplicing m n) f)
(let ([x '(m n)])
(eval `(let ([m '(b c)] [n '(d e)]) `(a ,@,@x f))
(environment '(rnrs)))) ⇒ (a b c d e f)
unquote
and unquotesplicing
are auxiliary keywords for quasiquote
. It is a syntax violation to reference these identifiers except in contexts where they are recognized as auxiliary keywords.
Section 6.2. Generic Equivalence and Type Predicates
This section describes the basic Scheme predicates (procedures returning one of the boolean values #t
or #f
) for determining the type of an object or the equivalence of two objects. The equivalence predicates eq?
, eqv?
, and equal?
are discussed first, followed by the type predicates.
procedure 

returns 

libraries 

In most Scheme systems, two objects are considered identical if they are represented internally by the same pointer value and distinct (not identical) if they are represented internally by different pointer values, although other criteria, such as timestamping, are possible.
Although the particular rules for object identity vary somewhat from system to system, the following rules always hold.

Two objects of different types (booleans, the empty list, pairs, numbers, characters, strings, vectors, symbols, and procedures) are distinct.

Two objects of the same type with different contents or values are distinct.

The boolean object
#t
is identical to itself wherever it appears, and#f
is identical to itself wherever it appears, but#t
and#f
are distinct. 
The empty list
()
is identical to itself wherever it appears. 
Two symbols are identical if and only if they have the same name (by
string=?
). 
A constant pair, vector, string, or bytevector is identical to itself, as is a pair, vector, string, or bytevector created by an application of
cons
,vector
,string
,makebytevector
, etc. Two pairs, vectors, strings, or bytevectors created by different applications ofcons
,vector
,string
,makebytevector
, etc., are distinct. One consequence is thatcons
, for example, may be used to create a unique object distinct from all other objects. 
Two procedures that may behave differently are distinct. A procedure created by an evaluation of a
lambda
expression is identical to itself. Two procedures created by the samelambda
expression at different times, or by similarlambda
expressions, may or may not be distinct.
eq?
cannot be used to compare numbers and characters reliably. Although every inexact number is distinct from every exact number, two exact numbers, two inexact numbers, or two characters with the same value may or may not be identical.
Since constant objects are immutable, i.e., programs should not modify them via vectorset!
, setcar!
, or any other structure mutation operation, all or portions of different quoted constants or selfevaluating literals may be represented internally by the same object. Thus, eq?
may return #t
when applied to equal parts of different immutable constants.
eq?
is most often used to compare symbols or to check for pointer equivalence of allocated objects, e.g., pairs, vectors, or record instances.
(eq? 'a 3) ⇒ #f
(eq? #t 't) ⇒ #f
(eq? "abc" 'abc) ⇒ #f
(eq? "hi" '(hi)) ⇒ #f
(eq? #f '()) ⇒ #f
(eq? 9/2 7/2) ⇒ #f
(eq? 3.4 53344) ⇒ #f
(eq? 3 3.0) ⇒ #f
(eq? 1/3 #i1/3) ⇒ #f
(eq? 9/2 9/2) ⇒ unspecified
(eq? 3.4 (+ 3.0 .4)) ⇒ unspecified
(let ([x (* 12345678987654321 2)])
(eq? x x)) ⇒ unspecified
(eq? #\a #\b) ⇒ #f
(eq? #\a #\a) ⇒ unspecified
(let ([x (stringref "hi" 0)])
(eq? x x)) ⇒ unspecified
(eq? #t #t) ⇒ #t
(eq? #f #f) ⇒ #t
(eq? #t #f) ⇒ #f
(eq? (null? '()) #t) ⇒ #t
(eq? (null? '(a)) #f) ⇒ #t
(eq? (cdr '(a)) '()) ⇒ #t
(eq? 'a 'a) ⇒ #t
(eq? 'a 'b) ⇒ #f
(eq? 'a (string>symbol "a")) ⇒ #t
(eq? '(a) '(b)) ⇒ #f
(eq? '(a) '(a)) ⇒ unspecified
(let ([x '(a . b)]) (eq? x x)) ⇒ #t
(let ([x (cons 'a 'b)])
(eq? x x)) ⇒ #t
(eq? (cons 'a 'b) (cons 'a 'b)) ⇒ #f
(eq? "abc" "cba") ⇒ #f
(eq? "abc" "abc") ⇒ unspecified
(let ([x "hi"]) (eq? x x)) ⇒ #t
(let ([x (string #\h #\i)]) (eq? x x)) ⇒ #t
(eq? (string #\h #\i)
(string #\h #\i)) ⇒ #f
(eq? '#vu8(1) '#vu8(1)) ⇒ unspecified
(eq? '#vu8(1) '#vu8(2)) ⇒ #f
(let ([x (makebytevector 10 0)])
(eq? x x)) ⇒ #t
(let ([x (makebytevector 10 0)])
(eq? x (makebytevector 10 0))) ⇒ #f
(eq? '#(a) '#(b)) ⇒ #f
(eq? '#(a) '#(a)) ⇒ unspecified
(let ([x '#(a)]) (eq? x x)) ⇒ #t
(let ([x (vector 'a)])
(eq? x x)) ⇒ #t
(eq? (vector 'a) (vector 'a)) ⇒ #f
(eq? car car) ⇒ #t
(eq? car cdr) ⇒ #f
(let ([f (lambda (x) x)])
(eq? f f)) ⇒ #t
(let ([f (lambda () (lambda (x) x))])
(eq? (f) (f))) ⇒ unspecified
(eq? (lambda (x) x) (lambda (y) y)) ⇒ unspecified
(let ([f (lambda (x)
(lambda ()
(set! x (+ x 1))
x))])
(eq? (f 0) (f 0))) ⇒ #f
procedure 

returns 

libraries 

eqv?
is similar to eq?
except eqv?
is guaranteed to return #t
for two characters that are considered equal by char=?
and two numbers that are (a) considered equal by =
and (b) cannot be distinguished by any other operation besides eq?
and eqv?
. A consequence of (b) is that (eqv? 0.0 +0.0)
is #f
even though (= 0.0 +0.0)
is #t
in systems that distinguish 0.0
and +0.0
, such as those based on IEEE floatingpoint arithmetic. This is because operations such as /
can expose the difference:
(/ 1.0 0.0) ⇒ inf.0
(/ 1.0 +0.0) ⇒ +inf.0
Similarly, although 3.0 and 3.0+0.0i are considered numerically equal, they are not considered equivalent by eqv?
if 0.0 and 0.0 have different representations.
(= 3.0+0.0i 3.0) ⇒ #t
(eqv? 3.0+0.0i 3.0) ⇒ #f
The boolean value returned by eqv?
is not specified when the arguments are NaNs.
(eqv? +nan.0 (/ 0.0 0.0)) ⇒ unspecified
eqv?
is less implementationdependent but generally more expensive than eq?
.
(eqv? 'a 3) ⇒ #f
(eqv? #t 't) ⇒ #f
(eqv? "abc" 'abc) ⇒ #f
(eqv? "hi" '(hi)) ⇒ #f
(eqv? #f '()) ⇒ #f
(eqv? 9/2 7/2) ⇒ #f
(eqv? 3.4 53344) ⇒ #f
(eqv? 3 3.0) ⇒ #f
(eqv? 1/3 #i1/3) ⇒ #f
(eqv? 9/2 9/2) ⇒ #t
(eqv? 3.4 (+ 3.0 .4)) ⇒ #t
(let ([x (* 12345678987654321 2)])
(eqv? x x)) ⇒ #t
(eqv? #\a #\b) ⇒ #f
(eqv? #\a #\a) ⇒ #t
(let ([x (stringref "hi" 0)])
(eqv? x x)) ⇒ #t
(eqv? #t #t) ⇒ #t
(eqv? #f #f) ⇒ #t
(eqv? #t #f) ⇒ #f
(eqv? (null? '()) #t) ⇒ #t
(eqv? (null? '(a)) #f) ⇒ #t
(eqv? (cdr '(a)) '()) ⇒ #t
(eqv? 'a 'a) ⇒ #t
(eqv? 'a 'b) ⇒ #f
(eqv? 'a (string>symbol "a")) ⇒ #t
(eqv? '(a) '(b)) ⇒ #f
(eqv? '(a) '(a)) ⇒ unspecified
(let ([x '(a . b)]) (eqv? x x)) ⇒ #t
(let ([x (cons 'a 'b)])
(eqv? x x)) ⇒ #t
(eqv? (cons 'a 'b) (cons 'a 'b)) ⇒ #f
(eqv? "abc" "cba") ⇒ #f
(eqv? "abc" "abc") ⇒ unspecified
(let ([x "hi"]) (eqv? x x)) ⇒ #t
(let ([x (string #\h #\i)]) (eqv? x x)) ⇒ #t
(eqv? (string #\h #\i)
(string #\h #\i)) ⇒ #f
(eqv? '#vu8(1) '#vu8(1)) ⇒ unspecified
(eqv? '#vu8(1) '#vu8(2)) ⇒ #f
(let ([x (makebytevector 10 0)])
(eqv? x x)) ⇒ #t
(let ([x (makebytevector 10 0)])
(eqv? x (makebytevector 10 0))) ⇒ #f
(eqv? '#(a) '#(b)) ⇒ #f
(eqv? '#(a) '#(a)) ⇒ unspecified
(let ([x '#(a)]) (eqv? x x)) ⇒ #t
(let ([x (vector 'a)])
(eqv? x x)) ⇒ #t
(eqv? (vector 'a) (vector 'a)) ⇒ #f
(eqv? car car) ⇒ #t
(eqv? car cdr) ⇒ #f
(let ([f (lambda (x) x)])
(eqv? f f)) ⇒ #t
(let ([f (lambda () (lambda (x) x))])
(eqv? (f) (f))) ⇒ unspecified
(eqv? (lambda (x) x) (lambda (y) y)) ⇒ unspecified
(let ([f (lambda (x)
(lambda ()
(set! x (+ x 1))
x))])
(eqv? (f 0) (f 0))) ⇒ #f
procedure 

returns 

libraries 

Two objects are equal if they are equivalent according to eqv?
, strings that are string=?
, bytevectors that are bytevector=?
, pairs whose cars and cdrs are equal, or vectors of the same length whose corresponding elements are equal.
equal?
is required to terminate even for cyclic arguments and return #t
"if and only if the (possibly infinite) unfoldings of its arguments into regular trees are equal as ordered trees" [24]. In essence, two values are equivalent, in the sense of equal?
, if the structure of the two objects cannot be distinguished by any composition of pair and vector accessors along with the eqv?
, string=?
, and bytevector=?
procedures for comparing data at the leaves.
Implementing equal?
efficiently is tricky [1], and even with a good implementation, it is likely to be more expensive than either eqv?
or eq?
.
(equal? 'a 3) ⇒ #f
(equal? #t 't) ⇒ #f
(equal? "abc" 'abc) ⇒ #f
(equal? "hi" '(hi)) ⇒ #f
(equal? #f '()) ⇒ #f
(equal? 9/2 7/2) ⇒ #f
(equal? 3.4 53344) ⇒ #f
(equal? 3 3.0) ⇒ #f
(equal? 1/3 #i1/3) ⇒ #f
(equal? 9/2 9/2) ⇒ #t
(equal? 3.4 (+ 3.0 .4)) ⇒ #t
(let ([x (* 12345678987654321 2)])
(equal? x x)) ⇒ #t
(equal? #\a #\b) ⇒ #f
(equal? #\a #\a) ⇒ #t
(let ([x (stringref "hi" 0)])
(equal? x x)) ⇒ #t
(equal? #t #t) ⇒ #t
(equal? #f #f) ⇒ #t
(equal? #t #f) ⇒ #f
(equal? (null? '()) #t) ⇒ #t
(equal? (null? '(a)) #f) ⇒ #t
(equal? (cdr '(a)) '()) ⇒ #t
(equal? 'a 'a) ⇒ #t
(equal? 'a 'b) ⇒ #f
(equal? 'a (string>symbol "a")) ⇒ #t
(equal? '(a) '(b)) ⇒ #f
(equal? '(a) '(a)) ⇒ #t
(let ([x '(a . b)]) (equal? x x)) ⇒ #t
(let ([x (cons 'a 'b)])
(equal? x x)) ⇒ #t
(equal? (cons 'a 'b) (cons 'a 'b)) ⇒ #t
(equal? "abc" "cba") ⇒ #f
(equal? "abc" "abc") ⇒ #t
(let ([x "hi"]) (equal? x x)) ⇒ #t
(let ([x (string #\h #\i)]) (equal? x x)) ⇒ #t
(equal? (string #\h #\i)
(string #\h #\i)) ⇒ #t
(equal? '#vu8(1) '#vu8(1)) ⇒ #t
(equal? '#vu8(1) '#vu8(2)) ⇒ #f
(let ([x (makebytevector 10 0)])
(equal? x x)) ⇒ #t
(let ([x (makebytevector 10 0)])
(equal? x (makebytevector 10 0))) ⇒ #t
(equal? '#(a) '#(b)) ⇒ #f
(equal? '#(a) '#(a)) ⇒ #t
(let ([x '#(a)]) (equal? x x)) ⇒ #t
(let ([x (vector 'a)])
(equal? x x)) ⇒ #t
(equal? (vector 'a) (vector 'a)) ⇒ #t
(equal? car car) ⇒ #t
(equal? car cdr) ⇒ #f
(let ([f (lambda (x) x)])
(equal? f f)) ⇒ #t
(let ([f (lambda () (lambda (x) x))])
(equal? (f) (f))) ⇒ unspecified
(equal? (lambda (x) x) (lambda (y) y)) ⇒ unspecified
(let ([f (lambda (x)
(lambda ()
(set! x (+ x 1))
x))])
(equal? (f 0) (f 0))) ⇒ #f
(equal?
(let ([x (cons 'x 'x)])
(setcar! x x)
(setcdr! x x)
x)
(let ([x (cons 'x 'x)])
(setcar! x x)
(setcdr! x x)
(cons x x))) ⇒ #t
procedure 

returns 

libraries 

boolean?
is equivalent to (lambda (x) (or (eq? x #t) (eq? x #f)))
.
(boolean? #t) ⇒ #t
(boolean? #f) ⇒ #t
(or (boolean? 't) (boolean? '())) ⇒ #f
procedure 

returns 

libraries 

null?
is equivalent to (lambda (x) (eq? x '()))
.
(null? '()) ⇒ #t
(null? '(a)) ⇒ #f
(null? (cdr '(a))) ⇒ #t
(null? 3) ⇒ #f
(null? #f) ⇒ #f
procedure 

returns 

libraries 

(pair? '(a b c)) ⇒ #t
(pair? '(3 . 4)) ⇒ #t
(pair? '()) ⇒ #f
(pair? '#(a b)) ⇒ #f
(pair? 3) ⇒ #f
procedure 

returns 

procedure 

returns 

procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

These predicates form a hierarchy: any integer is rational, any rational is real, any real is complex, and any complex is numeric. Most implementations do not provide internal representations for irrational numbers, so all real numbers are typically rational as well.
The real?
, rational?
, and integer?
predicates do not recognize as real, rational, or integer complex numbers with inexact zero imaginary parts.
(integer? 1901) ⇒ #t
(rational? 1901) ⇒ #t
(real? 1901) ⇒ #t
(complex? 1901) ⇒ #t
(number? 1901) ⇒ #t
(integer? 3.0) ⇒ #t
(rational? 3.0) ⇒ #t
(real? 3.0) ⇒ #t
(complex? 3.0) ⇒ #t
(number? 3.0) ⇒ #t
(integer? 7+0i) ⇒ #t
(rational? 7+0i) ⇒ #t
(real? 7+0i) ⇒ #t
(complex? 7+0i) ⇒ #t
(number? 7+0i) ⇒ #t
(integer? 2/3) ⇒ #f
(rational? 2/3) ⇒ #t
(real? 2/3) ⇒ #t
(complex? 2/3) ⇒ #t
(number? 2/3) ⇒ #t
(integer? 2.345) ⇒ #f
(rational? 2.345) ⇒ #t
(real? 2.345) ⇒ #t
(complex? 2.345) ⇒ #t
(number? 2.345) ⇒ #t
(integer? 7.0+0.0i) ⇒ #f
(rational? 7.0+0.0i) ⇒ #f
(real? 7.0+0.0i) ⇒ #f
(complex? 7.0+0.0i) ⇒ #t
(number? 7.0+0.0i) ⇒ #t
(integer? 3.22.01i) ⇒ #f
(rational? 3.22.01i) ⇒ #f
(real? 3.22.01i) ⇒ #f
(complex? 3.22.01i) ⇒ #t
(number? 3.22.01i) ⇒ #t
(integer? 'a) ⇒ #f
(rational? '(a b c)) ⇒ #f
(real? "3") ⇒ #f
(complex? '#(1 2)) ⇒ #f
(number? #\a) ⇒ #f
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

These predicates are similar to real?
, rational?
, and integer?
, but treat as real, rational, or integral complex numbers with inexact zero imaginary parts.
(integervalued? 1901) ⇒ #t
(rationalvalued? 1901) ⇒ #t
(realvalued? 1901) ⇒ #t
(integervalued? 3.0) ⇒ #t
(rationalvalued? 3.0) ⇒ #t
(realvalued? 3.0) ⇒ #t
(integervalued? 7+0i) ⇒ #t
(rationalvalued? 7+0i) ⇒ #t
(realvalued? 7+0i) ⇒ #t
(integervalued? 2/3) ⇒ #f
(rationalvalued? 2/3) ⇒ #t
(realvalued? 2/3) ⇒ #t
(integervalued? 2.345) ⇒ #f
(rationalvalued? 2.345) ⇒ #t
(realvalued? 2.345) ⇒ #t
(integervalued? 7.0+0.0i) ⇒ #t
(rationalvalued? 7.0+0.0i) ⇒ #t
(realvalued? 7.0+0.0i) ⇒ #t
(integervalued? 3.22.01i) ⇒ #f
(rationalvalued? 3.22.01i) ⇒ #f
(realvalued? 3.22.01i) ⇒ #f
As with real?
, rational?
, and integer?
, these predicates return #f
for all nonnumeric values.
(integervalued? 'a) ⇒ #f
(rationalvalued? '(a b c)) ⇒ #f
(realvalued? "3") ⇒ #f
procedure 

returns 

libraries 

(char? 'a) ⇒ #f
(char? 97) ⇒ #f
(char? #\a) ⇒ #t
(char? "a") ⇒ #f
(char? (stringref (makestring 1) 0)) ⇒ #t
procedure 

returns 

libraries 

(string? "hi") ⇒ #t
(string? 'hi) ⇒ #f
(string? #\h) ⇒ #f
procedure 

returns 

libraries 

(vector? '#()) ⇒ #t
(vector? '#(a b c)) ⇒ #t
(vector? (vector 'a 'b 'c)) ⇒ #t
(vector? '()) ⇒ #f
(vector? '(a b c)) ⇒ #f
(vector? "abc") ⇒ #f
procedure 

returns 

libraries 

(symbol? 't) ⇒ #t
(symbol? "t") ⇒ #f
(symbol? '(t)) ⇒ #f
(symbol? #\t) ⇒ #f
(symbol? 3) ⇒ #f
(symbol? #t) ⇒ #f
procedure 

returns 

libraries 

(procedure? car) ⇒ #t
(procedure? 'car) ⇒ #f
(procedure? (lambda (x) x)) ⇒ #t
(procedure? '(lambda (x) x)) ⇒ #f
(call/cc procedure?) ⇒ #t
procedure 

returns 

libraries 

(bytevector? #vu8()) ⇒ #t
(bytevector? '#()) ⇒ #f
(bytevector? "abc") ⇒ #f
procedure 

returns 

libraries 

(hashtable? (makeeqhashtable)) ⇒ #t
(hashtable? '(not a hash table)) ⇒ #f
Section 6.3. Lists and Pairs
The pair, or cons cell, is the most fundamental of Scheme’s structured object types. The most common use for pairs is to build lists, which are ordered sequences of pairs linked one to the next by the cdr field. The elements of the list occupy the car fields of the pairs. The cdr of the last pair in a proper list is the empty list, ()
; the cdr of the last pair in an improper list can be anything other than ()
.
Pairs may be used to construct binary trees. Each pair in the tree structure is an internal node of the binary tree; its car and cdr are the children of the node.
Proper lists are printed as sequences of objects separated by whitespace and enclosed in parentheses. Matching pairs of brackets ( [
]
) may be used in place of parentheses. For example, (1 2 3)
and (a [nested list])
are proper lists. The empty list is written as ()
.
Improper lists and trees require a slightly more complex syntax. A single pair is written as two objects separated by whitespace and a dot, e.g., (a . b)
. This is referred to as dottedpair notation. Improper lists and trees are also written in dottedpair notation; the dot appears wherever necessary, e.g., (1 2 3 . 4)
or 1 . 2) . 3)
. Proper lists may be written in dottedpair notation as well. For example, (1 2 3)
may be written as (1 . (2 . (3 . ())
.
It is possible to create a circular list or a cyclic graph by destructively altering the car or cdr field of a pair, using setcar!
or setcdr!
. Such lists are not considered proper lists.
Procedures that accept a list
argument are required to detect that the list is improper only to the extent that they actually traverse the list far enough either (a) to attempt to operate on a nonlist tail or (b) to loop indefinitely due to a circularity. For example, member
need not detect that a list is improper if it actually finds the element being sought, and listref
need never detect circularities, because its recursion is bounded by the index argument.
procedure 

returns 
a new pair whose car and cdr are 
libraries 

cons
is the pair constructor procedure. obj_{1}
becomes the car and obj_{2}
becomes the cdr of the new pair.
(cons 'a '()) ⇒ (a)
(cons 'a '(b c)) ⇒ (a b c)
(cons 3 4) ⇒ (3 . 4)
procedure 

returns 
the car of 
libraries 

The empty list is not a pair, so the argument must not be the empty list.
(car '(a)) ⇒ a
(car '(a b c)) ⇒ a
(car (cons 3 4)) ⇒ 3
procedure 

returns 
the cdr of 
libraries 

The empty list is not a pair, so the argument must not be the empty list.
(cdr '(a)) ⇒ ()
(cdr '(a b c)) ⇒ (b c)
(cdr (cons 3 4)) ⇒ 4
procedure 

returns 
unspecified 
libraries 

setcar!
changes the car of pair
to obj
.
(let ([x (list 'a 'b 'c)])
(setcar! x 1)
x) ⇒ (1 b c)
procedure 

returns 
unspecified 
libraries 

setcdr!
changes the cdr of pair
to obj
.
(let ([x (list 'a 'b 'c)])
(setcdr! x 1)
x) ⇒ (a . 1)
procedure 

procedure 

procedure 

returns 
the caar, cadr, ..., or cddddr of 
libraries 

These procedures are defined as the composition of up to four car
s and cdr
s. The a
's and d
's between the c
and r
represent the application of car
or cdr
in order from right to left. For example, the procedure cadr
applied to a pair yields the car
of the cdr
of the pair and is equivalent to (lambda (x) (car (cdr x)))
.
(caar '((a))) ⇒ a
(cadr '(a b c)) ⇒ b
(cdddr '(a b c d)) ⇒ (d)
(cadadr '(a (b c))) ⇒ c
procedure 

returns 
a list of 
libraries 

list
is equivalent to (lambda x x)
.
(list) ⇒ ()
(list 1 2 3) ⇒ (1 2 3)
(list 3 2 1) ⇒ (3 2 1)
procedure 

returns 
a list of 
libraries 

If the objects obj ...
are omitted, the result is simply finalobj
. Otherwise, a list of obj ...
is constructed, as with list
, except that the final cdr field is finalobj
instead of ()
. If finalobj
is not a list, the result is an improper list.
(cons* '()) ⇒ ()
(cons* '(a b)) ⇒ (a b)
(cons* 'a 'b 'c) ⇒ (a b . c)
(cons* 'a 'b '(c d)) ⇒ (a b c d)
procedure 

returns 

libraries 

list?
must return #f
for all improper lists, including cyclic lists. A definition of list?
is shown on page 67.
(list? '()) ⇒ #t
(list? '(a b c)) ⇒ #t
(list? 'a) ⇒ #f
(list? '(3 . 4)) ⇒ #f
(list? 3) ⇒ #f
(let ([x (list 'a 'b 'c)])
(setcdr! (cddr x) x)
(list? x)) ⇒ #f
procedure 

returns 
the number of elements in 
libraries 

length
may be defined as follows, using an adaptation of the hare and tortoise algorithm used for the definition of list?
on page 67.
(define length
(lambda (x)
(define improperlist
(lambda ()
(assertionviolation 'length "not a proper list" x)))
(let f ([h x] [t x] [n 0])
(if (pair? h)
(let ([h (cdr h)])
(if (pair? h)
(if (eq? h t)
(improperlist)
(f (cdr h) (cdr t) (+ n 2)))
(if (null? h)
(+ n 1)
(improperlist))))
(if (null? h)
n
(improperlist))))))
(length '()) ⇒ 0
(length '(a b c)) ⇒ 3
(length '(a b . c)) ⇒ exception
(length
(let ([ls (list 'a 'b)])
(setcdr! (cdr ls) ls) ⇒ exception
ls))
(length
(let ([ls (list 'a 'b)])
(setcar! (cdr ls) ls) ⇒ 2
ls))
procedure 

returns 
the 
libraries 

n
must be an exact nonnegative integer less than the length of list
. listref
may be defined without error checks as follows.
(define listref
(lambda (ls n)
(if (= n 0)
(car ls)
(listref (cdr ls) ( n 1)))))
(listref '(a b c) 0) ⇒ a
(listref '(a b c) 1) ⇒ b
(listref '(a b c) 2) ⇒ c
procedure 

returns 
the 
libraries 

n
must be an exact nonnegative integer less than or equal to the length of list
. The result is not a copy; the tail is eq?
to the n
th cdr of list
(or to list
itself, if n
is zero).
listtail
may be defined without error checks as follows.
(define listtail
(lambda (ls n)
(if (= n 0)
ls
(listtail (cdr ls) ( n 1)))))
(listtail '(a b c) 0) ⇒ (a b c)
(listtail '(a b c) 2) ⇒ (c)
(listtail '(a b c) 3) ⇒ ()
(listtail '(a b c . d) 2) ⇒ (c . d)
(listtail '(a b c . d) 3) ⇒ d
(let ([x (list 1 2 3)])
(eq? (listtail x 2)
(cddr x))) ⇒ #t
procedure 

procedure 

returns 
the concatenation of the input lists 
libraries 

append
returns a new list consisting of the elements of the first list followed by the elements of the second list, the elements of the third list, and so on. The new list is made from new pairs for all arguments but the last; the last (which need not be a list) is merely placed at the end of the new structure. append
may be defined without error checks as follows.
(define append
(lambda args
(let f ([ls '()] [args args])
(if (null? args)
ls
(let g ([ls ls])
(if (null? ls)
(f (car args) (cdr args))
(cons (car ls) (g (cdr ls)))))))))
(append '(a b c) '()) ⇒ (a b c)
(append '() '(a b c)) ⇒ (a b c)
(append '(a b) '(c d)) ⇒ (a b c d)
(append '(a b) 'c) ⇒ (a b . c)
(let ([x (list 'b)])
(eq? x (cdr (append '(a) x)))) ⇒ #t
procedure 

returns 
a new list containing the elements of 
libraries 

reverse
may be defined without error checks as follows.
(define reverse
(lambda (ls)
(let rev ([ls ls] [new '()])
(if (null? ls)
new
(rev (cdr ls) (cons (car ls) new))))))
(reverse '()) ⇒ ()
(reverse '(a b c)) ⇒ (c b a)
procedure 

procedure 

procedure 

returns 
the first tail of 
libraries 

These procedures traverse the argument list
in order, comparing the elements of list
against obj
. If an object equivalent to obj
is found, the tail of the list whose first element is that object is returned. If the list contains more than one object equivalent to obj
, the first tail whose first element is equivalent to obj
is returned. If no object equivalent to obj
is found, #f
is returned. The equivalence test for memq
is eq?
, for memv
is eqv?
, and for member
is equal?
.
These procedures are most often used as predicates, but their names do not end with a question mark because they return a useful true value in place of #t
. memq
may be defined without error checks as follows.
(define memq
(lambda (x ls)
(cond
[(null? ls) #f]
[(eq? (car ls) x) ls]
[else (memq x (cdr ls))])))
memv
and member
may be defined similarly, with eqv?
and equal?
in place of eq?
.
(memq 'a '(b c a d e)) ⇒ (a d e)
(memq 'a '(b c d e g)) ⇒ #f
(memq 'a '(b a c a d a)) ⇒ (a c a d a)
(memv 3.4 '(1.2 2.3 3.4 4.5)) ⇒ (3.4 4.5)
(memv 3.4 '(1.3 2.5 3.7 4.9)) ⇒ #f
(let ([ls (list 'a 'b 'c)])
(setcar! (memv 'b ls) 'z)
ls) ⇒ (a z c)
(member '(b) '((a) (b) (c))) ⇒ ((b) (c))
(member '(d) '((a) (b) (c))) ⇒ #f
(member "b" '("a" "b" "c")) ⇒ ("b" "c")
(let ()
(define member?
(lambda (x ls)
(and (member x ls) #t)))
(member? '(b) '((a) (b) (c)))) ⇒ #t
(define countoccurrences
(lambda (x ls)
(cond
[(memq x ls) =>
(lambda (ls)
(+ (countoccurrences x (cdr ls)) 1))]
[else 0])))
(countoccurrences 'a '(a b c d a)) ⇒ 2
procedure 

returns 
the first tail of 
libraries 

procedure
should accept one argument and return a single value. It should not modify list
.
(memp odd? '(1 2 3 4)) ⇒ (1 2 3 4)
(memp even? '(1 2 3 4)) ⇒ (2 3 4)
(let ([ls (list 1 2 3 4)])
(eq? (memp odd? ls) ls)) ⇒ #t
(let ([ls (list 1 2 3 4)])
(eq? (memp even? ls) (cdr ls))) ⇒ #t
(memp odd? '(2 4 6 8)) ⇒ #f
procedure 

procedure 

procedure 

returns 
a list containing the elements of 
libraries 

These procedures traverse the argument list
, removing any objects that are equivalent to obj
. The elements remaining in the output list are in the same order as they appear in the input list. If a tail of list
(including list
itself) contains no occurrences of obj
, the corresponding tail of the result list may be the same (by eq?
) as the tail of the input list.
The equivalence test for remq
is eq?
, for remv
is eqv?
, and for remove
is equal?
.
(remq 'a '(a b a c a d)) ⇒ (b c d)
(remq 'a '(b c d)) ⇒ (b c d)
(remv 1/2 '(1.2 1/2 0.5 3/2 4)) ⇒ (1.2 0.5 3/2 4)
(remove '(b) '((a) (b) (c))) ⇒ ((a) (c))
procedure 

returns 
a list of the elements of 
libraries 

procedure
should accept one argument and return a single value. It should not modify list
.
remp
applies procedure
to each element of list
and returns a list containing only the elements for which procedure
returns #f
. The elements of the returned list appear in the same order as they appeared in the original list.
(remp odd? '(1 2 3 4)) ⇒ (2 4)
(remp
(lambda (x) (and (> x 0) (< x 10)))
'(5 15 3 14 20 6 0 9)) ⇒ (5 15 14 20 0 9)
procedure 

returns 
a list of the elements of 
libraries 

procedure
should accept one argument and return a single value. It should not modify list
.
filter
applies procedure
to each element of list
and returns a new list containing only the elements for which procedure
returns true. The elements of the returned list appear in the same order as they appeared in the original list.
(filter odd? '(1 2 3 4)) ⇒ (1 3)
(filter
(lambda (x) (and (> x 0) (< x 10)))
'(5 15 3 14 20 6 0 9)) ⇒ (3 6)
procedure 

returns 
see below 
libraries 

procedure
should accept one argument and return a single value. It should not modify list
.
partition
applies procedure
to each element of list
and returns two values: a new list containing only the elements for which procedure
returns true, and a new list containing only the elements for which procedure
returns #f
. The elements of the returned lists appear in the same order as they appeared in the original list.
(partition odd? '(1 2 3 4)) ⇒ (1 3)
(2 4)
(partition
(lambda (x) (and (> x 0) (< x 10)))
'(5 15 3 14 20 6 0 9)) ⇒ (3 6)
(5 15 14 20 0 9)
The values returned by partition
can be obtained by calling filter
and remp
separately, but this would require two calls to procedure
for each element of list
.
procedure 

returns 
the first element of 
libraries 

procedure
should accept one argument and return a single value. It should not modify list
.
find
traverses the argument list
in order, applying procedure
to each element in turn. If procedure
returns a true value for a given element, find
returns that element without applying procedure
to the remaining elements. If procedure
returns #f
for each element of list
, find
returns #f
.
If a program must distinguish between finding #f
in the list and finding no element at all, memp
should be used instead.
(find odd? '(1 2 3 4)) ⇒ 1
(find even? '(1 2 3 4)) ⇒ 2
(find odd? '(2 4 6 8)) ⇒ #f
(find not '(1 a #f 55)) ⇒ #f
procedure  
procedure 

procedure 

returns 
first element of 
libraries 

The argument alist
must be an association list. An association list is a proper list whose elements are keyvalue pairs of the form (key . value)
. Associations are useful for storing information (values) associated with certain objects (keys).
These procedures traverse the association list, testing each key for equivalence with obj
. If an equivalent key is found, the keyvalue pair is returned. Otherwise, #f
is returned.
The equivalence test for assq
is eq?
, for assv
is eqv?
, and for assoc
is equal?
. assq
may be defined without error checks as follows.
(define assq
(lambda (x ls)
(cond
[(null? ls) #f]
[(eq? (caar ls) x) (car ls)]
[else (assq x (cdr ls))])))
assv
and assoc
may be defined similarly, with eqv?
and equal?
in place of eq?
.
(assq 'b '((a . 1) (b . 2))) ⇒ (b . 2)
(cdr (assq 'b '((a . 1) (b . 2)))) ⇒ 2
(assq 'c '((a . 1) (b . 2))) ⇒ #f
(assv 2/3 '((1/3 . 1) (2/3 . 2))) ⇒ (2/3 . 2)
(assv 2/3 '((1/3 . a) (3/4 . b))) ⇒ #f
(assoc '(a) '(((a) . a) (1 . b))) ⇒ ((a) . a)
(assoc '(a) '(((b) . b) (a . c))) ⇒ #f
(let ([alist (list (cons 2 'a) (cons 3 'b))])
(setcdr! (assv 3 alist) 'c)
alist) ⇒ ((2 . a) (3 . c))
The interpreter given in Section 12.7 represents environments as association lists and uses assq
for both variable lookup and assignment.
procedure 

returns 
first element of 
libraries 

alist
must be an association list. An association list is a proper list whose elements are keyvalue pairs of the form (key . value)
. procedure
should accept one argument and return a single value. It should not modify list
.
(assp odd? '((1 . a) (2 . b))) ⇒ (1 . a)
(assp even? '((1 . a) (2 . b))) ⇒ (2 . b)
(let ([ls (list (cons 1 'a) (cons 2 'b))])
(eq? (assp odd? ls) (car ls))) ⇒ #t
(let ([ls (list (cons 1 'a) (cons 2 'b))])
(eq? (assp even? ls) (cadr ls))) ⇒ #t
(assp odd? '((2 . b))) ⇒ #f
procedure 

returns 
a list containing the elements of 
libraries 

predicate
should be a procedure that expects two arguments and returns #t
if its first argument must precede its second in the sorted list. That is, if predicate
is applied to two elements x
and y
, where x
appears after y
in the input list, it should return true only if x
should appear before y
in the output list. If this constraint is met, listsort
performs a stable sort, i.e., two elements are reordered only when necessary according to predicate
. Duplicate elements are not removed. This procedure may call predicate up to \(n\log{n}\) times, where \(n\) is the length of list
.
(listsort < '(3 4 2 1 2 5)) ⇒ (1 2 2 3 4 5)
(listsort > '(0.5 1/2)) ⇒ (0.5 1/2)
(listsort > '(1/2 0.5)) ⇒ (1/2 0.5)
(list>string
(listsort char>?
(string>list "hello"))) ⇒ "ollhe"
Section 6.4. Numbers
Scheme numbers may be classified as integers, rational numbers, real numbers, or complex numbers. This classification is hierarchical, in that all integers are rational, all rational numbers are real, and all real numbers are complex. The predicates integer?
, rational?
, real?
, and complex?
described in Section 6.2 are used to determine into which of these classes a number falls.
A Scheme number may also be classified as exact or inexact, depending upon the quality of operations used to derive the number and the inputs to these operations. The predicates exact?
and inexact?
may be used to determine the exactness of a number. Most operations on numbers in Scheme are exactness preserving: if given exact operands they return exact values, and if given inexact operands or a combination of exact and inexact operands they return inexact values.
Exact integer and rational arithmetic is typically supported to arbitrary precision; the size of an integer or of the denominator or numerator of a ratio is limited only by system storage constraints. Although other representations are possible, inexact numbers are typically represented by floatingpoint numbers supported by the host computer’s hardware or by system software. Complex numbers are typically represented as ordered pairs (realpart
, imagpart
), where realpart
and imagpart
are exact integers, exact rationals, or floatingpoint numbers.
Scheme numbers are written in a straightforward manner not much different from ordinary conventions for writing numbers. An exact integer is normally written as a sequence of numerals preceded by an optional sign. For example, 3
, +19
, 100000
, and 208423089237489374
all represent exact integers.
An exact rational number is normally written as two sequences of numerals separated by a slash (/
) and preceded by an optional sign. For example, 3/4
, 6/5
, and 1/1208203823
are all exact rational numbers. A ratio is reduced immediately to lowest terms when it is read and may in fact reduce to an exact integer.
Inexact real numbers are normally written in either floatingpoint or scientific notation. Floatingpoint notation consists of a sequence of numerals followed by a decimal point and another sequence of numerals, all preceded by an optional sign. Scientific notation consists of an optional sign, a sequence of numerals, an optional decimal point followed by a second string of numerals, and an exponent; an exponent is written as the letter e
followed by an optional sign and a sequence of numerals. For example, 1.0
and 200.0
are valid inexact integers, and 1.5
, 0.034
, 10e10
and 1.5e5
are valid inexact rational numbers. The exponent is the power of ten by which the number preceding the exponent should be scaled, so that 2e3
is equivalent to 2000.0
.
A mantissa width w
may appear as the suffix of a real number or the real components of a complex number written in floatingpoint or scientific notation. The mantissa width w
represents the number of significant bits in the representation of the number. The mantissa width defaults to 53, the number of significant bits in a normalized IEEE double floatingpoint number, or more. For denormalized IEEE double floatingpoint numbers, the mantissa width is less than 53. If an implementation cannot represent a number with the mantissa width specified, it uses a representation with at least as many significant bits as requested if possible, otherwise it uses its representation with the largest mantissa width.
Exact and inexact real numbers are written as exact or inexact integers or rational numbers; no provision is made in the syntax of Scheme numbers for nonrational real numbers, i.e., irrational numbers.
Complex numbers may be written in either rectangular or polar form. In rectangular form, a complex number is written as x+yi
or xyi
, where x
is an integer, rational, or real number and y
is an unsigned integer, rational, or real number. The real part, x, may be omitted, in which case it is assumed to be zero. For example, 3+4i
, 3.23/4i
, +i
, and 3e5i
are complex numbers written in rectangular form. In polar form, a complex number is written as x@y
, where x
and y
are integer, rational, or real numbers. For example, 1.1@1.764
and 1@1/2
are complex numbers written in polar form.
The syntaxes +inf.0
and inf.0
represent inexact real numbers that represent positive and negative infinity. The syntaxes +nan.0
and nan.0
represent an inexact "notanumber" (NaN) value. Infinities may be produced by dividing inexact positive and negative values by inexact zero, and NaNs may also be produced by dividing inexact zero by inexact zero, among other ways.
The exactness of a numeric representation may be overridden by preceding the representation by either #e
or #i
. #e
forces the number to be exact, and #i
forces it to be inexact. For example, 1
, #e1
, 1/1, #e1/1
, #e1.0
, and #e1e0
all represent the exact integer 1, and #i3/10
, 0.3
, #i0.3
, and 3e1
all represent the inexact rational 0.3.
Numbers are written by default in base 10, although the special prefixes #b
(binary), #o
(octal), #d
(decimal), and #x
(hexadecimal) can be used to specify base 2, base 8, base 10, or base 16. For radix 16, the letters a
through f
or A
through F
serve as the additional numerals required to express digit values 10 through 15. For example, #b10101
is the binary equivalent of 21_{10}, #o72
is the octal equivalent of 58_{10}, and #xC7
is the hexadecimal equivalent of 199_{10}. Numbers written in floatingpoint and scientific notations are always written in base 10.
If both are present, radix and exactness prefixes may appear in either order.
A Scheme implementation may support more than one size of internal representation for inexact quantities. The exponent markers s
(short), f
(single), d
(double), and l
(long) may appear in place of the default exponent marker e
to override the default size for numbers written in scientific notation. In implementations that support multiple representations, the default size has at least as much precision as double.
A precise grammar for Scheme numbers is given on page 459.
Any number can be written in a variety of different ways, but the system printer (invoked by putdatum
, write
, and display
) and number>string
express numbers in a compact form, using the fewest number of digits necessary to retain the property that, when read, the printed number is identical to the original number.
The remainder of this section describes "generic arithmetic" procedures that operate on numbers. The two sections that follow this section describe operations specific to fixnums and flonums, which are representations of exact, fixedprecision integer values and inexact real values.
The types of numeric arguments accepted by the procedures in this section are implied by the names given to the arguments: num
for complex numbers (that is, all numbers), real
for real numbers, rat
for rational numbers, and int
for integers. If a real
, rat
, or int
is required, the argument must be considered real, rational, or integral by real?
, rational?
, or integer?
, i.e., the imaginary part of the number must be exactly zero. Where exact integers are required, the name exint
is used. In each case, a suffix may appear on the name, e.g., int_{2}
.
procedure 

returns 

libraries 

(exact? 1) ⇒ #t
(exact? 15/16) ⇒ #t
(exact? 2.01) ⇒ #f
(exact? #i77) ⇒ #f
(exact? #i2/3) ⇒ #f
(exact? 1.02i) ⇒ #f
procedure 

returns 

libraries 

(inexact? 123) ⇒ #f
(inexact? #i123) ⇒ #t
(inexact? 1e23) ⇒ #t
(inexact? +i) ⇒ #f
procedure 

procedure 

procedure 

procedure 

procedure 

returns 

libraries 

The predicate =
returns #t
if its arguments are equal. The predicate <
returns #t
if its arguments are monotonically increasing, i.e., each argument is greater than the preceding ones, while >
returns #t
if its arguments are monotonically decreasing. The predicate <=
returns #t
if its arguments are monotonically nondecreasing, i.e., each argument is not less than the preceding ones, while >=
returns #t
if its arguments are monotonically nonincreasing.
As implied by the names of the arguments, =
is defined for complex arguments while the other relational predicates are defined only for real arguments. Two complex numbers are considered equal if their real and imaginary parts are equal. Comparisons involving NaNs always return #f
.
(= 7 7) ⇒ #t
(= 7 9) ⇒ #f
(< 2e3 3e2) ⇒ #f
(<= 1 2 3 3 4 5) ⇒ #t
(<= 1 2 3 4 5) ⇒ #t
(> 1 2 2 3 3 4) ⇒ #f
(>= 1 2 2 3 3 4) ⇒ #f
(= 1/2 0.5) ⇒ #t
(= 2/3 .667) ⇒ #f
(= 7.2+0i 7.2) ⇒ #t
(= 7.23i 7) ⇒ #f
(< 1/2 2/3 3/4) ⇒ #t
(> 8 4.102 2/3 5) ⇒ #t
(let ([x 0.218723452])
(< 0.210 x 0.220)) ⇒ #t
(let ([i 1] [v (vector 'a 'b 'c)])
(< 1 i (vectorlength v))) ⇒ #t
(apply < '(1 2 3 4)) ⇒ #t
(apply > '(4 3 3 2)) ⇒ #f
(= +nan.0 +nan.0) ⇒ #f
(< +nan.0 +nan.0) ⇒ #f
(> +nan.0 +nan.0) ⇒ #f
(>= +inf.0 +nan.0) ⇒ #f
(>= +nan.0 inf.0) ⇒ #f
(> +nan.0 0.0) ⇒ #f
procedure 

returns 
the sum of the arguments 
libraries 

When called with no arguments, +
returns 0.
(+) ⇒ 0
(+ 1 2) ⇒ 3
(+ 1/2 2/3) ⇒ 7/6
(+ 3 4 5) ⇒ 12
(+ 3.0 4) ⇒ 7.0
(+ 3+4i 4+3i) ⇒ 7+7i
(apply + '(1 2 3 4 5)) ⇒ 15
procedure 

returns 
the additive inverse of 
procedure 

returns 
the difference between 
libraries 

( 3) ⇒ 3
( 2/3) ⇒ 2/3
( 4 3.0) ⇒ 1.0
( 3.25+4.25i 1/4+1/4i) ⇒ 3.0+4.0i
( 4 3 2 1) ⇒ 2
procedure 

returns 
the product of the arguments 
libraries 

When called with no arguments, *
returns 1.
(*) ⇒ 1
(* 3.4) ⇒ 3.4
(* 1 1/2) ⇒ 1/2
(* 3 4 5.5) ⇒ 66.0
(* 1+2i 3+4i) ⇒ 5+10i
(apply * '(1 2 3 4 5)) ⇒ 120
procedure 

returns 
the multiplicative inverse of 
procedure 

returns 
the result of dividing 
libraries 

(/ 17) ⇒ 1/17
(/ 1/2) ⇒ 2
(/ .5) ⇒ 2.0
(/ 3 4) ⇒ 3/4
(/ 3.0 4) ⇒ .75
(/ 5+10i 3+4i) ⇒ 1+2i
(/ 60 5 4 3 2) ⇒ 1/2
procedure 

returns 

libraries 

zero?
is equivalent to (lambda (x) (= x 0))
.
(zero? 0) ⇒ #t
(zero? 1) ⇒ #f
(zero? ( 3.0 3.0)) ⇒ #t
(zero? (+ 1/2 1/2)) ⇒ #f
(zero? 0+0i) ⇒ #t
(zero? 0.00.0i) ⇒ #t
procedure 

returns 

libraries 

positive?
is equivalent to (lambda (x) (> x 0))
.
(positive? 128) ⇒ #t
(positive? 0.0) ⇒ #f
(positive? 1.8e15) ⇒ #t
(positive? 2/3) ⇒ #f
(positive? .0010.0i) ⇒ exception: not a real number
procedure 

returns 

libraries 

negative?
is equivalent to (lambda (x) (< x 0))
.
(negative? 65) ⇒ #t
(negative? 0) ⇒ #f
(negative? 0.0121) ⇒ #t
(negative? 15/16) ⇒ #f
(negative? 7.0+0.0i) ⇒ exception: not a real number
procedure 

returns 

procedure 

returns 

libraries 

(even? 0) ⇒ #t
(even? 1) ⇒ #f
(even? 2.0) ⇒ #t
(even? 120762398465) ⇒ #f
(even? 2.0+0.0i) ⇒ exception: not an integer
(odd? 0) ⇒ #f
(odd? 1) ⇒ #t
(odd? 2.0) ⇒ #f
(odd? 120762398465) ⇒ #t
(odd? 2.0+0.0i) ⇒ exception: not an integer
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

(finite? 2/3) ⇒ #t
(infinite? 2/3) ⇒ #f
(nan? 2/3) ⇒ #f
(finite? 3.1415) ⇒ #t
(infinite? 3.1415) ⇒ #f
(nan? 3.1415) ⇒ #f
(finite? +inf.0) ⇒ #f
(infinite? inf.0) ⇒ #t
(nan? inf.0) ⇒ #f
(finite? +nan.0) ⇒ #f
(infinite? +nan.0) ⇒ #f
(nan? +nan.0) ⇒ #t
procedure 

returns 
the integer quotient of 
procedure 

returns 
the integer remainder of 
procedure 

returns 
the integer modulus of 
libraries 

The result of remainder
has the same sign as int_{1}
, while the result of modulo
has the same sign as int_{2}
.
(quotient 45 6) ⇒ 7
(quotient 6.0 2.0) ⇒ 3.0
(quotient 3.0 2) ⇒ 1.0
(remainder 16 4) ⇒ 0
(remainder 5 2) ⇒ 1
(remainder 45.0 7) ⇒ 3.0
(remainder 10.0 3.0) ⇒ 1.0
(remainder 17 9) ⇒ 8
(modulo 16 4) ⇒ 0
(modulo 5 2) ⇒ 1
(modulo 45.0 7) ⇒ 4.0
(modulo 10.0 3.0) ⇒ 2.0
(modulo 17 9) ⇒ 8
procedure 

procedure 

procedure 

returns 
see below 
libraries 

If x_{1}
and x_{2}
are exact, x_{2}
must not be zero. These procedures implement numbertheoretic integer division, with the div
operation being related to quotient
and the mod
operation being related to remainder
or modulo
, but in both cases extended to handle real numbers.
The value n_{d}
of (div x_{1} x_{2})
is an integer, and the value x_{m}
of (mod x_{1} x_{2})
is a real number such that \(x_1 = n_d \cdot x_2 + x_m\) and \(0 \le x_m \lt x_2\). In situations where the implementation cannot represent the mathematical results prescribed by these equations as a number object, div
and mod
return an unspecified number or raise an exception with condition type &implementationrestriction
.
The divandmod
procedure behaves as if defined as follows.
(define (divandmod x1 x2) (values (div x1 x2) (mod x1 x2)))
That is, unless it raises an exception in the circumstance described above, it returns two values: the result of calling div
on the two arguments and the result of calling mod
on the two arguments.
(div 17 3) ⇒ 5
(mod 17 3) ⇒ 2
(div 17 3) ⇒ 6
(mod 17 3) ⇒ 1
(div 17 3) ⇒ 5
(mod 17 3) ⇒ 2
(div 17 3) ⇒ 6
(mod 17 3) ⇒ 1
(divandmod 17.5 3) ⇒ 5.0
2.5
procedure 

procedure 

procedure 

returns 
see below 
libraries 

If x_{1}
and x_{2}
are exact, x_{2}
must not be zero. These procedures are similar to div
, mod
, and divandmod
, but constrain the "mod" value differently, which also affects the "div" value. The value n_{d}
of (div0 x_{1} x_{2})
is an integer, and the value x_{m}
of (mod0 x_{1} x_{2})
is a real number such that \(x_1 = n_d \cdot x_2 + x_m\) and \(x_2 / 2 \leq x_m \lt x_2 / 2\). In situations where the implementation cannot represent the mathematical results prescribed by these equations as a number object, div0
and mod0
return an unspecified number or raise an exception with condition type &implementationrestriction
.
The div0andmod0
procedure behaves as if defined as follows.
(define (div0andmod0 x1 x2) (values (div0 x1 x2) (mod0 x1 x2)))
That is, unless it raises an exception in the circumstance described above, it returns two values: the result of calling div0
on the two arguments and the result of calling mod0
on the two arguments.
(div0 17 3) ⇒ 6
(mod0 17 3) ⇒ 1
(div0 17 3) ⇒ 6
(mod0 17 3) ⇒ 1
(div0 17 3) ⇒ 6
(mod0 17 3) ⇒ 1
(div0 17 3) ⇒ 6
(mod0 17 3) ⇒ 1
(div0andmod0 17.5 3) ⇒ 6.0
0.5
procedure 

returns 
the integer closest to 
libraries 

If real
is an infinity or NaN, truncate
returns real
.
(truncate 19) ⇒ 19
(truncate 2/3) ⇒ 0
(truncate 2/3) ⇒ 0
(truncate 17.3) ⇒ 17.0
(truncate 17/2) ⇒ 8
procedure 

returns 
the integer closest to 
libraries 

If real
is an infinity or NaN, floor
returns real
.
(floor 19) ⇒ 19
(floor 2/3) ⇒ 0
(floor 2/3) ⇒ 1
(floor 17.3) ⇒ 17.0
(floor 17/2) ⇒ 9
procedure 

returns 
the integer closest to 
libraries 

If real
is an infinity or NaN, ceiling
returns real
.
(ceiling 19) ⇒ 19
(ceiling 2/3) ⇒ 1
(ceiling 2/3) ⇒ 0
(ceiling 17.3) ⇒ 18.0
(ceiling 17/2) ⇒ 8
procedure 

returns 
the integer closest to 
libraries 

If real
is exactly between two integers, the closest even integer is returned. If real
is an infinity or NaN, round
returns real
.
(round 19) ⇒ 19
(round 2/3) ⇒ 1
(round 2/3) ⇒ 1
(round 17.3) ⇒ 17.0
(round 17/2) ⇒ 8
(round 2.5) ⇒ 2.0
(round 3.5) ⇒ 4.0
abs
is equivalent to (lambda (x) (if (< x 0) ( x) x))
. abs
and magnitude
(see page 183) are identical for real inputs.
(abs 1) ⇒ 1
(abs 3/4) ⇒ 3/4
(abs 1.83) ⇒ 1.83
(abs 0.093) ⇒ 0.093
procedure 

returns 
the maximum of 
libraries 

(max 4 7 2 0 6) ⇒ 4
(max 1/2 3/4 4/5 5/6 6/7) ⇒ 6/7
(max 1.5 1.3 0.3 0.4 2.0 1.8) ⇒ 2.0
(max 5 2.0) ⇒ 5.0
(max 5 2.0) ⇒ 2.0
(let ([ls '(7 3 5 2 9 8)])
(apply max ls)) ⇒ 9
procedure 

returns 
the minimum of 
libraries 

(min 4 7 2 0 6) ⇒ 7
(min 1/2 3/4 4/5 5/6 6/7) ⇒ 1/2
(min 1.5 1.3 0.3 0.4 2.0 1.8) ⇒ 0.3
(min 5 2.0) ⇒ 2.0
(min 5 2.0) ⇒ 5.0
(let ([ls '(7 3 5 2 9 8)])
(apply min ls)) ⇒ 2
procedure  
returns 
the greatest common divisor of its arguments 
libraries 

The result is always nonnegative, i.e., factors of 1 are ignored. When called with no arguments, gcd
returns 0.
(gcd) ⇒ 0
(gcd 34) ⇒ 34
(gcd 33.0 15.0) ⇒ 3.0
(gcd 70 42 28) ⇒ 14
procedure 

returns 
the least common multiple of its arguments 
libraries 

The result is always nonnegative, i.e., common multiples of 1 are ignored. Although lcm
should probably return \(\infty\) when called with no arguments, it is defined to return 1. If one or more of the arguments is 0, lcm
returns 0.
(lcm) ⇒ 1
(lcm 34) ⇒ 34
(lcm 33.0 15.0) ⇒ 165.0
(lcm 70 42 28) ⇒ 420
(lcm 17.0 0) ⇒ 0.0
procedure 

returns 

libraries 

If both arguments are 0, expt
returns 1.
(expt 2 10) ⇒ 1024
(expt 2 10) ⇒ 1/1024
(expt 2 10.0) ⇒ 9.765625e4
(expt 1/2 5) ⇒ 1/32
(expt 3.0 3) ⇒ 27.0
(expt +i 2) ⇒ 1
procedure 

returns 
an inexact representation of 
libraries 

If num
is already inexact, it is returned unchanged. If no inexact representation for num
is supported by the implementation, an exception with condition type &implementationviolation
may be raised. inexact
may also return +inf.0
or inf.0
for inputs whose magnitude exceeds the range of the implementation’s inexact number representations.
(inexact 3) ⇒ 3.0
(inexact 3.0) ⇒ 3.0
(inexact 1/4) ⇒ .25
(inexact 3+4i) ⇒ 3.0+4.0i
(inexact (expt 10 20)) ⇒ 1e20
procedure 

returns 
an exact representation of 
libraries 

If num
is already exact, it is returned unchanged. If no exact representation for num
is supported by the implementation, an exception with condition type &implementationviolation
may be raised.
(exact 3.0) ⇒ 3
(exact 3) ⇒ 3
(exact .25) ⇒ 1/4
(exact 3.0+4.0i) ⇒ 3+4i
(exact 1e20) ⇒ 100000000000000000000
procedure 

returns 
an inexact representation of 
procedure 

returns 
an exact representation of 
libraries 

These are alternative names for inexact
and exact
, supported for compatibility with the Revised^{5} Report.
procedure 

returns 
see below 
libraries 

rationalize
returns the simplest rational number that differs from real_{1}
by no more than real_{2}
. A rational number \(q_1 = n_1/m_1\) is simpler than another rational number \(q_2 = n_2/m_2\) if \(n_1 \le n_2\) and \(m_1 \le m_2\) and either \(n_1 \lt n_2\) or \(m_1 \lt m_2\).
(rationalize 3/10 1/10) ⇒ 1/3
(rationalize .3 1/10) ⇒ 0.3333333333333333
(eqv? (rationalize .3 1/10) #i1/3) ⇒ #t
procedure 

returns 
the numerator of 
libraries 

If rat
is an integer, the numerator is rat
.
(numerator 9) ⇒ 9
(numerator 9.0) ⇒ 9.0
(numerator 0.0) ⇒ 0.0
(numerator 2/3) ⇒ 2
(numerator 9/4) ⇒ 9
(numerator 2.25) ⇒ 9.0
procedure 

returns 
the denominator of 
libraries 

If rat
is an integer, including zero, the denominator is one.
(denominator 9) ⇒ 1
(denominator 9.0) ⇒ 1.0
(denominator 0) ⇒ 1
(denominator 0.0) ⇒ 1.0
(denominator 2/3) ⇒ 3
(denominator 9/4) ⇒ 4
(denominator 2.25) ⇒ 4.0
procedure 

returns 
the real component of 
libraries 

If num
is real, realpart
returns num
.
(realpart 3+4i) ⇒ 3
(realpart 2.3+0.7i) ⇒ 2.3
(realpart i) ⇒ 0
(realpart 17.2) ⇒ 17.2
(realpart 17/100) ⇒ 17/100
procedure 

returns 
the imaginary component of 
libraries 

If num
is real, imagpart
returns exact zero.
(imagpart 3+4i) ⇒ 4
(imagpart 2.3+0.7i) ⇒ 0.7
(imagpart i) ⇒ 1
(imagpart 2.5) ⇒ 0
(imagpart 17/100) ⇒ 0
procedure 

returns 
a complex number with real component 
libraries 

(makerectangular 2 7) ⇒ 2+7i
(makerectangular 2/3 1/2) ⇒ 2/31/2i
(makerectangular 3.2 5.3) ⇒ 3.2+5.3i
procedure 

returns 
a complex number with magnitude 
libraries 

(makepolar 2 0) ⇒ 2
(makepolar 2.0 0.0) ⇒ 2.0+0.0i
(makepolar 1.0 (asin 1.0)) ⇒ 0.01.0i
(eqv? (makepolar 7.2 0.588) 7.2@0.588) ⇒ #t
procedure 

returns 
the angle part of the polar representation of 
libraries 

The range of the result is \(π\) (exclusive) to \(+π\) (inclusive).
(angle 7.3@1.5708) ⇒ 1.5708
(angle 5.2) ⇒ 0.0
magnitude
and abs
(see page 178) are identical for real arguments. The magnitude of a complex number \(x + yi\) is \(+\sqrt{x^2+y^2}\).
(magnitude 1) ⇒ 1
(magnitude 3/4) ⇒ 3/4
(magnitude 1.83) ⇒ 1.83
(magnitude 0.093) ⇒ 0.093
(magnitude 3+4i) ⇒ 5
(magnitude 7.25@1.5708) ⇒ 7.25
procedure 

returns 
the principal square root of 
libraries 

Implementations are encouraged, but not required, to return exact results for exact inputs to sqrt
whenever feasible.
(sqrt 16) ⇒ 4
(sqrt 1/4) ⇒ 1/2
(sqrt 4.84) ⇒ 2.2
(sqrt 4.84) ⇒ 0.0+2.2i
(sqrt 3+4i) ⇒ 2+1i
(sqrt 3.04.0i) ⇒ 1.02.0i
procedure 

returns 
see below 
libraries 

This procedure returns two nonnegative exact integers s and r where \(n = s^2 + r\) and \(n < (s + 1)^2\).
(exactintegersqrt 0) ⇒ 0
0
(exactintegersqrt 9) ⇒ 3
⇒ 0
(exactintegersqrt 19) ⇒ 4
⇒ 3
procedure 

returns 
e to the 
libraries 

(exp 0.0) ⇒ 1.0
(exp 1.0) ⇒ 2.7182818284590455
(exp .5) ⇒ 0.6065306597126334
procedure 

returns 
the natural logarithm of 
procedure 

returns 
the base 
libraries 

(log 1.0) ⇒ 0.0
(log (exp 1.0)) ⇒ 1.0
(/ (log 100) (log 10)) ⇒ 2.0
(log (makepolar (exp 2.0) 1.0)) ⇒ 2.0+1.0i
(log 100.0 10.0) ⇒ 2.0
(log .125 2.0) ⇒ 3.0
procedure 

procedure 

procedure 

returns 
the sine, cosine, or tangent of 
libraries 

The argument is specified in radians.
(sin 0.0) ⇒ 0.0
(cos 0.0) ⇒ 1.0
(tan 0.0) ⇒ 0.0
procedure 

procedure 

returns 
the arc sine or the arc cosine of 
libraries 

The result is in radians. The arc sine and arc cosine of a complex number z are defined as follows.
(define pi (* (asin 1) 2))
(= (* (acos 0) 2) pi) ⇒ #t
procedure 

procedure 

returns 
see below 
libraries 

When passed a single complex argument num
(the first form), atan
returns the arc tangent of num
. The arc tangent of a complex number z is defined as follows.
When passed two real arguments (the second form), atan
is equivalent to (lambda (y x) (angle (makerectangular x y)))
.
(define pi (* (atan 1) 4))
(= (* (atan 1.0 0.0) 2) pi) ⇒ #t
procedure 

returns 
the bitwise not of 
procedure 

returns 
the bitwise and of 
procedure 

returns 
the bitwise inclusive or of 
procedure 

returns 
the bitwise exclusive or of 
libraries 

The inputs are treated as if represented in two’s complement, even if they are not represented that way internally.
(bitwisenot 0) ⇒ 1
(bitwisenot 3) ⇒ 4
(bitwiseand #b01101 #b00111) ⇒ #b00101
(bitwiseior #b01101 #b00111) ⇒ #b01111
(bitwisexor #b01101 #b00111) ⇒ #b01010
procedure 

returns 
the bitwise "if" of its arguments 
libraries 

The inputs are treated as if represented in two’s complement, even if they are not represented that way internally.
For each bit set in exint_{1}
, the corresponding bit of the result is taken from exint_{2}
, and for each bit not set in exint_{1}
, the corresponding bit of the result is taken from x_{3}
.
(bitwiseif #b101010 #b111000 #b001100) ⇒ #b101100
bitwiseif
might be defined as follows:
(define bitwiseif
(lambda (exint1 exint2 exint3)
(bitwiseior
(bitwiseand exint1 exint2)
(bitwiseand (bitwisenot exint1) exint3))))
procedure 

returns 
see below 
libraries 

For nonnegative inputs, bitwisebitcount
returns the number of bits set in the two’s complement representation of exint
. For negative inputs, it returns a negative number whose magnitude is one greater than the number of bits not set in the two’s complement representation of exint
, which is equivalent to (bitwisenot (bitwisebitcount (bitwisenot exint)))
.
(bitwisebitcount #b00000) ⇒ 0
(bitwisebitcount #b00001) ⇒ 1
(bitwisebitcount #b00100) ⇒ 1
(bitwisebitcount #b10101) ⇒ 3
(bitwisebitcount 1) ⇒ 1
(bitwisebitcount 2) ⇒ 2
(bitwisebitcount 4) ⇒ 3
procedure 

returns 
see below 
libraries 

This procedure returns the number of bits of the smallest two’s complement representation of exint
, not including the sign bit for negative numbers. For 0 bitwiselength
returns 0.
(bitwiselength #b00000) ⇒ 0
(bitwiselength #b00001) ⇒ 1
(bitwiselength #b00100) ⇒ 3
(bitwiselength #b00110) ⇒ 3
(bitwiselength 1) ⇒ 0
(bitwiselength 6) ⇒ 3
(bitwiselength 9) ⇒ 4
procedure 

returns 
the index of the least significant bit set in 
libraries 

The input is treated as if represented in two’s complement, even if it is not represented that way internally.
If exint
is 0, bitwisefirstbitset
returns 1.
(bitwisefirstbitset #b00000) ⇒ 1
(bitwisefirstbitset #b00001) ⇒ 0
(bitwisefirstbitset #b01100) ⇒ 2
(bitwisefirstbitset 1) ⇒ 0
(bitwisefirstbitset 2) ⇒ 1
(bitwisefirstbitset 3) ⇒ 0
procedure 

returns 

libraries 

exint_{2}
is taken as a zerobased index for the bits in the two’s complement representation of exint_{1}
. The two’s complement representation of a nonnegative number conceptually extends to the left (toward more significant bits) with an infinite number of zero bits, and the two’s complement representation of a negative number conceptually extends to the left with an infinite number of one bits. Thus, exact integers can be used to represent arbitrarily large sets, where 0 is the empty set, 1 is the universe, and bitwisebitset?
is used to test for membership.
(bitwisebitset? #b01011 0) ⇒ #t
(bitwisebitset? #b01011 2) ⇒ #f
(bitwisebitset? 1 0) ⇒ #t
(bitwisebitset? 1 20) ⇒ #t
(bitwisebitset? 3 1) ⇒ #f
(bitwisebitset? 0 5000) ⇒ #f
(bitwisebitset? 1 5000) ⇒ #t
procedure 

returns 

libraries 

exint_{2}
is taken as a zerobased index for the bits in the two’s complement representation of exint_{1}
. exint_{3}
must be 0 or 1. This procedure effectively clears or sets the specified bit depending on the value of exint_{3}
. exint_{1}
is treated as if represented in two’s complement, even if it is not represented that way internally.
(bitwisecopybit #b01110 0 1) ⇒ #b01111
(bitwisecopybit #b01110 2 0) ⇒ #b01010
procedure 

returns 
see below 
libraries 

exint_{2}
and exint_{3}
must be nonnegative, and exint_{2}
must not be greater than exint_{3}
. This procedure returns the number represented by extracting from exint_{1}
the sequence of bits from exint_{2}
(inclusive) to exint_{3}
(exclusive). exint_{1}
is treated as if represented in two’s complement, even if it is not represented that way internally.
(bitwisebitfield #b10110 0 3) ⇒ #b00110
(bitwisebitfield #b10110 1 3) ⇒ #b00011
(bitwisebitfield #b10110 2 3) ⇒ #b00001
(bitwisebitfield #b10110 3 3) ⇒ #b00000
procedure 

returns 
see below 
libraries 

exint_{2}
and exint_{3}
must be nonnegative, and exint_{2}
must not be greater than exint_{3}
. This procedure returns exint_{1}
with the n
bits from exint_{2}
(inclusive) to exint_{3}
(exclusive) replaced by the loworder n
bits of exint_{4}
. exint_{1}
and exint_{4}
are treated as if represented in two’s complement, even if they are not represented that way internally.
(bitwisecopybitfield #b10000 0 3 #b10101) ⇒ #b10101
(bitwisecopybitfield #b10000 1 3 #b10101) ⇒ #b10010
(bitwisecopybitfield #b10000 2 3 #b10101) ⇒ #b10100
(bitwisecopybitfield #b10000 3 3 #b10101) ⇒ #b10000
procedure 

returns 

procedure 

returns 

libraries 

exint_{2}
must be nonnegative. exint_{1}
is treated as if represented in two’s complement, even if it is not represented that way internally.
(bitwisearithmeticshiftright #b10000 3) ⇒ #b00010
(bitwisearithmeticshiftright 1 1) ⇒ 1
(bitwisearithmeticshiftright 64 3) ⇒ 8
(bitwisearithmeticshiftleft #b00010 2) ⇒ #b01000
(bitwisearithmeticshiftleft 1 2) ⇒ 4
procedure 

returns 
see below 
libraries 

If exint_{2}
is negative, bitwisearithmeticshift
returns the result of arithmetically shifting exint_{1}
right by exint_{2}
bits. Otherwise, bitwisearithmeticshift
returns the result of shifting exint_{1}
left by exint_{2}
bits. exint_{1}
is treated as if represented in two’s complement, even if it is not represented that way internally.
(bitwisearithmeticshift #b10000 3) ⇒ #b00010
(bitwisearithmeticshift 1 1) ⇒ 1
(bitwisearithmeticshift 64 3) ⇒ 8
(bitwisearithmeticshift #b00010 2) ⇒ #b01000
(bitwisearithmeticshift 1 2) ⇒ 4
Thus, bitwisearithmeticshift
behaves as if defined as follows.
(define bitwisearithmeticshift
(lambda (exint1 exint2)
(if (< exint2 0)
(bitwisearithmeticshiftright exint1 ( exint2))
(bitwisearithmeticshiftleft exint1 exint2))))
procedure 

returns 
see below 
libraries 

exint_{2}
, exint_{3}
, and exint_{4}
must be nonnegative, and exint_{2}
must not be greater than exint_{3}
. This procedure returns the result of shifting the bits of exint_{1}
from bit exint_{2}
(inclusive) through bit exint_{3}
(exclusive) left by (mod exint_{4} ( exint_{3} exint_{2}))
bits, with the bits shifted out of the range inserted at the bottom end of the range. exint_{1}
is treated as if represented in two’s complement, even if it is not represented that way internally.
(bitwiserotatebitfield #b00011010 0 5 3) ⇒ #b00010110
(bitwiserotatebitfield #b01101011 2 7 3) ⇒ #b01011011
procedure 

returns 
see below 
libraries 

exint_{2}
and exint_{3}
must be nonnegative, and exint_{2}
must not be greater than exint_{3}
. This procedure returns the result of reversing the bits of exint_{1}
from bit exint_{2}
(inclusive) through bit exint_{3}
(exclusive). exint_{1}
is treated as if represented in two’s complement, even if it is not represented that way internally.
(bitwisereversebitfield #b00011010 0 5) ⇒ #b00001011
(bitwisereversebitfield #b01101011 2 7) ⇒ #b00101111
procedure 

procedure 

returns 
the number represented by 
libraries 

If string
is a valid representation of a number, that number is returned, otherwise #f
is returned. The number is interpreted in radix radix
, which must be an exact integer in the set {2,8,10,16}. If not specified, radix
defaults to 10. Any radix specifier within string
, e.g., #x
, overrides the radix
argument.
(string>number "0") ⇒ 0
(string>number "3.4e3") ⇒ 3400.0
(string>number "#x#e2e2") ⇒ 738
(string>number "#e2e2" 16) ⇒ 738
(string>number "#i15/16") ⇒ 0.9375
(string>number "10" 16) ⇒ 16
procedure 

procedure 

procedure 

returns 
an external representation of 
libraries 

The num is expressed in radix radix
, which must be an exact integer in the set {2,8,10,16}. If not specified, radix
defaults to 10. In any case, no radix specifier appears in the resulting string.
The external representation is such that, when converted back into a number using string>number
, the resulting numeric value is equivalent to num
. That is, for all inputs:
(eqv? (string>number
(number>string num radix)
radix)
num)
returns #t
. An exception with condition type &implementationrestriction
is raised if this is not possible.
If precision
is provided, it must be an exact positive integer, num
must be inexact, and radix
must be 10. In this case, the real part and, if present, the imaginary part of the number are each printed with an explicit mantissa width m
, where m
is the least possible value greater than or equal to precision
that makes the expression above true.
If radix
is 10, inexact values of num
are expressed using the fewest number of significant digits possible [5] without violating the above restriction.
(number>string 3.4) ⇒ "3.4"
(number>string 1e2) ⇒ "100.0"
(number>string 1e23) ⇒ "1e23"
(number>string 7/2) ⇒ "7/2"
(number>string 220/9 16) ⇒ "DC/9"
Section 6.5. Fixnums
Fixnums represent exact integers in the fixnum range, which is required to be a closed range \([2^{w1}, 2^{w1}  1]\), where w (the fixnum width) is at least 24. The implementationspecific value of w may be determined via the procedure fixnumwidth
, and the endpoints of the range may be determined via the procedures leastfixnum
and greatestfixnum
.
The names of arithmetic procedures that operate only on fixnums begin with the prefix “fx” to set them apart from their generic counterparts.
Procedure arguments required to be fixnums are named fx
, possibly with a suffix, e.g., fx_{2}
.
Unless otherwise specified, the numeric values of fixnumspecific procedures are fixnums. If the value of a fixnum operation should be a fixnum, but the mathematical result would be outside the fixnum range, an exception with condition type &implementationrestriction
is raised.
Bit and shift operations on fixnums assume that fixnums are represented in two’s complement, even if they are not represented that way internally.
procedure 

returns 

libraries 

(fixnum? 0) ⇒ #t
(fixnum? 1) ⇒ #t
(fixnum? ( (expt 2 23))) ⇒ #t
(fixnum? ( (expt 2 23) 1)) ⇒ #t
procedure 

returns 
the least (most negative) fixnum supported by the implementation 
procedure 

returns 
the greatest (most positive) fixnum supported by the implementation 
libraries 

(fixnum? ( (leastfixnum) 1)) ⇒ #f
(fixnum? (leastfixnum)) ⇒ #t
(fixnum? (greatestfixnum)) ⇒ #t
(fixnum? (+ (greatestfixnum) 1)) ⇒ #f
procedure 

returns 
the implementationdependent fixnum width 
libraries 

As described in the leadin to this section, the fixnum width determines the size of the fixnum range and must be at least 24.
(define w (fixnumwidth))
(= (leastfixnum) ( (expt 2 ( w 1)))) ⇒ #t
(= (greatestfixnum) ( (expt 2 ( w 1)) 1)) ⇒ #t
(>= w 24) ⇒ #t
procedure 

procedure 

procedure 

procedure 

procedure 

returns 

libraries 

The predicate fx=?
returns #t
if its arguments are equal. The predicate fx<?
returns #t
if its arguments are monotonically increasing, i.e., each argument is greater than the preceding ones, while fx>?
returns #t
if its arguments are monotonically decreasing. The predicate fx<=?
returns #t
if its arguments are monotonically nondecreasing, i.e., each argument is not less than the preceding ones, while fx>=?
returns #t
if its arguments are monotonically nonincreasing.
(fx=? 0 0) ⇒ #t
(fx=? 1 1) ⇒ #f
(fx? 5 4 3 2 1) ⇒ #t
(fx<=? 1 3 2) ⇒ #f
(fx>=? 0 0 (leastfixnum)) ⇒ #t
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

fxzero?
is equivalent to (lambda (x) (fx=? x 0))
, fxpositive?
is equivalent to (lambda (x) (fx>? x 0))
, and fxnegative?
to (lambda (x) (fx<? x 0))
.
(fxzero? 0) ⇒ #t
(fxzero? 1) ⇒ #f
(fxpositive? 128) ⇒ #t
(fxpositive? 0) ⇒ #f
(fxpositive? 1) ⇒ #f
(fxnegative? 65) ⇒ #t
(fxnegative? 0) ⇒ #f
(fxnegative? 1) ⇒ #f
procedure 

returns 

procedure 

returns 

libraries 

(fxeven? 0) ⇒ #t
(fxeven? 1) ⇒ #f
(fxeven? 1) ⇒ #f
(fxeven? 10) ⇒ #t
(fxodd? 0) ⇒ #f
(fxodd? 1) ⇒ #t
(fxodd? 1) ⇒ #t
(fxodd? 10) ⇒ #f
procedure 

returns 
the minimum of 
procedure 

returns 
the maximum of 
libraries 

(fxmin 4 7 2 0 6) ⇒ 7
(let ([ls '(7 3 5 2 9 8)])
(apply fxmin ls)) ⇒ 2
(fxmax 4 7 2 0 6) ⇒ 4
(let ([ls '(7 3 5 2 9 8)])
(apply fxmax ls)) ⇒ 9
procedure 

returns 
the sum of 
libraries 

(fx+ 3 4) ⇒ 1
procedure 

returns 
the additive inverse of 
procedure 

returns 
the difference between 
libraries 

(fx 3) ⇒ 3
(fx 3 4) ⇒ 7
procedure 

returns 
the product of 
libraries 

(fx* 3 4) ⇒ 12
procedure 

procedure 

procedure 

returns 
see below 
libraries 

fx_{2}
must not be zero. These are fixnumspecific versions of the generic div
, mod
, and divandmod
.
(fxdiv 17 3) ⇒ 5
(fxmod 17 3) ⇒ 2
(fxdiv 17 3) ⇒ 6
(fxmod 17 3) ⇒ 1
(fxdiv 17 3) ⇒ 5
(fxmod 17 3) ⇒ 2
(fxdiv 17 3) ⇒ 6
(fxmod 17 3) ⇒ 1
(fxdivandmod 17 3) ⇒ 5
2
procedure 

procedure 

procedure 

returns 
see below 
libraries 

fx_{2}
must not be zero. These are fixnumspecific versions of the generic div0
, mod0
, and div0andmod0
.
(fxdiv0 17 3) ⇒ 6
(fxmod0 17 3) ⇒ 1
(fxdiv0 17 3) ⇒ 6
(fxmod0 17 3) ⇒ 1
(fxdiv0 17 3) ⇒ 6
(fxmod0 17 3) ⇒ 1
(fxdiv0 17 3) ⇒ 6
(fxmod0 17 3) ⇒ 1
(fxdiv0andmod0 17 3) ⇒ 6
1
procedure 

procedure 

procedure 

returns 
see below 
libraries 

When an ordinary fixnum addition, subtraction, or multiplication operation overflows, an exception is raised. These alternative procedures instead return a carry and also allow the carry to be propagated to the next operation. They can be used to implement portable code for multipleprecision arithmetic.
These procedures return the two fixnum values of the following computations. For fx+/carry
:
(let* ([s (+ fx_{1} fx_{2} fx_{3})]
[s0 (mod0 s (expt 2 (fixnumwidth)))]
[s1 (div0 s (expt 2 (fixnumwidth)))])
(values s0 s1))
for fx/carry
:
(let* ([d ( fx_{1} fx_{2} fx_{3})]
[d0 (mod0 d (expt 2 (fixnumwidth)))]
[d1 (div0 d (expt 2 (fixnumwidth)))])
(values d0 d1))
and for fx*/carry
:
(let* ([s (+ (* fx_{1} fx_{2}) fx_{3})]
[s0 (mod0 s (expt 2 (fixnumwidth)))]
[s1 (div0 s (expt 2 (fixnumwidth)))])
(values s0 s1))
procedure 

returns 
the bitwise not of 
procedure 

returns 
the bitwise and of 
procedure 

returns 
the bitwise inclusive or of 
procedure 

returns 
the bitwise exclusive or of 
libraries 

(fxnot 0) ⇒ 1
(fxnot 3) ⇒ 4
(fxand #b01101 #b00111) ⇒ #b00101
(fxior #b01101 #b00111) ⇒ #b01111
(fxxor #b01101 #b00111) ⇒ #b01010
procedure 

returns 
the bitwise "if" of its arguments 
libraries 

For each bit set in fx_{1}
, the corresponding bit of the result is taken from fx_{2}
, and for each bit not set in fx_{1}
, the corresponding bit of the result is taken from x_{3}
.
(fxif #b101010 #b111000 #b001100) ⇒ #b101100
fxif
might be defined as follows:
(define fxif
(lambda (fx1 fx2 fx3)
(fxior (fxand fx1 fx2)
(fxand (fxnot fx1) fx3))))
procedure 

returns 
see below 
libraries 

For nonnegative inputs, fxbitcount
returns the number of bits set in the two’s complement representation of fx
. For negative inputs, it returns a negative number whose magnitude is one greater than the number of bits not set in fx
, which is equivalent to (fxnot (fxbitcount (fxnot fx)))
.
(fxbitcount #b00000) ⇒ 0
(fxbitcount #b00001) ⇒ 1
(fxbitcount #b00100) ⇒ 1
(fxbitcount #b10101) ⇒ 3
(fxbitcount 1) ⇒ 1
(fxbitcount 2) ⇒ 2
(fxbitcount 4) ⇒ 3
procedure 

returns 
see below 
libraries 

This procedure returns the number of bits of the smallest two’s complement representation of fx
, not including the sign bit for negative numbers. For 0 fxlength
returns 0.
(fxlength #b00000) ⇒ 0
(fxlength #b00001) ⇒ 1
(fxlength #b00100) ⇒ 3
(fxlength #b00110) ⇒ 3
(fxlength 1) ⇒ 0
(fxlength 6) ⇒ 3
(fxlength 9) ⇒ 4
procedure 

returns 
the index of the least significant bit set in 
libraries 

If fx
is 0, fxfirstbitset
returns 1.
(fxfirstbitset #b00000) ⇒ 1
(fxfirstbitset #b00001) ⇒ 0
(fxfirstbitset #b01100) ⇒ 2
(fxfirstbitset 1) ⇒ 0
(fxfirstbitset 2) ⇒ 1
(fxfirstbitset 3) ⇒ 0
procedure 

returns 

libraries 

fx_{2}
must be nonnegative. It is taken as a zerobased index for the bits in the two’s complement representation of fx_{1}
, with the sign bit virtually replicated an infinite number of positions to the left.
(fxbitset? #b01011 0) ⇒ #t
(fxbitset? #b01011 2) ⇒ #f
(fxbitset? 1 0) ⇒ #t
(fxbitset? 1 20) ⇒ #t
(fxbitset? 3 1) ⇒ #f
(fxbitset? 0 ( (fixnumwidth) 1)) ⇒ #f
(fxbitset? 1 ( (fixnumwidth) 1)) ⇒ #t
procedure 

returns 

libraries 

fx_{2}
must be nonnegative and less than the value of ( (fixnumwidth) 1)
. fx_{3}
must be 0 or 1. This procedure effectively clears or sets the specified bit depending on the value of fx_{3}
.
(fxcopybit #b01110 0 1) ⇒ #b01111
(fxcopybit #b01110 2 0) ⇒ #b01010
procedure 

returns 
see below 
libraries 

fx_{2}
and fx_{3}
must be nonnegative and less than the value of (fixnumwidth)
, and fx_{2}
must not be greater than fx_{3}
. This procedure returns the number represented by extracting from fx_{1}
the sequence of bits from fx_{2}
(inclusive) to fx_{3}
(exclusive).
(fxbitfield #b10110 0 3) ⇒ #b00110
(fxbitfield #b10110 1 3) ⇒ #b00011
(fxbitfield #b10110 2 3) ⇒ #b00001
(fxbitfield #b10110 3 3) ⇒ #b00000
procedure 

returns 
see below 
libraries 

fx_{2}
and fx_{3}
must be nonnegative and less than the value of (fixnumwidth)
, and fx_{2}
must not be greater than fx_{3}
. This procedure returns fx_{1}
with n
bits from fx_{2}
(inclusive) to fx_{3}
(exclusive) replaced by the loworder n
bits of x_{4}
.
(fxcopybitfield #b10000 0 3 #b10101) ⇒ #b10101
(fxcopybitfield #b10000 1 3 #b10101) ⇒ #b10010
(fxcopybitfield #b10000 2 3 #b10101) ⇒ #b10100
(fxcopybitfield #b10000 3 3 #b10101) ⇒ #b10000
procedure 

returns 

procedure 

returns 

libraries 

fx_{2}
must be nonnegative and less than the value of (fixnumwidth)
.
(fxarithmeticshiftright #b10000 3) ⇒ #b00010
(fxarithmeticshiftright 1 1) ⇒ 1
(fxarithmeticshiftright 64 3) ⇒ 8
(fxarithmeticshiftleft #b00010 2) ⇒ #b01000
(fxarithmeticshiftleft 1 2) ⇒ 4
procedure 

returns 
see below 
libraries 

The absolute value of fx_{2}
must be less than the value of (fixnumwidth)
. If fx_{2}
is negative, fxarithmeticshift
returns the result of arithmetically shifting fx_{1}
right by fx_{2}
bits. Otherwise, fxarithmeticshift
returns the result of shifting fx_{1}
left by fx_{2}
bits.
(fxarithmeticshift #b10000 3) ⇒ #b00010
(fxarithmeticshift 1 1) ⇒ 1
(fxarithmeticshift 64 3) ⇒ 8
(fxarithmeticshift #b00010 2) ⇒ #b01000
(fxarithmeticshift 1 2) ⇒ 4
Thus, fxarithmeticshift
behaves as if defined as follows.
(define fxarithmeticshift
(lambda (fx1 fx2)
(if (fx<? fx2 0)
(fxarithmeticshiftright fx1 (fx fx2))
(fxarithmeticshiftleft fx1 fx2))))
procedure 

returns 
see below 
libraries 

fx_{2}
, fx_{3}
, and fx_{4}
must be nonnegative and less than the value of (fixnumwidth)
, fx_{2}
must not be greater than fx_{3}
, and fx_{4}
must not be greater than the difference between fx_{3}
and fx_{2}
.
This procedure returns the result of shifting the bits of fx_{1}
from bit fx_{2}
(inclusive) through bit fx_{3}
(exclusive) left by fx_{4}
bits, with the bits shifted out of the range inserted at the bottom end of the range.
(fxrotatebitfield #b00011010 0 5 3) ⇒ #b00010110
(fxrotatebitfield #b01101011 2 7 3) ⇒ #b01011011
procedure 

returns 
see below 
libraries 

fx_{2}
and fx_{3}
must be nonnegative and less than the value of (fixnumwidth)
, and fx_{2}
must not be greater than fx_{3}
. This procedure returns the result of reversing the bits of fx_{1}
from bit fx_{2}
(inclusive) through bit fx_{3}
(exclusive).
(fxreversebitfield #b00011010 0 5) ⇒ #b00001011
(fxreversebitfield #b01101011 2 7) ⇒ #b00101111
Section 6.6. Flonums
Flonums represent inexact real numbers. Implementations are required to represent as a flonum any inexact real number whose lexical syntax contains no vertical bar and no exponent marker other than e
, but are not required to represent any other inexact real number as a flonum.
Implementations typically use the IEEE doubleprecision floatingpoint representation for flonums, but implementations are not required to do so or even to use a floatingpoint representation of any sort, despite the name "flonum."
This section describes operations on flonums. Flonumspecific procedure names begin with the prefix “fl” to set them apart from their generic counterparts.
Procedure arguments required to be flonums are named fl
, possibly with suffix, e.g., fl_{2}
. Unless otherwise specified, the numeric values of flonumspecific procedures are flonums.
procedure 

returns 

libraries 

(flonum? 0) ⇒ #f
(flonum? 3/4) ⇒ #f
(flonum? 3.5) ⇒ #t
(flonum? .02) ⇒ #t
(flonum? 1e10) ⇒ #t
(flonum? 3.0+0.0i) ⇒ #f
procedure 

procedure 

procedure 

procedure 

procedure 

returns 

libraries 

The predicate fl=?
returns #t
if its arguments are equal. The predicate fl<?
returns #t
if its arguments are monotonically increasing, i.e., each argument is greater than the preceding ones, while fl>?
returns #t
if its arguments are monotonically decreasing. The predicate fl<=?
returns #t
if its arguments are monotonically nondecreasing, i.e., each argument is not less than the preceding ones, while fl>=?
returns #t
if its arguments are monotonically nonincreasing. When passed only one argument, each of these predicates returns #t
.
Comparisons involving NaNs always return #f
.
(fl=? 0.0 0.0) ⇒ #t
(fl<? 1.0 0.0 1.0) ⇒ #t
(fl>? 1.0 0.0 1.0) ⇒ #f
(fl<=? 0.0 3.0 3.0) ⇒ #t
(fl>=? 4.0 3.0 3.0) ⇒ #t
(fl<? 7.0 +inf.0) ⇒ #t
(fl=? +nan.0 0.0) ⇒ #f
(fl=? +nan.0 +nan.0) ⇒ #f
(fl<? +nan.0 +nan.0) ⇒ #f
(fl<=? +nan.0 +inf.0) ⇒ #f
(fl>=? +nan.0 +inf.0) ⇒ #f
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

flzero?
is equivalent to (lambda (x) (fl=? x 0.0))
, flpositive?
is equivalent to (lambda (x) (fl>? x 0.0))
, and flnegative?
to (lambda (x) (fl<? x 0.0))
.
Even if the flonum representation distinguishes 0.0 from +0.0, 0.0 is considered both zero and nonnegative.
(flzero? 0.0) ⇒ #t
(flzero? 1.0) ⇒ #f
(flpositive? 128.0) ⇒ #t
(flpositive? 0.0) ⇒ #f
(flpositive? 1.0) ⇒ #f
(flnegative? 65.0) ⇒ #t
(flnegative? 0.0) ⇒ #f
(flnegative? 1.0) ⇒ #f
(flzero? 0.0) ⇒ #t
(flnegative? 0.0) ⇒ #f
(flnegative? +nan.0) ⇒ #f
(flzero? +nan.0) ⇒ #f
(flpositive? +nan.0) ⇒ #f
(flnegative? +inf.0) ⇒ #f
(flnegative? inf.0) ⇒ #t
procedure 

returns 

libraries 

(flinteger? 0.0) ⇒ #t
(flinteger? 17.0) ⇒ #t
(flinteger? +nan.0) ⇒ #f
(flinteger? +inf.0) ⇒ #f
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

(flfinite? 3.1415) ⇒ #t
(flinfinite? 3.1415) ⇒ #f
(flnan? 3.1415) ⇒ #f
(flfinite? +inf.0) ⇒ #f
(flinfinite? inf.0) ⇒ #t
(flnan? inf.0) ⇒ #f
(flfinite? +nan.0) ⇒ #f
(flinfinite? +nan.0) ⇒ #f
(flnan? +nan.0) ⇒ #t
procedure 

returns 

procedure 

returns 

libraries 

flint
must be an integervalued flonum.
(fleven? 0.0) ⇒ #t
(fleven? 1.0) ⇒ #f
(fleven? 1.0) ⇒ #f
(fleven? 10.0) ⇒ #t
(flodd? 0.0) ⇒ #f
(flodd? 1.0) ⇒ #t
(flodd? 1.0) ⇒ #t
(flodd? 10.0) ⇒ #f
procedure 

returns 
the minimum of 
procedure 

returns 
the maximum of 
libraries 

(flmin 4.2 7.5 2.0 0.0 6.4) ⇒ 7.5
(let ([ls '(7.1 3.5 5.0 2.6 2.6 8.0)])
(apply flmin ls)) ⇒ 2.6
(flmax 4.2 7.5 2.0 0.0 6.4) ⇒ 4.2
(let ([ls '(7.1 3.5 5.0 2.6 2.6 8.0)])
(apply flmax ls)) ⇒ 8.0
procedure 

returns 
the sum of the arguments 
libraries 

When called with no arguments, fl+
returns 0.0
.
(fl+) ⇒ 0.0
(fl+ 1.0 2.5) ⇒ 3.25
(fl+ 3.0 4.25 5.0) ⇒ 12.25
(apply fl+ '(1.0 2.0 3.0 4.0 5.0)) ⇒ 15.0
procedure 

returns 
the additive inverse of 
procedure 

returns 
the difference between 
libraries 

With an IEEE floatingpoint representation of flonums, the singleargument fl
is equivalent to
(lambda (x) (fl* 1.0 x))
or
(lambda (x) (fl 0.0 x))
but not
(lambda (x) (fl 0.0 x))
since the latter returns 0.0
rather than 0.0
for 0.0
.
(fl 0.0) ⇒ 0.0
(fl 3.0) ⇒ 3.0
(fl 4.0 3.0) ⇒ 1.0
(fl 4.0 3.0 2.0 1.0) ⇒ 2.0
procedure 

returns 
the product of the arguments 
libraries 

When called with no arguments, fl*
returns 1.0
.
(fl*) ⇒ 1.0
(fl* 1.5 2.5) ⇒ 3.75
(fl* 3.0 4.0 5.0) ⇒ 60.0
(apply fl* '(1.0 2.0 3.0 4.0 5.0)) ⇒ 120.0
procedure 

returns 
the multiplicative inverse of 
procedure 

returns 
the result of dividing 
libraries 

(fl/ 4.0) ⇒ 0.25
(fl/ 8.0 2.0) ⇒ 4.0
(fl/ 9.0 2.0) ⇒ 4.5
(fl/ 60.0 5.0 3.0 2.0) ⇒ 2.0
procedure 

procedure 

procedure 

returns 
see below 
libraries 

These are flonumspecific versions of the generic div
, mod
, and divandmod
.
(fldiv 17.0 3.0) ⇒ 5.0
(flmod 17.0 3.0) ⇒ 2.0
(fldiv 17.0 3.0) ⇒ 6.0
(flmod 17.0 3.0) ⇒ 1.0
(fldiv 17.0 3.0) ⇒ 5.0
(flmod 17.0 3.0) ⇒ 2.0
(fldiv 17.0 3.0) ⇒ 6.0
(flmod 17.0 3.0) ⇒ 1.0
(fldivandmod 17.5 3.75) ⇒ 4.0
2.5
procedure 

procedure 

procedure 

returns 
see below 
libraries 

These are flonumspecific versions of the generic div0
, mod0
, and div0andmod0
.
(fldiv0 17.0 3.0) ⇒ 6.0
(flmod0 17.0 3.0) ⇒ 1.0
(fldiv0 17.0 3.0) ⇒ 6.0
(flmod0 17.0 3.0) ⇒ 1.0
(fldiv0 17.0 3.0) ⇒ 6.0
(flmod0 17.0 3.0) ⇒ 1.0
(fldiv0 17.0 3.0) ⇒ 6.0
(flmod0 17.0 3.0) ⇒ 1.0
(fldiv0andmod0 17.5 3.75) ⇒ 5.0
1.25
procedure 

returns 
the integer closest to 
procedure 

returns 
the integer closest to 
procedure 

returns 
the integer closest to 
procedure 

returns 
the integer closest to 
libraries 

If fl
is an integer, NaN, or infinity, each of these procedures returns fl
. If fl
is exactly between two integers, flround
returns the closest even integer.
(flround 17.3) ⇒ 17.0
(flround 17.3) ⇒ 17.0
(flround 2.5) ⇒ 2.0
(flround 3.5) ⇒ 4.0
(fltruncate 17.3) ⇒ 17.0
(fltruncate 17.3) ⇒ 17.0
(flfloor 17.3) ⇒ 17.0
(flfloor 17.3) ⇒ 18.0
(flceiling 17.3) ⇒ 18.0
(flceiling 17.3) ⇒ 17.0
procedure 

returns 
the numerator of 
procedure 

returns 
the denominator of 
libraries 

If fl
is an integer, including 0.0, or infinity, the numerator is fl
and the denominator is 1.0.
(flnumerator 9.0) ⇒ 9.0
(fldenominator 9.0) ⇒ 1.0
(flnumerator 0.0) ⇒ 0.0
(fldenominator 0.0) ⇒ 1.0
(flnumerator inf.0) ⇒ inf.0
(fldenominator inf.0) ⇒ 1.0
The following hold for IEEE floats, but not necessarily other flonum representations.
(flnumerator 3.5) ⇒ 7.0
(fldenominator 3.5) ⇒ 2.0
procedure 

returns 
absolute value of 
libraries 

(flabs 3.2) ⇒ 3.2
(flabs 2e20) ⇒ 2e20
procedure 

returns 
e to the 
procedure 

returns 
the natural logarithm of 
procedure 

returns 
the base 
libraries 

(flexp 0.0) ⇒ 1.0
(flexp 1.0) ⇒ 2.7182818284590455
(fllog 1.0) ⇒ 0.0
(fllog (exp 1.0)) ⇒ 1.0
(fl/ (fllog 100.0) (fllog 10.0)) ⇒ 2.0
(fllog 100.0 10.0) ⇒ 2.0
(fllog .125 2.0) ⇒ 3.0
procedure 

returns 
the sine of 
procedure 

returns 
the cosine of 
procedure 

returns 
the tangent of 
libraries 

procedure 

returns 
the arc sine of 
procedure 

returns 
the arc cosine of 
procedure 

returns 
the arc tangent of 
procedure 

returns 
the arc tangent of 
libraries 

procedure 

returns 
the principal square root of 
libraries 

Returns the principal square root of fl
. The square root of 0.0 should be 0.0. The result for other negative numbers may be a NaN or some other unspecified flonum.
(flsqrt 4.0) ⇒ 2.0
(flsqrt 0.0) ⇒ 0.0
(flsqrt 0.0) ⇒ 0.0
procedure 

returns 

libraries 

If fl_{1}
is negative and fl_{2}
is not an integer, the result may be a NaN or some other unspecified flonum. If fl_{1}
and fl_{2}
are both zero, the result is 1.0. If fl_{1}
is zero and fl_{2}
is positive, the result is zero. In other cases where fl_{1}
is zero, the result may be a NaN or some other unspecified flonum.
(flexpt 3.0 2.0) ⇒ 9.0
(flexpt 0.0 +inf.0) ⇒ 0.0
procedure 

returns 
the flonum representation closest to 
procedure 

returns 
the flonum representation closest to 
libraries 

fixnum>flonum
is a restricted variant of inexact
. real>flonum
is a restricted variant of inexact
when the input is an exact real; when it is an inexact nonflonum real, it coverts the inexact nonflonum real into the closest flonum.
(fixnum>flonum 0) ⇒ 0.0
(fixnum>flonum 13) ⇒ 13.0
(real>flonum 1/2) ⇒ 0.5
(real>flonum 1s3) ⇒ 1000.0
Section 6.7. Characters
Characters are atomic objects representing letters, digits, special symbols such as $
or 
, and certain nongraphic control characters such as space and newline. Characters are written with a #\
prefix. For most characters, the prefix is followed by the character itself. The written character representation of the letter A
, for example, is #\A
. The characters newline, space, and tab may be written in this manner as well, but they can be written more clearly as #\newline
, #\space
, and #\tab
. Other character names are supported as well, as defined by the grammar for character objects on page 457. Any Unicode character may be written with the syntax #\xn
, where n
consists of one or more hexadecimal digits and represents a valid Unicode scalar value.
This section describes the operations that deal primarily with characters. See also the following section on strings and Chapter 7 on input and output for other operations relating to characters.
procedure 

procedure 

procedure 

procedure 

procedure 

returns 

libraries 

These predicates behave in a similar manner to the numeric predicates =
, <
, >
, <=
, and >=
. For example, char=?
returns #t
when its arguments are equivalent characters, and char<?
returns #t
when its arguments are monotonically increasing character (Unicode scalar) values.
(char>? #\a #\b) ⇒ #f
(char<? #\a #\b) ⇒ #t
(char<? #\a #\b #\c) ⇒ #t
(let ([c #\r])
(char<=? #\a c #\z)) ⇒ #t
(char<=? #\Z #\W) ⇒ #f
(char=? #\+ #\+) ⇒ #t
procedure 

procedure 

procedure 

procedure 

procedure 

returns 

libraries 

These predicates are identical to the predicates char=?
, char<?
, char>?
, char<=?
, and char>=?
except that they are caseinsensitive, i.e., compare the casefolded versions of their arguments. For example, char=?
considers #\a
and #\A
to be distinct values; charci=?
does not.
(charci<? #\a #\B) ⇒ #t
(charci=? #\W #\w) ⇒ #t
(charci=? #\= #\+) ⇒ #f
(let ([c #\R])
(list (char<=? #\a c #\z)
(charci<=? #\a c #\z))) ⇒ (#f #t)
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

A character is alphabetic if it has the Unicode "Alphabetic" property, numeric if it has the Unicode "Numeric" property, and whitespace if has the Unicode "White_Space" property.
(charalphabetic? #\a) ⇒ #t
(charalphabetic? #\T) ⇒ #t
(charalphabetic? #\8) ⇒ #f
(charalphabetic? #\$) ⇒ #f
(charnumeric? #\7) ⇒ #t
(charnumeric? #\2) ⇒ #t
(charnumeric? #\X) ⇒ #f
(charnumeric? #\space) ⇒ #f
(charwhitespace? #\space) ⇒ #t
(charwhitespace? #\newline) ⇒ #t
(charwhitespace? #\Z) ⇒ #f
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

A character is uppercase if it has the Unicode "Uppercase" property, lowercase if it has the "Lowercase" property, and titlecase if it is in the Lt general category.
(charlowercase? #\r) ⇒ #t
(charlowercase? #\R) ⇒ #f
(charuppercase? #\r) ⇒ #f
(charuppercase? #\R) ⇒ #t
(chartitlecase? #\I) ⇒ #f
(chartitlecase? #\x01C5) ⇒ #t
procedure 

returns 
a symbol representing the Unicode general category of 
libraries 

The return value is one of the symbols Lu
, Ll
, Lt
, Lm
, Lo
, Mn
, Mc
, Me
, Nd
, Nl
, No
, Ps
, Pe
, Pi
, Pf
, Pd
, Pc
, Po
, Sc
, Sm
, Sk
, So
, Zs
, Zp
, Zl
, Cc
, Cf
, Cs
, Co
, or Cn
.
(chargeneralcategory #\a) ⇒ Ll
(chargeneralcategory #\space) ⇒ Zs
(chargeneralcategory #\x10FFFF) ⇒ Cn
procedure 

returns 
the uppercase character counterpart of 
libraries 

If char
is a lower or titlecase character and has a single uppercase counterpart, charupcase
returns the uppercase counterpart. Otherwise charupcase
returns char
.
(charupcase #\g) ⇒ #\G
(charupcase #\G) ⇒ #\G
(charupcase #\7) ⇒ #\7
(charupcase #\ς) ⇒ #\Σ
procedure 

returns 
the lowercase character equivalent of 
libraries 

If char
is an upper or titlecase character and has a single lowercase counterpart, chardowncase
returns the lowercase counterpart. Otherwise chardowncase
returns char
.
(chardowncase #\g) ⇒ #\g
(chardowncase #\G) ⇒ #\g
(chardowncase #\7) ⇒ #\7
(chardowncase #\ς) ⇒ #\ς
procedure 

returns 
the titlecase character equivalent of 
libraries 

If char
is an upper or lowercase character and has a single titlecase counterpart, chartitlecase
returns the titlecase counterpart. Otherwise, if it is not a titlecase character, has no single titlecase counterpart, but does have a single uppercase counterpart, chartitlecase
returns the uppercase counterpart. Otherwise chartitlecase
returns char
.
(chartitlecase #\g) ⇒ #\G
(chartitlecase #\G) ⇒ #\G
(chartitlecase #\7) ⇒ #\7
(chartitlecase #\ς) ⇒ #\Σ
procedure 

returns 
the casefolded character equivalent of 
libraries 

If char
has a casefolded counterpart, charfoldcase
returns the casefolded counterpart. Otherwise, charfoldcase
returns char
. For most characters, (charfoldcase char)
is equivalent to (chardowncase (charupcase char))
, but for Turkic İ and ı, charfoldcase
acts as the identity.
(charfoldcase #\g) ⇒ #\g
(charfoldcase #\G) ⇒ #\g
(charfoldcase #\7) ⇒ #\7
(charfoldcase #\ς) ⇒ #\σ
procedure 

returns 
the Unicode scalar value of 
libraries 

(char>integer #\newline) ⇒ 10
(char>integer #\space) ⇒ 32
( (char>integer #\Z) (char>integer #\A)) ⇒ 25
procedure 

returns 
the character corresponding to the Unicode scalar value 
libraries 

n
must be an exact integer and a valid Unicode scalar value, i.e., \(0 \le n \le \#xD7FF\) or \(\#xE000 \le n \le 10FFFF\).
(integer>char 48) ⇒ #\0
(integer>char #x3BB) ⇒ #\λ
Section 6.8. Strings
Strings are sequences of characters and are often used as messages, character buffers, or containers for blocks of text. Scheme provides operations for creating strings, extracting characters from strings, obtaining substrings, concatenating strings, and altering the contents of strings.
A string is written as a sequence of characters enclosed in double quotes, e.g., "hi there"
. A double quote may be introduced into a string by preceding it by a backward slash, e.g., "two \"quotes\" within"
. A backward slash may also be included by preceding it with a backward slash, e.g., "a \\slash"
. Various special characters can be inserted with other twocharacter sequences, e.g., \n
for newline, \r
for carriage return, and \t
for tab. Any Unicode character may be inserted with the syntax #\xn;
, where n
consists of one or more hexadecimal digits and represents a valid Unicode scalar value. A grammar defining the precise syntax of strings is given on page 458.
Strings are indexed by exact nonnegative integers, and the index of the first element of any string is 0. The highest valid index for a given string is one less than its length.
procedure 

procedure 

procedure 

procedure 

procedure 

returns 

libraries 

As with =
, <
, >
, <=
, and >=
, these predicates express relationships among all of the arguments. For example, string>?
determines if the lexicographic ordering of its arguments is monotonically decreasing.
The comparisons are based on the character predicates char=?
and char<?
. Two strings are lexicographically equivalent if they are the same length and consist of the same sequence of characters according to char=?
. If two strings differ only in length, the shorter string is considered to be lexicographically less than the longer string. Otherwise, the first character position at which the strings differ (by char=?
) determines which string is lexicographically less than the other, according to char<?
.
Twoargument string=?
may be defined without error checks as follows.
(define string=?
(lambda (s1 s2)
(let ([n (stringlength s1)])
(and (= (stringlength s2) n)
(let loop ([i 0])
(or (= i n)
(and (char=? (stringref s1 i) (stringref s2 i))
(loop (+ i 1)))))))))
Twoargument string<?
may be defined without error checks as follows.
(define string<?
(lambda (s1 s2)
(let ([n1 (stringlength s1)] [n2 (stringlength s2)])
(let loop ([i 0])
(and (not (= i n2))
(or (= i n1)
(let ([c1 (stringref s1 i)] [c2 (stringref s2 i)])
(or (char<? c1 c2)
(and (char=? c1 c2)
(loop (+ i 1)))))))))))
These definitions may be extended straightforwardly to support three or more arguments. string<=?
, string>?
, and string>=?
may be defined similarly.
(string=? "mom" "mom") ⇒ #t
(string<? "mom" "mommy") ⇒ #t
(string>? "Dad" "Dad") ⇒ #f
(string=? "Mom and Dad" "mom and dad") ⇒ #f
(string<? "a" "b" "c") ⇒ #t
procedure 

procedure 

procedure 

procedure 

procedure 

returns 

libraries 

These predicates are identical to string=?
, string<?
, string>?
, string<=?
, and string>=?
except that they are caseinsensitive, i.e., compare the casefolded versions of their arguments.
(stringci=? "Mom and Dad" "mom and dad") ⇒ #t
(stringci<=? "say what" "Say What!?") ⇒ #t
(stringci>? "N" "m" "L" "k") ⇒ #t
(stringci=? "Straße" "Strasse") ⇒ #t
procedure 

returns 
a string containing the characters 
libraries 

(string) ⇒ ""
(string #\a #\b #\c) ⇒ "abc"
(string #\H #\E #\Y #\!) ⇒ "HEY!"
procedure 

procedure 

returns 
a string of length 
libraries 

n
must be an exact nonnegative integer. If char
is supplied, the string is filled with n
occurrences of char
, otherwise the characters contained in the string are unspecified.
(makestring 0) ⇒ ""
(makestring 0 #\x) ⇒ ""
(makestring 5 #\x) ⇒ "xxxxx"
procedure 

returns 
the number of characters in 
libraries 

The length of a string is always an exact nonnegative integer.
(stringlength "abc") ⇒ 3
(stringlength "") ⇒ 0
(stringlength "hi there") ⇒ 8
(stringlength (makestring 1000000)) ⇒ 1000000
procedure 

returns 
the 
libraries 

n
must be an exact nonnegative integer less than the length of string
.
(stringref "hi there" 0) ⇒ #\h
(stringref "hi there" 5) ⇒ #\e
procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer less than the length of string
. stringset!
changes the n
th element of string
to char
.
(let ([str (stringcopy "hi three")])
(stringset! str 5 #\e)
(stringset! str 6 #\r)
str) ⇒ "hi there"
procedure 

returns 
a new copy of 
libraries 

This procedure creates a new string with the same length and contents as string
.
(stringcopy "abc") ⇒ "abc"
(let ([str "abc"])
(eq? str (stringcopy str))) ⇒ #f
procedure 

returns 
a new string formed by concatenating the strings 
libraries 

(stringappend) ⇒ ""
(stringappend "abc" "def") ⇒ "abcdef"
(stringappend "Hey " "you " "there!") ⇒ "Hey you there!"
The following implementation of stringappend
recurs down the list of strings to compute the total length, then allocates the new string, then fills it up as it unwinds the recursion.
(define stringappend
(lambda args
(let f ([ls args] [n 0])
(if (null? ls)
(makestring n)
(let* ([s1 (car ls)]
[m (stringlength s1)]
[s2 (f (cdr ls) (+ n m))])
(do ([i 0 (+ i 1)] [j n (+ j 1)])
((= i m) s2)
(stringset! s2 j (stringref s1 i))))))))
procedure 

returns 
a copy of 
libraries 

start
and end
must be exact nonnegative integers; start
must be less than or equal to end
, while end
must be less than or equal to the length of string
. If end
= start
, a string of length zero is returned. substring
may be defined without error checks as follows.
(define substring
(lambda (s1 m n)
(let ([s2 (makestring ( n m))])
(do ([j 0 (+ j 1)] [i m (+ i 1)])
((= i n) s2)
(stringset! s2 j (stringref s1 i))))))
(substring "hi there" 0 1) ⇒ "h"
(substring "hi there" 3 6) ⇒ "the"
(substring "hi there" 5 5) ⇒ ""
(let ([str "hi there"])
(let ([end (stringlength str)])
(substring str 0 end))) ⇒ "hi there"
procedure 

returns 
unspecified 
libraries 

stringfill!
sets every character in string
to char
.
(let ([str (stringcopy "sleepy")])
(stringfill! str #\Z)
str) ⇒ "ZZZZZZ"
stringfill!
might be defined as follows:
(define stringfill!
(lambda (s c)
(let ([n (stringlength s)])
(do ([i 0 (+ i 1)])
((= i n))
(stringset! s i c)))))
An alternative definition is given on page 276.
procedure 

returns 
the uppercase equivalent of 
procedure 

returns 
the lowercase equivalent of 
procedure 

returns 
the casefolded equivalent of 
procedure 

returns 
the titlecase equivalent of 
libraries 

These procedures implement Unicode’s localeindependent case mappings from scalarvalue sequences to scalarvalue sequences. These mappings do not always map single characters to single characters, so the length of the result string may differ from the length of string
. If the result string is the same as string
(by string=?
), string
or a copy of string
may be returned. Otherwise, the result string is newly allocated. stringfoldcase
does not use the special mappings for Turkic languages.
stringtitlecase
converts the first cased character of each word in string
to its titlecase counterpart and converts each other character to its lowercase counterpart. Word breaks are recognized as specified in Unicode Standard Annex #29 [8].
(stringupcase "Hi") ⇒ "HI"
(stringdowncase "Hi") ⇒ "hi"
(stringfoldcase "Hi") ⇒ "hi"
(stringupcase "Straße") ⇒ "STRASSE"
(stringdowncase "Straße") ⇒ "straße"
(stringfoldcase "Straße") ⇒ "strasse"
(stringdowncase "STRASSE") ⇒ "strasse"
(stringdowncase "Σ") ⇒ "σ"
(stringtitlecase "kNock KNoCK") ⇒ "Knock Knock"
(stringtitlecase "who's there?") ⇒ "Who's There?"
(stringtitlecase "r6rs") ⇒ "R6rs"
(stringtitlecase "R6RS") ⇒ "R6rs"
procedure 

returns 
the Unicode normalized form D of 
procedure 

returns 
the Unicode normalized form KD of 
procedure 

returns 
the Unicode normalized form C of 
procedure 

returns 
the Unicode normalized form KC of 
libraries 

If the result string is the same as string
(by string=?
), string
or a copy of string
may be returned. Otherwise, the result string is newly allocated.
(stringnormalizenfd "\xE9;") ⇒ "e\x301;"
(stringnormalizenfc "\xE9;") ⇒ "\xE9;"
(stringnormalizenfd "\x65;\x301;") ⇒ "e\x301;"
(stringnormalizenfc "\x65;\x301;") ⇒ "\xE9;"
procedure 

returns 
a list of the characters in 
libraries 

string>list
allows a string to be converted into a list, so that Scheme’s listprocessing operations may be applied to the processing of strings. string>list
may be defined without error checks as follows.
(define string>list
(lambda (s)
(do ([i ( (stringlength s) 1) ( i 1)]
[ls '() (cons (stringref s i) ls)])
((< i 0) ls))))
(string>list "") ⇒ ()
(string>list "abc") ⇒ (#\a #\b #\c)
(apply char<? (string>list "abc")) ⇒ #t
(map charupcase (string>list "abc")) ⇒ (#\A #\B #\C)
procedure 

returns 
a string of the characters in 
libraries 

list
must consist entirely of characters.
list>string
is the functional inverse of string>list
. A program might use both procedures together, first converting a string into a list, then operating on this list to produce a new list, and finally converting the new list back into a string.
list>string
may be defined without error checks as follows.
(define list>string
(lambda (ls)
(let ([s (makestring (length ls))])
(do ([ls ls (cdr ls)] [i 0 (+ i 1)])
((null? ls) s)
(stringset! s i (car ls))))))
(list>string '()) ⇒ ""
(list>string '(#\a #\b #\c)) ⇒ "abc"
(list>string
(map charupcase
(string>list "abc"))) ⇒ "ABC"
Section 6.9. Vectors
Vectors are more convenient and efficient than lists for some applications. Whereas accessing an arbitrary element in a list requires a linear traversal of the list up to the selected element, arbitrary vector elements are accessed in constant time. The length of a vector is the number of elements it contains. Vectors are indexed by exact nonnegative integers, and the index of the first element of any vector is 0. The highest valid index for a given vector is one less than its length.
As with lists, the elements of a vector can be of any type, and a single vector can hold more than one type of object.
A vector is written as a sequence of objects separated by whitespace, preceded by the prefix #(
and followed by )
. For example, a vector consisting of the elements a
, b
, and c
would be written #(a b c)
.
procedure 

returns 
a vector of the objects 
libraries 

(vector) ⇒ #()
(vector 'a 'b 'c) ⇒ #(a b c)
procedure 

procedure 

returns 
a vector of length 
libraries 

n
must be an exact nonnegative integer. If obj
is supplied, each element of the vector is filled with obj
; otherwise, the elements are unspecified.
(makevector 0) ⇒ #()
(makevector 0 '#(a)) ⇒ #()
(makevector 5 '#(a)) ⇒ #(#(a) #(a) #(a) #(a) #(a))
procedure 

returns 
the number of elements in 
libraries 

The length of a vector is always an exact nonnegative integer.
(vectorlength '#()) ⇒ 0
(vectorlength '#(a b c)) ⇒ 3
(vectorlength (vector 1 '(2) 3 '#(4 5))) ⇒ 4
(vectorlength (makevector 300)) ⇒ 300
procedure 

returns 
the 
libraries 

n
must be an exact nonnegative integer less than the length of vector
.
(vectorref '#(a b c) 0) ⇒ a
(vectorref '#(a b c) 1) ⇒ b
(vectorref '#(x y z w) 3) ⇒ w
procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer less than the length of vector
. vectorset!
changes the n
th element of vector
to obj
.
(let ([v (vector 'a 'b 'c 'd 'e)])
(vectorset! v 2 'x)
v) ⇒ #(a b x d e)
procedure 

returns 
unspecified 
libraries 

vectorfill!
replaces each element of vector
with obj
. It may be defined without error checks as follows.
(define vectorfill!
(lambda (v x)
(let ([n (vectorlength v)])
(do ([i 0 (+ i 1)])
((= i n))
(vectorset! v i x)))))
(let ([v (vector 1 2 3)])
(vectorfill! v 0)
v) ⇒ #(0 0 0)
procedure 

returns 
a list of the elements of 
libraries 

vector>list
provides a convenient method for applying listprocessing operations to vectors. It may be defined without error checks as follows.
(define vector>list
(lambda (s)
(do ([i ( (vectorlength s) 1) ( i 1)]
[ls '() (cons (vectorref s i) ls)])
((< i 0) ls))))
(vector>list (vector)) ⇒ ()
(vector>list '#(a b c)) ⇒ (a b c)
(let ((v '#(1 2 3 4 5)))
(apply * (vector>list v))) ⇒ 120
procedure 

returns 
a vector of the elements of 
libraries 

list>vector
is the functional inverse of vector>list
. The two procedures are often used in combination to take advantage of a listprocessing operation. A vector may be converted to a list with vector>list
, this list processed in some manner to produce a new list, and the new list converted back into a vector with list>vector
.
list>vector
may be defined without error checks as follows.
(define list>vector
(lambda (ls)
(let ([s (makevector (length ls))])
(do ([ls ls (cdr ls)] [i 0 (+ i 1)])
((null? ls) s)
(vectorset! s i (car ls))))))
(list>vector '()) ⇒ #()
(list>vector '(a b c)) ⇒ #(a b c)
(let ([v '#(1 2 3 4 5)])
(let ([ls (vector>list v)])
(list>vector (map * ls ls)))) ⇒ #(1 4 9 16 25)
procedure 

returns 
a vector containing the elements of 
procedure 

returns 
unspecified 
libraries 

predicate
should be a procedure that expects two arguments and returns #t
if its first argument must precede its second in the sorted vector. That is, if predicate
is applied to two elements x
and y
, where x
appears after y
in the input vector, the predicate should return true only if x
should appear before y
in the output vector. If this constraint is met, vectorsort
performs a stable sort, i.e., two elements are reordered only when necessary according to predicate
. vectorsort!
performs the sort destructively and does not necessarily perform a stable sort. Duplicate elements are not removed. predicate
should not have any side effects.
vectorsort
may call predicate
up to \(n\log{n}\) times, where n is the length of vector
, while vectorsort!
may call the predicate up to \(n^2\) times. The looser bound for vectorsort!
allows an implementation to use a quicksort algorithm, which may be faster in some cases than algorithms that have the tighter \(n\log{n}\) bound.
(vectorsort < '#(3 4 2 1 2 5)) ⇒ #(1 2 2 3 4 5)
(vectorsort > '#(0.5 1/2)) ⇒ #(0.5 1/2)
(vectorsort > '#(1/2 0.5)) ⇒ #(1/2 0.5)
(let ([v (vector 3 4 2 1 2 5)])
(vectorsort! < v)
v) ⇒ #(1 2 2 3 4 5)
Section 6.10. Bytevectors
Bytevectors are vectors of raw binary data. Although nominally organized as a sequence of exact unsigned 8bit integers, a bytevector can be interpreted as a sequence of exact signed 8bit integers, exact signed or unsigned 16bit, 32bit, 64bit, or arbitraryprecision integers, IEEE single or double floatingpoint numbers, or arbitrary combinations of the above.
The length of a bytevector is the number of 8bit bytes it stores, and indices into a bytevector are always given as byte offsets. Any data element may be aligned at any byte offset, regardless of the underlying hardware’s alignment requirements, and may be represented using a specified endianness (see below) that differs from that prescribed by the hardware. Special, typically more efficient operators are provided for 16, 32, and 64bit integers and single and double floats that are in their native format, i.e,. with the endianness of the underlying hardware and stored at an index that is a multiple of the size in bytes of the integer or float.
The endianness of a multibyte data value determines how it is laid out in memory. In bigendian format, the value is laid out with the more significant bytes at lower indices, while in littleendian format, the value is laid out with the more significant bytes at higher indices. When a bytevector procedure accepts an endianness argument, the argument may be the symbol big
, representing the bigendian format, or the symbol little
, representing the littleendian format. Implementations may extend these procedures to accept other endianness symbols. The native endianness of the implementation may be obtained via the procedure nativeendianness
.
Bytevectors are written with the #vu8(
prefix in place of the #(
prefix for vectors, e.g., #vu8(1 2 3)
. The elements of a bytevector specified in this manner are always given as 8bit unsigned exact integers, i.e., integers from 0 to 255 inclusive, written using any valid syntax for such numbers. Like strings, bytevectors are selfevaluating, so they need not be quoted.
'#vu8(1 2 3) ⇒ #vu8(1 2 3)
#vu8(1 2 3) ⇒ #vu8(1 2 3)
#vu8(#x3f #x7f #xbf #xff) ⇒ #vu8(63 127 191 255)
syntax 

returns 

libraries 

symbol
must be the symbol little
, the symbol big
, or some other symbol recognized by the implementation as an endianness symbol. It is a syntax violation if symbol
is not a symbol or if it is not recognized by the implementation as an endianness symbol.
(endianness little) ⇒ little
(endianness big) ⇒ big
(endianness "spam") ⇒ exception
procedure 

returns 
a symbol naming the implementation’s native endianness 
libraries 

The return value is the symbol little
, the symbol big
, or some other endianness symbol recognized by the implementation. It typically reflects the endianness of the underlying hardware.
(symbol? (nativeendianness)) ⇒ #t
procedure 

procedure 

returns 
a new bytevector of length 
libraries 

If fill
is supplied, each element of the bytevector is initialized to fill
; otherwise, the elements are unspecified. The fill
value must be a signed or unsigned 8bit value, i.e., a value in the range 128 to 255 inclusive. A negative fill value is treated as its two’s complement equivalent.
(makebytevector 0) ⇒ #vu8()
(makebytevector 0 7) ⇒ #vu8()
(makebytevector 5 7) ⇒ #vu8(7 7 7 7 7)
(makebytevector 5 7) ⇒ #vu8(249 249 249 249 249)
procedure 

returns 
the length of 
libraries 

(bytevectorlength #vu8()) ⇒ 0
(bytevectorlength #vu8(1 2 3)) ⇒ 3
(bytevectorlength (makebytevector 300)) ⇒ 300
procedure 

returns 

libraries 

Two bytevectors are equal by bytevector=?
if and only if they have the same length and same contents.
(bytevector=? #vu8() #vu8()) ⇒ #t
(bytevector=? (makebytevector 3 0) #vu8(0 0 0)) ⇒ #t
(bytevector=? (makebytevector 5 0) #vu8(0 0 0)) ⇒ #f
(bytevector=? #vu8(1 127 128 255) #vu8(255 128 127 1)) ⇒ #f
procedure 

returns 
unspecified 
libraries 

The fill
value must be a signed or unsigned 8bit value, i.e., a value in the range 128 to 255 inclusive. A negative fill value is treated as its two’s complement equivalent.
bytevectorfill!
replaces each element of bytevector
with fill
.
(let ([v (makebytevector 6)])
(bytevectorfill! v 255)
v) ⇒ #vu8(255 255 255 255 255 255)
(let ([v (makebytevector 6)])
(bytevectorfill! v 128)
v) ⇒ #vu8(128 128 128 128 128 128)
procedure 

returns 
a new bytevector that is a copy of 
libraries 

bytevectorcopy
creates a new bytevector with the same length and contents as bytevector
.
(bytevectorcopy #vu8(1 127 128 255)) ⇒ #vu8(1 127 128 255)
(let ([v #vu8(1 127 128 255)])
(eq? v (bytevectorcopy v))) ⇒ #f
procedure 

returns 
unspecified 
libraries 

src
and dst
must be bytevectors. srcstart
, dststart
, and n
must be exact nonnegative integers. The sum of srcstart
and n
must not exceed the length of src
, and the sum of dststart
and n
must not exceed the length of dst
.
bytevectorcopy!
overwrites the n
bytes of dst
starting at dststart
with the n
bytes of src
starting at srcstart
. This works even if dst
is the same bytevector as src
and the source and destination locations overlap. That is, the destination is filled with the bytes that appeared at the source before the operation began.
(define v1 #vu8(31 63 95 127 159 191 223 255))
(define v2 (makebytevector 10 0))
(bytevectorcopy! v1 2 v2 1 4)
v2 ⇒ #vu8(0 95 127 159 191 0 0 0 0 0)
(bytevectorcopy! v1 5 v2 7 3)
v2 ⇒ #vu8(0 95 127 159 191 0 0 191 223 255)
(bytevectorcopy! v2 3 v2 0 6)
v2 ⇒ #vu8(159 191 0 0 191 223 0 191 223 255)
(bytevectorcopy! v2 0 v2 1 9)
v2 ⇒ #vu8(159 159 191 0 0 191 223 0 191 223)
procedure 

returns 
the 8bit unsigned byte at index 
libraries 

n
must be an exact nonnegative integer less than the length of bytevector
.
The value is returned as an exact 8bit unsigned integer, i.e., a value in the range 0 to 255 inclusive.
(bytevectoru8ref #vu8(1 127 128 255) 0) ⇒ 1
(bytevectoru8ref #vu8(1 127 128 255) 2) ⇒ 128
(bytevectoru8ref #vu8(1 127 128 255) 3) ⇒ 255
procedure 

returns 
the 8bit signed byte at index 
libraries 

n
must be an exact nonnegative integer less than the length of bytevector
.
The value returned is an exact 8bit signed integer, i.e., a value in the range 128 to 127 inclusive, and is the equivalent of the stored value treated as a two’s complement value.
(bytevectors8ref #vu8(1 127 128 255) 0) ⇒ 1
(bytevectors8ref #vu8(1 127 128 255) 1) ⇒ 127
(bytevectors8ref #vu8(1 127 128 255) 2) ⇒ 128
(bytevectors8ref #vu8(1 127 128 255) 3) ⇒ 1
procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer less than the length of bytevector
. u8
must be an 8bit unsigned value, i.e., a value in the range 0 to 255 inclusive.
bytevectoru8set!
changes the 8bit value at index n
(zerobased) of bytevector
to u8
.
(let ([v (makebytevector 5 1)])
(bytevectoru8set! v 2 128)
v) ⇒ #vu8(255 255 128 255 255)
procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer less than the length of bytevector
. s8
must be an 8bit signed value, i.e., a value in the range 128 to 127 inclusive.
bytevectors8set!
changes the 8bit value at index n
(zerobased) of bytevector
to the two’s complement equivalent of s8
.
(let ([v (makebytevector 4 0)])
(bytevectors8set! v 1 100)
(bytevectors8set! v 2 100)
v) ⇒ #vu8(0 100 156 0)
procedure 

returns 
a list of the 8bit unsigned elements of 
libraries 

(bytevector>u8list (makebytevector 0)) ⇒ ()
(bytevector>u8list #vu8(1 127 128 255)) ⇒ (1 127 128 255)
(let ([v #vu8(1 2 3 255)])
(apply * (bytevector>u8list v))) ⇒ 1530
procedure 

returns 
a new bytevector of the elements of 
libraries 

list
must consist entirely of exact 8bit unsigned integers, i.e., values in the range 0 to 255 inclusive.
(u8list>bytevector '()) ⇒ #vu8()
(u8list>bytevector '(1 127 128 255)) ⇒ #vu8(1 127 128 255)
(let ([v #vu8(1 2 3 4 5)])
(let ([ls (bytevector>u8list v)])
(u8list>bytevector (map * ls ls)))) ⇒ #vu8(1 4 9 16 25)
procedure 

returns 
the 16bit unsigned integer at index 
procedure 

returns 
the 16bit signed integer at index 
procedure 

returns 
the 32bit unsigned integer at index 
procedure 

returns 
the 32bit signed integer at index 
procedure 

returns 
the 64bit unsigned integer at index 
procedure 

returns 
the 64bit signed integer at index 
libraries 

n
must be an exact nonnegative integer. It indexes the starting byte of the value and must be a multiple of the number of bytes occupied by the value: 2 for 16bit values, 4 for 32bit values, and 8 for 64bit values. The sum of n
and the number of bytes occupied by the value must not exceed the length of bytevector
. The native endianness is assumed.
The return value is an exact integer in the appropriate range for the number of bytes occupied by the value. Signed values are the equivalent of the stored value treated as a two’s complement value.
(define v #vu8(#x12 #x34 #xfe #x56 #xdc #xba #x78 #x98))
If native endianness is big:
(bytevectoru16nativeref v 2) ⇒ #xfe56
(bytevectors16nativeref v 2) ⇒ #x1aa
(bytevectors16nativeref v 6) ⇒ #x7898
(bytevectoru32nativeref v 0) ⇒ #x1234fe56
(bytevectors32nativeref v 0) ⇒ #x1234fe56
(bytevectors32nativeref v 4) ⇒ #x23458768
(bytevectoru64nativeref v 0) ⇒ #x1234fe56dcba7898
(bytevectors64nativeref v 0) ⇒ #x1234fe56dcba7898
If native endianness is little:
(bytevectoru16nativeref v 2) ⇒ #x56fe
(bytevectors16nativeref v 2) ⇒ #x56fe
(bytevectors16nativeref v 6) ⇒ #x6788
(bytevectoru32nativeref v 0) ⇒ #x56fe3412
(bytevectors32nativeref v 0) ⇒ #x56fe3412
(bytevectors32nativeref v 4) ⇒ #x67874524
(bytevectoru64nativeref v 0) ⇒ #x9878badc56fe3412
(bytevectors64nativeref v 0) ⇒ #x67874523a901cbee
procedure 

procedure 

procedure 

procedure 

procedure 

procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer. It indexes the starting byte of the value and must be a multiple of the number of bytes occupied by the value: 2 for 16bit values, 4 for 32bit values, and 8 for 64bit values. The sum of n
and the number of bytes occupied by the value must not exceed the length bytevector
. u16
must be a 16bit unsigned value, i.e., a value in the range 0 to \(2^{16}  1\) inclusive; s16
must be a 16bit signed value, i.e., a value in the range \(2^{15}\) to \(2^{15}  1\) inclusive; u32
must be a 32bit unsigned value, i.e., a value in the range 0 to \(2^{32}  1\) inclusive; s32
must be a 32bit signed value, i.e., a value in the range \(2^{31}\) to \(2^{31}  1\) inclusive; u64
must be a 64bit unsigned value, i.e., a value in the range \(0\) to \(2^{64}  1\) inclusive; and s64
must be a 64bit signed value, i.e., a value in the range \(2^{63}\) to \(2^{63}  1\) inclusive. The native endianness is assumed.
These procedures store the given value in the 2, 4, or 8 bytes starting at index n
(zerobased) of bytevector
. Negative values are stored as their two’s complement equivalent.
(define v (makebytevector 8 0))
(bytevectoru16nativeset! v 0 #xfe56)
(bytevectors16nativeset! v 2 #x1aa)
(bytevectors16nativeset! v 4 #x7898)
If native endianness is big:
v ⇒ #vu8(#xfe #x56 #xfe #x56 #x78 #x98 #x00 #x00)
If native endianness is little:
v ⇒ #vu8(#x56 #xfe #x56 #xfe #x98 #x78 #x00 #x00)
(define v (makebytevector 16 0))
(bytevectoru32nativeset! v 0 #x1234fe56)
(bytevectors32nativeset! v 4 #x1234fe56)
(bytevectors32nativeset! v 8 #x23458768)
If native endianness is big:
v ⇒ #vu8(#x12 #x34 #xfe #x56 #x12 #x34 #xfe #x56
#xdc #xba #x78 #x98 #x00 #x00 #x00 #x00)
If native endianness is little:
v ⇒ #vu8(#x56 #xfe #x34 #x12 #x56 #xfe #x34 #x12
#x98 #x78 #xba #xdc #x00 #x00 #x00 #x00)
(define v (makebytevector 24 0))
(bytevectoru64nativeset! v 0 #x1234fe56dcba7898)
(bytevectors64nativeset! v 8 #x1234fe56dcba7898)
(bytevectors64nativeset! v 16 #x67874523a901cbee)
If native endianness is big:
v ⇒ #vu8(#x12 #x34 #xfe #x56 #xdc #xba #x78 #x98
#x12 #x34 #xfe #x56 #xdc #xba #x78 #x98
#x98 #x78 #xba #xdc #x56 #xfe #x34 #x12)
If native endianness is little:
v ⇒ #vu8(#x98 #x78 #xba #xdc #x56 #xfe #x34 #x12
#x98 #x78 #xba #xdc #x56 #xfe #x34 #x12
#x12 #x34 #xfe #x56 #xdc #xba #x78 #x98)
procedure 

returns 
the 16bit unsigned integer at index 
procedure 

returns 
the 16bit signed integer at index 
procedure 

returns 
the 32bit unsigned integer at index 
procedure 

returns 
the 32bit signed integer at index 
procedure 

returns 
the 64bit unsigned integer at index 
procedure 

returns 
the 64bit signed integer at index 
libraries 

n
must be an exact nonnegative integer and indexes the starting byte of the value. The sum of n
and the number of bytes occupied by the value (2 for 16bit values, 4 for 32bit values, and 8 for 32bit values) must not exceed the length of bytevector
. n
need not be a multiple of the number of bytes occupied by the value. eness
must be a valid endianness symbol naming the endianness.
The return value is an exact integer in the appropriate range for the number of bytes occupied by the value. Signed values are the equivalent of the stored value treated as a two’s complement value.
(define v #vu8(#x12 #x34 #xfe #x56 #xdc #xba #x78 #x98 #x9a #x76))
(bytevectoru16ref v 0 (endianness big)) ⇒ #x1234
(bytevectors16ref v 1 (endianness big)) ⇒ #x34fe
(bytevectors16ref v 5 (endianness big)) ⇒ #x4588
(bytevectoru32ref v 2 'big) ⇒ #xfe56dcba
(bytevectors32ref v 3 'big) ⇒ #x56dcba78
(bytevectors32ref v 4 'big) ⇒ #x23458768
(bytevectoru64ref v 0 'big) ⇒ #x1234fe56dcba7898
(bytevectors64ref v 1 'big) ⇒ #x34fe56dcba78989a
(bytevectoru16ref v 0 (endianness little)) ⇒ #x3412
(bytevectors16ref v 1 (endianness little)) ⇒ #x1cc
(bytevectors16ref v 5 (endianness little)) ⇒ #x78ba
(bytevectoru32ref v 2 'little) ⇒ #xbadc56fe
(bytevectors32ref v 3 'little) ⇒ #x78badc56
(bytevectors32ref v 4 'little) ⇒ #x67874524
(bytevectoru64ref v 0 'little) ⇒ #x9878badc56fe3412
(bytevectors64ref v 1 'little) ⇒ #x6567874523a901cc
procedure 

procedure 

procedure 

procedure 

procedure 

procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer and indexes the starting byte of the value. The sum of n
and the number of bytes occupied by the value must not exceed the length of bytevector
. n
need not be a multiple of the number of bytes occupied by the value. u16
must be a 16bit unsigned value, i.e., a value in the range \(0\) to \(2^{16}  1\) inclusive; s16
must be a 16bit signed value, i.e., a value in the range \(2^{15}\) to \(2^{15}  1\) inclusive; u32
must be a 32bit unsigned value, i.e., a value in the range \(0\) to \(2^{32}  1\) inclusive; s32
must be a 32bit signed value, i.e., a value in the range \(2^{31}\) to \(2^{31}  1\) inclusive; u64
must be a 64bit unsigned value, i.e., a value in the range \(0\) to \(2^{64}  1\) inclusive; and s64
must be a 64bit signed value, i.e., a value in the range \(2^{63}\) to \(2^{63}  1\) inclusive. eness
must be a valid endianness symbol naming the endianness.
These procedures store the given value in the 2, 4, or 8 bytes starting at index n
(zerobased) of bytevector
. Negative values are stored as their two’s complement equivalent.
(define v (makebytevector 8 0))
(bytevectoru16set! v 0 #xfe56 (endianness big))
(bytevectors16set! v 3 #x1aa (endianness little))
(bytevectors16set! v 5 #x7898 (endianness big))
v ⇒ #vu8(#xfe #x56 #x0 #x56 #xfe #x78 #x98 #x0)
(define v (makebytevector 16 0))
(bytevectoru32set! v 0 #x1234fe56 'little)
(bytevectors32set! v 6 #x1234fe56 'big)
(bytevectors32set! v 11 #x23458768 'little)
v ⇒ #vu8(#x56 #xfe #x34 #x12 #x0 #x0
#x12 #x34 #xfe #x56 #x0
#x98 #x78 #xba #xdc #x0)
(define v (makebytevector 28 0))
(bytevectoru64set! v 0 #x1234fe56dcba7898 'little)
(bytevectors64set! v 10 #x1234fe56dcba7898 'big)
(bytevectors64set! v 19 #x67874523a901cbee 'big)
v ⇒ #vu8(#x98 #x78 #xba #xdc #x56 #xfe #x34 #x12 #x0 #x0
#x12 #x34 #xfe #x56 #xdc #xba #x78 #x98 #x0
#x98 #x78 #xba #xdc #x56 #xfe #x34 #x12 #x0)
procedure 

returns 
the 
procedure 

returns 
the 
libraries 

n
must be an exact nonnegative integer and indexes the starting byte of the value. size
must be an exact positive integer and specifies the number of bytes occupied by the value. The sum of n
and size
must not exceed the length of bytevector
. n
need not be a multiple of the number of bytes occupied by the value. eness
must be a valid endianness symbol naming the endianness.
The return value is an exact integer in the appropriate range for the number of bytes occupied by the value. Signed values are the equivalent of the stored value treated as a two’s complement value.
(define v #vu8(#x12 #x34 #xfe #x56 #xdc #xba #x78 #x98 #x9a #x76))
(bytevectoruintref v 0 'big 1) ⇒ #x12
(bytevectoruintref v 0 'little 1) ⇒ #x12
(bytevectoruintref v 1 'big 3) ⇒ #x34fe56
(bytevectoruintref v 2 'little 7) ⇒ #x9a9878badc56fe
(bytevectorsintref v 2 'big 1) ⇒ #x02
(bytevectorsintref v 1 'little 6) ⇒ #x78badc56fe34
(bytevectorsintref v 2 'little 7) ⇒ #x6567874523a902
(bytevectorsintref (makebytevector 1000 1) 0 'big 1000) ⇒ 1
procedure 

procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer and indexes the starting byte of the value. size
must be an exact positive integer and specifies the number of bytes occupied by the value. The sum of n
and size
must not exceed the length of bytevector
. n
need not be a multiple of the number of bytes occupied by the value. uint
must be an exact integer in the range \(0\) to \(2^{size \cdot 8}  1\) inclusive. sint
must be an exact integer in the range \(2^{size \cdot 8  1}\) to \(2^{size \cdot 8  1}  1\) inclusive. eness
must be a valid endianness symbol naming the endianness.
These procedures store the given value in the size
bytes starting at index n
(zerobased) of bytevector
. Negative values are stored as their two’s complement equivalent.
(define v (makebytevector 5 0))
(bytevectoruintset! v 1 #x123456 (endianness big) 3)
v ⇒ #vu8(0 #x12 #x34 #x56 0)
(define v (makebytevector 7 1))
(bytevectorsintset! v 1 #x8000000000 (endianness little) 5)
v ⇒ #vu8(#xff 0 0 0 0 #x80 #xff)
procedure 

returns 
a new list of the 
procedure 

returns 
a new list of the 
libraries 

eness
must be a valid endianness symbol naming the endianness. size
must be an exact positive integer and specifies the number of bytes occupied by the value. It must be a value that evenly divides the length of bytevector
.
(bytevector>uintlist (makebytevector 0) 'little 3) ⇒ ()
(let ([v #vu8(1 2 3 4 5 6)])
(bytevector>uintlist v 'big 3)) ⇒ (#x010203 #x040506)
(let ([v (makebytevector 80 1)])
(bytevector>sintlist v 'big 20)) ⇒ (1 1 1 1)
procedure 

procedure 

returns 
a new bytevector of the elements of 
libraries 

eness
must be a valid endianness symbol naming the endianness. size
must be an exact positive integer and specifies the number of bytes occupied by the value. For uintlist>bytevector
, list
must consist entirely of size
byte exact unsigned integers, i.e., values in the range \(0\) to \(2^{size \cdot 8}  1\) inclusive. For sintlist>bytevector
, list
must consist entirely of size
byte exact signed integers, i.e., values in the range \(2^{size \cdot 8  1}\) to \(2^{size \cdot 8  1}  1\) inclusive. Each value occupies size
bytes in the resulting bytevector, whose length is thus size
times the length of list
.
(uintlist>bytevector '() 'big 25) ⇒ #vu8()
(sintlist>bytevector '(0 1) 'big 3) ⇒ #vu8(0 0 0 #xff #xff #xff)
(define (f size)
(let ([ls (list ( (expt 2 ( (* 8 size) 1)))
( (expt 2 ( (* 8 size) 1)) 1))])
(sintlist>bytevector ls 'little size)))
(f 6) ⇒ #vu8(#x00 #x00 #x00 #x00 #x00 #x80
#xff #xff #xff #xff #xff #x7f)
procedure 

returns 
the single floatingpoint value at index 
procedure 

returns 
the double floatingpoint value at index 
libraries 

n
must be an exact nonnegative integer. It indexes the starting byte of the value and must be a multiple of the number of bytes occupied by the value: 4 for single floats, 8 for double. The sum of n
and the number of bytes occupied by the value must not exceed the length of bytevector
. The native endianness is assumed.
The return value is an inexact real number. Examples appear after the mutation operators below.
procedure 

procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer. It indexes the starting byte of the value and must be a multiple of the number of bytes occupied by the value: 4 for single floats, 8 for double. The sum of n
and the number of bytes occupied by the value must not exceed the length of bytevector
. The native endianness is assumed.
These procedures store the given value as an IEEE754 single or double floatingpoint value at index n
(zerobased) of bytevector
.
(define v (makebytevector 8 0))
(bytevectorieeesinglenativeset! v 0 .125)
(bytevectorieeesinglenativeset! v 4 3/2)
(list
(bytevectorieeesinglenativeref v 0)
(bytevectorieeesinglenativeref v 4)) ⇒ (0.125 1.5)
(bytevectorieeedoublenativeset! v 0 1e23)
(bytevectorieeedoublenativeref v 0) ⇒ 1e23
procedure 

returns 
the single floatingpoint value at index 
procedure 

returns 
the double floatingpoint value at index 
libraries 

n
must be an exact nonnegative integer and indexes the starting byte of the value. The sum of n
and the number of bytes occupied by the value (4 for a single float, 8 for a double) must not exceed the length of bytevector
. n
need not be a multiple of the number of bytes occupied by the value. eness
must be a valid endianness symbol naming the endianness.
The return value is an inexact real number. Examples appear after the mutation operators below.
procedure 

procedure 

returns 
unspecified 
libraries 

n
must be an exact nonnegative integer and indexes the starting byte of the value. The sum of n
and the number of bytes occupied by the value (4 for a single float, 8 for a double) must not exceed the length of bytevector
. n
need not be a multiple of the number of bytes occupied by the value. eness
must be a valid endianness symbol naming the endianness.
These procedures store the given value as an IEEE754 single or double floatingpoint value at index n
(zerobased) of bytevector
.
(define v (makebytevector 10 #xc7))
(bytevectorieeesingleset! v 1 .125 'little)
(bytevectorieeesingleset! v 6 3/2 'big)
(list
(bytevectorieeesingleref v 1 'little)
(bytevectorieeesingleref v 6 'big)) ⇒ (0.125 1.5)
v ⇒ #vu8(#xc7 #x0 #x0 #x0 #x3e #xc7 #xbf #xc0 #x0 #x0)
(bytevectorieeedoubleset! v 1 1e23 'big)
(bytevectorieeedoubleref v 1 'big) ⇒ 1e23
Section 6.11. Symbols
Symbols are used for a variety of purposes as symbolic names in Scheme programs. Strings could be used for most of the same purposes, but an important characteristic of symbols makes comparisons between symbols much more efficient. This characteristic is that two symbols with the same name are identical in the sense of eq?
. The reason is that the Scheme reader (invoked by getdatum
and read
) and the procedure string>symbol
catalog symbols in an internal symbol table and always return the same symbol whenever the same name is encountered. Thus, no characterbycharacter comparison is needed, as would be needed to compare two strings.
The property that two symbols may be compared quickly for equivalence makes them ideally suited for use as identifiers in the representation of programs, allowing fast comparison of identifiers. This property also makes symbols useful for a variety of other purposes. For example, symbols might be used as messages passed between procedures, labels for liststructured records, or names for objects stored in an association list (see assq
in Section 6.3).
Symbols are written without double quotes or other bracketing characters. Parentheses, double quotes, spaces, and most other characters with a special meaning to the Scheme reader are not allowed within the printed representation of a symbol. These and any other Unicode character may appear anywhere within the printed representation of a symbol with the syntax #\xn;
, where n
consists of one or more hexadecimal digits and represents a valid Unicode scalar value.
The grammar for symbols on page 458 gives a precise definition of the syntax of symbols.
procedure 

returns 

libraries 

Symbols can also be compared with eq?
, which is typically more efficient than symbol=?
.
(symbol=? 'a 'a) ⇒ #t
(symbol=? 'a (string>symbol "a")) ⇒ #t
(symbol=? 'a 'b) ⇒ #f
procedure 

returns 
a symbol whose name is 
libraries 

string>symbol
records all symbols it creates in an internal table that it shares with the system reader. If a symbol whose name is equivalent to string (according to the predicate string=?
) already exists in the table, this symbol is returned. Otherwise, a new symbol is created with string
as its name; this symbol is entered into the table and returned.
The effect of modifying a string after it is used as an argument to string>symbol
is unspecified.
(string>symbol "x") ⇒ x
(eq? (string>symbol "x") 'x) ⇒ #t
(eq? (string>symbol "X") 'x) ⇒ #f
(eq? (string>symbol "x")
(string>symbol "x")) ⇒ #t
(string>symbol "()") ⇒ \x28;\x29;
procedure 

returns 
a string, the name of 
libraries 

The string returned by symbol>string
should be treated as immutable. Unpredictable behavior can result if a string passed to string>symbol
is altered with stringset!
or by any other means.
(symbol>string 'xyz) ⇒ "xyz"
(symbol>string 'Hi) ⇒ "Hi"
(symbol>string (string>symbol "()")) ⇒ "()"
Section 6.12. Booleans
While every Scheme object has a truth value when used in a conditional context, with every object but #f
counting as true, Scheme provides the dedicated true value #t
for use when a value of an expression should convey nothing more than that it is true.
procedure 

returns 

libraries 

The boolean values #t
and #f
may also be compared with eq?
, which is typically more efficient than boolean=?
.
(boolean=? #t #t) ⇒ #t
(boolean=? #t #f) ⇒ #f
(boolean=? #t (< 3 4)) ⇒ #t
Section 6.13. Hashtables
Hashtables represent sets of associations between arbitrary Scheme values. They serve essentially the same purpose as association lists (see page 165) but are typically much faster when large numbers of associations are involved.
procedure 

procedure 

returns 
a new mutable eq hashtable 
libraries 

If size
is provided, it must be a nonnegative exact integer indicating approximately how many elements the hashtable should initially hold. Hashtables grow as needed, but when the hashtable grows it generally must rehash all of the existing elements. Providing a nonzero size
can help limit the amount of rehashing that must be done as the table is initially populated.
An eq hashtable compares keys using the eq?
(pointer equality) procedure and typically employs a hash function based on object addresses. Its hash and equivalence functions are suitable for any Scheme object.
(define ht1 (makeeqhashtable))
(define ht2 (makeeqhashtable 32))
procedure 

procedure 

returns 
a new mutable eqv hashtable 
libraries 

If size
is provided, it must be a nonnegative exact integer indicating approximately how many elements the hashtable should initially hold. Hashtables grow as needed, but when the hashtable grows it generally must rehash all of the existing elements. Providing a nonzero size
can help limit the amount of rehashing that must be done as the table is initially populated.
An eqv hashtable compares keys using the eqv?
procedure and typically employs a hash function based on object addresses for objects that are identifiable with eq?
. Its hash and equivalence functions are suitable for any Scheme object.
procedure 

procedure 

returns 
a new mutable hashtable 
libraries 

hash
and equiv?
must be procedures. If size
is provided, it must be a nonnegative exact integer indicating approximately how many elements the hashtable should initially hold. Hashtables grow as needed, but when the hashtable grows it generally must rehash all of the existing elements. Providing a nonzero size
can help limit the amount of rehashing that must be done as the table is initially populated.
The new hashtable computes hash values using hash
and compares keys using equiv?
, neither of which should modify the hashtable. equiv?
should compare two keys and return false only if the two keys should be distinguished. hash
should accept a key as an argument and return a nonnegative exact integer value that is the same each time it is called with arguments that equiv?
does not distinguish. The hash
and equiv?
procedures need not accept arbitrary inputs as long as the hashtable is used only for keys that they do accept, and both procedures may assume that the keys are immutable as long as the keys are not modified while they have associations stored in the table. The hashtable operation may call hash
and equiv?
once, not at all, or multiple times for each hashtable operation.
(define ht (makehashtable stringhash string=?))
procedure 

returns 

libraries 

Hashtables returned by one of the hashtable creation procedures above are mutable, but those created by hashtablecopy
may be immutable. Immutable hashtables cannot be altered by any of the procedures hashtableset!
, hashtableupdate!
, hashtabledelete!
, or hashtableclear!
.
(hashtablemutable? (makeeqhashtable)) ⇒ #t
(hashtablemutable? (hashtablecopy (makeeqhashtable))) ⇒ #f
procedure 

returns 
the hash function associated with 
procedure 

returns 
the equivalence function associated with 
libraries 

hashtablehashfunction
returns #f
for eq and eqv hashtables.
(define ht (makeeqhashtable))
(hashtablehashfunction ht) ⇒ #f
(eq? (hashtableequivalencefunction ht) eq?) ⇒ #t
(define ht (makehashtable stringhash string=?))
(eq? (hashtablehashfunction ht) stringhash) ⇒ #t
(eq? (hashtableequivalencefunction ht) string=?) ⇒ #t
procedure 

procedure 

procedure 

procedure 

returns 
an exact nonnegative integer hash value 
libraries 

These procedures are hash functions suitable for use with the appropriate Scheme predicate: equal?
for equalhash
, string=?
for stringhash
, stringci=?
for stringcihash
, and symbol=?
(or eq?) for symbolhash
. The hash values returned by equalhash
, stringhash
, and stringcihash
are typically dependent on the current structure and contents of the input values and are thus unsuitable if keys are modified while they have associations in a hashtable.
procedure 

returns 
unspecified 
libraries 

hashtable
must be a mutable hashtable. key
should be an appropriate key for the hashtable’s hash and equivalence functions. obj
may be any Scheme object.
hashtableset!
associates key
with obj
in hashtable
, replacing the existing association, if any.
(define ht (makeeqhashtable))
(hashtableset! ht 'a 73)
procedure 

returns 
see below 
libraries 

key
should be an appropriate key for the hashtable’s hash and equivalence functions. default
may be any Scheme object.
hashtableref
returns the value associated with key
in hashtable
. If no value is associated with key
in hashtable
, hashtableref
returns default
.
(define p1 (cons 'a 'b))
(define p2 (cons 'a 'b))
(define eqht (makeeqhashtable))
(hashtableset! eqht p1 73)
(hashtableref eqht p1 55) ⇒ 73
(hashtableref eqht p2 55) ⇒ 55
(define equalht (makehashtable equalhash equal?))
(hashtableset! equalht p1 73)
(hashtableref equalht p1 55) ⇒ 73
(hashtableref equalht p2 55) ⇒ 73
procedure 

returns 

libraries 

key
should be an appropriate key for the hashtable’s hash and equivalence functions.
(define ht (makeeqhashtable))
(define p1 (cons 'a 'b))
(define p2 (cons 'a 'b))
(hashtableset! ht p1 73)
(hashtablecontains? ht p1) ⇒ #t
(hashtablecontains? ht p2) ⇒ #f
procedure 

returns 
unspecified 
libraries 

hashtable
must be a mutable hashtable. key
should be an appropriate key for the hashtable’s hash and equivalence functions. default
may be any Scheme object. procedure
should accept one argument, should return one value, and should not modify hashtable
.
hashtableupdate!
applies procedure
to the value associated with key
in hashtable
, or to default
if no value is associated with key
in hashtable
. If procedure
returns, hashtableupdate!
associates key
with the value returned by procedure
, replacing the old association, if any.
A version of hashtableupdate!
that does not verify that it receives arguments of the proper type might be defined as follows.
(define hashtableupdate!
(lambda (ht key proc value)
(hashtableset! ht key
(proc (hashtableref ht key value)))))
An implementation may, however, be able to implement hashtableupdate!
more efficiently by avoiding multiple hash computations and hashtable lookups.
(define ht (makeeqhashtable))
(hashtableupdate! ht 'a
(lambda (x) (* x 2))
55)
(hashtableref ht 'a 0) ⇒ 110
(hashtableupdate! ht 'a
(lambda (x) (* x 2))
0)
(hashtableref ht 'a 0) ⇒ 220
procedure 

returns 
unspecified 
libraries 

hashtable
must be a mutable hashtable. key
should be an appropriate key for the hashtable’s hash and equivalence functions.
hashtabledelete!
drops any association for key
from hashtable
.
(define ht (makeeqhashtable))
(define p1 (cons 'a 'b))
(define p2 (cons 'a 'b))
(hashtableset! ht p1 73)
(hashtablecontains? ht p1) ⇒ #t
(hashtabledelete! ht p1)
(hashtablecontains? ht p1) ⇒ #f
(hashtablecontains? ht p2) ⇒ #f
(hashtabledelete! ht p2)
procedure 

returns 
number of entries in 
libraries 

(define ht (makeeqhashtable))
(define p1 (cons 'a 'b))
(define p2 (cons 'a 'b))
(hashtablesize ht) ⇒ 0
(hashtableset! ht p1 73)
(hashtablesize ht) ⇒ 1
(hashtabledelete! ht p1)
(hashtablesize ht) ⇒ 0
procedure 

procedure 

returns 
a new hashtable containing the same entries as 
libraries 

If mutable?
is present and not false, the copy is mutable; otherwise, the copy is immutable.
(define ht (makeeqhashtable))
(define p1 (cons 'a 'b))
(hashtableset! ht p1 "c")
(define htcopy (hashtablecopy ht))
(hashtablemutable? htcopy) ⇒ #f
(hashtabledelete! ht p1)
(hashtableref ht p1 #f) ⇒ #f
(hashtabledelete! htcopy p1) ⇒ exception: not mutable
(hashtableref htcopy p1 #f) ⇒ "c"
procedure 

procedure 

returns 
unspecified 
libraries 

hashtable
must be a mutable hashtable. If size
is provided, it must be a nonnegative exact integer.
hashtableclear!
removes all entries from hashtable
. If size is provided, the hashtable is reset to the given size, as if newly created by one of the hashtable creation operations with size argument size
.
(define ht (makeeqhashtable))
(define p1 (cons 'a 'b))
(define p2 (cons 'a 'b))
(hashtableset! ht p1 "first")
(hashtableset! ht p2 "second")
(hashtablesize ht) ⇒ 2
(hashtableclear! ht)
(hashtablesize ht) ⇒ 0
(hashtableref ht p1 #f) ⇒ #f
procedure 

returns 
a vector containing the keys in 
libraries 

The keys may appear in any order in the returned vector.
(define ht (makeeqhashtable))
(define p1 (cons 'a 'b))
(define p2 (cons 'a 'b))
(hashtableset! ht p1 "one")
(hashtableset! ht p2 "two")
(hashtableset! ht 'q "three")
(hashtablekeys ht) ⇒ #((a . b) q (a . b))
procedure 

returns 
two vectors: one of keys and a second of values 
libraries 

hashtableentries
returns two values. The first is a vector containing the keys in hashtable
, and the second is a vector containing the corresponding values. The keys and values may appear in any order, but the order is the same for the keys and for the corresponding values.
(define ht (makeeqhashtable))
(define p1 (cons 'a 'b))
(define p2 (cons 'a 'b))
(hashtableset! ht p1 "one")
(hashtableset! ht p2 "two")
(hashtableset! ht 'q "three")
(hashtableentries ht) ⇒ #((a . b) q (a . b))
#("two" "three" "one")
Section 6.14. Enumerations
Enumerations are ordered sets of symbols, typically used to name and manipulate options, as with the buffer modes and file options that may be specified when files are created.
syntax 

libraries 

A defineenumeration
form is a definition and can appear anywhere any other definition can appear.
The defineenumeration
syntax creates a new enumeration set with the specified symbols in the specified order forming the enumeration’s universe. It defines a new syntactic form named by name
that may be used to verify that a symbol is in the universe. If x
is in the universe, (name x)
evaluates to x
. It is a syntax violation if x
is not in the universe.
defineenumeration
also defines a new syntactic form named by constructor
that may be used to create subsets of the enumeration type. If x ...
are each in the universe, (constructor x ...)
evaluates to an enumeration set containing x ...
. Otherwise, it is a syntax violation. The same symbol may appear more than once in x ...
, but the resulting set contains only one occurrence of the symbol.
(defineenumeration weatherelement
(hot warm cold sunny rainy snowy windy)
weather)
(weatherelement hot) ⇒ hot
(weatherelement fun) ⇒ _syntax violation_
(weather hot sunny windy) ⇒ #
(enumset>list (weather rainy cold rainy)) ⇒ (cold rainy)
procedure 

returns 
an enumeration set 
libraries 

This procedure creates a new enumeration type whose universe comprises the elements of symbollist
, which must be a list of symbols, in the order of their first appearance in the list. It returns the universe of the new enumeration type as an enumeration set.
(define positions (makeenumeration '(top bottom above top beside)))
(enumset>list positions) ⇒ (top bottom above beside)
procedure 

returns 
an enumerationset construction procedure 
libraries 

This procedure returns a procedure p
that may be used to create subsets of the universe of enumset
. p
must be passed a list of symbols, and each element of the list must be an element of the universe of enumset
. The enumeration set returned by p
contains all and only the symbols in the list it is passed. The value returned by p
may contain elements not in enumset
if the universe of enumset
contains those elements.
(define e1 (makeenumeration '(one two three four)))
(define p1 (enumsetconstructor e1))
(define e2 (p1 '(one three)))
(enumset>list e2) ⇒ (one three)
(define p2 (enumsetconstructor e2))
(define e3 (p2 '(one two four)))
(enumset>list e3) ⇒ (one two four)
procedure 

returns 
the universe of 
libraries 

(define e1 (makeenumeration '(a b c a b c d)))
(enumset>list (enumsetuniverse e1)) ⇒ (a b c d)
(define e2 ((enumsetconstructor e1) '(c)))
(enumset>list (enumsetuniverse e2)) ⇒ (a b c d)
procedure 

returns 
a list of the elements of 
libraries 

The symbols in the resulting list appear in the order given to them when the enumeration type of enumset
was created.
(define e1 (makeenumeration '(a b c a b c d)))
(enumset>list e1) ⇒ (a b c d)
(define e2 ((enumsetconstructor e1) '(d c a b)))
(enumset>list e2) ⇒ (a b c d)
procedure 

returns 

libraries 

An enumeration set enumset_{1}
is a subset of an enumeration set enumset_{2}
if and only if the universe of enumset_{1}
is a subset of the universe of enumset_{2}
and each element of enumset_{1}
is an element of enumset_{2}
.
(define e1 (makeenumeration '(a b c)))
(define e2 (makeenumeration '(a b c d e)))
(enumsetsubset? e1 e2) ⇒ #t
(enumsetsubset? e2 e1) ⇒ #f
(define e3 ((enumsetconstructor e2) '(a c)))
(enumsetsubset? e3 e1) ⇒ #f
(enumsetsubset? e3 e2) ⇒ #t
procedure 

returns 

libraries 

Two enumeration sets enumset_{1}
and enumset_{2}
are equivalent if each is a subset of the other.
(define e1 (makeenumeration '(a b c d)))
(define e2 (makeenumeration '(b d c a)))
(enumset=? e1 e2) ⇒ #t
(define e3 ((enumsetconstructor e1) '(a c)))
(define e4 ((enumsetconstructor e2) '(a c)))
(enumset=? e3 e4) ⇒ #t
(enumset=? e3 e2) ⇒ #f
enumset=?
could be defined in terms of enumsetsubset?
as follows.
(define enumset=?
(lambda (e1 e2)
(and (enumsetsubset? e1 e2) (enumsetsubset? e2 e1))))
procedure 

returns 

libraries 

(define e1 (makeenumeration '(a b c d e)))
(define e2 ((enumsetconstructor e1) '(d b)))
(enumsetmember? 'c e1) ⇒ #t
(enumsetmember? 'c e2) ⇒ #f
procedure 

returns 
the union of 
procedure 

returns 
the intersection of 
procedure 

returns 
the difference of 
libraries 

enumset_{1}
and enumset_{2}
must have the same enumeration type. Each procedure returns a new enumeration set representing the union, intersection, or difference of the two sets.
(define e1 (makeenumeration '(a b c d)))
(define e2 ((enumsetconstructor e1) '(a c)))
(define e3 ((enumsetconstructor e1) '(b c)))
(enumset>list (enumsetunion e2 e3)) ⇒ (a b c)
(enumset>list (enumsetintersection e2 e3)) ⇒ (c)
(enumset>list (enumsetdifference e2 e3)) ⇒ (a)
(enumset>list (enumsetdifference e3 e2)) ⇒ (b)
(define e4 (makeenumeration '(b d c a)))
(enumsetunion e1 e4) ⇒ exception: different enumeration types
procedure 

returns 
the complement of 
libraries 

(define e1 (makeenumeration '(a b c d)))
(enumset>list (enumsetcomplement e1)) ⇒ ()
(define e2 ((enumsetconstructor e1) '(a c)))
(enumset>list (enumsetcomplement e2)) ⇒ (b d)
procedure 

returns 
the projection of 
libraries 

Any elements of enumset_{1}
not in the universe of enumset_{2}
are dropped. The result is of the same enumeration type as enumset_{2}
.
(define e1 (makeenumeration '(a b c d)))
(define e2 (makeenumeration '(a b c d e f g)))
(define e3 ((enumsetconstructor e1) '(a d)))
(define e4 ((enumsetconstructor e2) '(a c e g)))
(enumset>list (enumsetprojection e4 e3)) ⇒ (a c)
(enumset>list
(enumsetunion e3
(enumsetprojection e4 e3))) ⇒ (a c d)
procedure 

returns 
a procedure that returns the index of a symbol in the universe of 
libraries 

enumsetindexer
returns a procedure p
that, when applied to a symbol in the universe of enumset
, returns the index of the symbol (zerobased) in the ordered set of symbols that form the universe. If applied to a symbol not in the universe, p
returns #f
.
(define e1 (makeenumeration '(a b c d)))
(define e2 ((enumsetconstructor e1) '(a d)))
(define p (enumsetindexer e2))
(list (p 'a) (p 'c) (p 'e)) ⇒ (0 2 #f)
Chapter 7. Input and Output
All input and output operations are performed through ports. A port is a pointer into a (possibly infinite) stream of data (often a file), an opening through which programs may draw bytes or characters from the stream or place bytes or characters into the stream. A port may be an input port, an output port, or both simultaneously.
Ports are firstclass objects, like any other object in Scheme. Like procedures, ports do not have a printed representation the way strings and numbers do. There are initially three ports: the current input port, current output port, and current error port, which are textual ports connected to the process’s standard input, standard output, and standard error streams. Several ways to open new ports are provided.
An input port often points to a finite stream, e.g., an input file stored on disk. If one of the input operations, e.g., getu8
, getchar
, or getdatum
, is asked to read from a port that has reached the end of a finite stream, it returns a special eof (end of file) object. The predicate eofobject?
may be used to determine if the value returned from the input operation is the eof object.
Ports are either binary or textual. A binary port allows a program to read or write 8bit unsigned bytes, or "octets," from or to the underlying stream. A textual port allows a program to read or write characters.
In many cases, the underlying stream is organized as a sequence of bytes, but these bytes should be treated as encodings for characters. In this case, a textual port may be created with a transcoder to decode bytes to characters (for input) or encode characters to bytes (for output). A transcoder encapsulates a codec that determines how characters are represented as bytes. Three standard codecs are provided: a latin1 codec, a Unicode utf8 codec, and a Unicode utf16 codec. For the latin1 encoding, each character is represented by exactly one byte. For utf8, each character is represented by from one to four bytes, and for utf16, each character is represented by two or four bytes.
A transcoder also encapsulates an eol style that determines whether and how line endings are recognized. If the eol style is none
, no line endings are recognized. The six other standard eol styles are the following:
lf

linefeed character 
cr

carriagereturn character 
nel

Unicode nextline character 
ls

Unicode lineseparator character 
crlf

carriage return followed by line feed, and 
crnel

carriage return followed by next line 
The eol style affects input and output operations differently. For input, any eol style except none
causes each of the lineending characters or twocharacter sequences to be converted into a single linefeed character. For output, any eol style except none
causes linefeed characters to be converted into the specific one or twocharacter sequence associated with the eol style. In the input direction, all eol styles except none
are equivalent, while in the output direction, the eol styles none
and lf
are equivalent.
In addition to the codec and eol style, a transcoder encapsulates just one other piece of information: an errorhandling mode that determines what happens if a decoding or encoding error occurs, i.e., if a sequence of bytes cannot be converted to a character with the encapsulated codec in the input direction or a character cannot be converted to a sequence of bytes with the encapsulated codec in the output direction. The errorhandling mode is ignore
, raise
, or replace
. If the errorhandling mode is ignore
, the offending sequence of bytes or the character is ignored. If the errorhandling mode is raise
, an exception with condition type i/odecoding
or i/oencoding
is raised; in the input direction, the port is positioned beyond the sequence of bytes. If the errorhandling mode is replace
, a replacement character or character encoding is produced: in the input direction, the replacement character is U+FFFD, while in the output direction, the replacement is either the encoding of U+FFFD for utf8
and utf16
codecs or the encoding of the questionmark character ( ? ) for the latin1
codec.
A port may be buffered for efficiency, to eliminate the overhead of a call into the operating system for each byte or character. Three standard buffer modes are supported: block, line, and none. With block buffering, input is drawn from a stream and output is sent to the stream in chunks of some implementationdependent size. With line buffering, buffering is performed on a linebyline basis or on some other implementationdependent basis. Line buffering is typically distinguished from block buffering only for textual output ports; there are no line divisions in binary ports, and input is likely to be drawn from a stream as it becomes available. With buffermode none, no buffering is performed, so output is sent immediately to the stream and input is drawn only as needed.
The remainder of this chapter covers operations on transcoders, file ports, standard ports, string and bytevector ports, custom ports, general port operations, input operations, output operations, convenience I/O, filesystem operations, and conversions between bytevectors and strings.
Section 7.1. Transcoders
As described above, transcoders encapsulate three values: a codec, an eol style, and an errorhandling mode. This section describes the procedures that create or operate on transcoders and the values that transcoders encapsulate.
procedure 

procedure 

procedure 

returns 
a transcoder encapsulating 
libraries 

eolstyle
must be a valid eolstyle symbol (lf
, cr
, nel
, ls
, crlf
, crnel
, or none
); it defaults to the native eolstyle for the platform. errorhandlingmode
must be a valid errorhandlingmode symbol (ignore
, raise
, or replace
) and defaults to replace
.
procedure 

returns 
the codec encapsulated in 
procedure 

returns 
the eolstyle symbol encapsulated in 
procedure 

returns 
the errorhandlingmode symbol encapsulated in 
libraries 

procedure 

returns 
the native transcoder 
libraries 

The native transcoder is implementationdependent and may vary by platform or locale.
procedure 

returns 
a codec for ISO 88591 (Latin 1) character encodings 
procedure 

returns 
a codec for Unicode UTF8 character encodings 
procedure 

returns 
a codec for Unicode UTF16 character encodings 
libraries 

syntax 

returns 

libraries 

symbol
must be one of the symbols lf
, cr
, nel
, ls
, crlf
, crnel
, or none
. The expression (eolstyle symbol)
is equivalent to the expression (quote symbol)
except the former checks at expansion time that symbol
is one of the eolstyle symbols. The eolstyle
syntax provides useful documentation as well.
(eolstyle crlf) ⇒ crlf
(eolstyle lfcr) ⇒ syntax violation
procedure 

returns 
the native eol style 
libraries 

The native eol style is implementationdependent and may vary by platform or locale.
syntax 

returns 

libraries 

symbol
must be one of the symbols ignore
, raise
, or replace
. The expression (errorhandlingmode symbol)
is equivalent to the expression (quote symbol)
except that the former checks at expansion time that symbol
is one of the errorhandlingmode symbols. The errorhandlingmode
syntax provides useful documentation as well.
(errorhandlingmode replace) ⇒ replace
(errorhandlingmode relpace) ⇒ syntax violation
Section 7.2. Opening Files
The procedures in this section are used for opening file ports. Procedures for opening other kinds of ports, e.g., string ports or custom ports, are described in subsequent sections.
Each of the fileopen operations accepts a path
argument that names the file to be opened. It must be a string or some other implementationdependent value that names a file.
Some of the fileopen procedures accept optional options
, bmode
, and ?transcoder
arguments. options
must be an enumeration set over the symbols constituting valid file options described in the fileoptions
entry below, and it defaults to the value of (fileoptions)
. bmode
must be a valid buffer mode described in the buffermode
entry below, and it defaults to block
. ?transcoder
must be a transcoder or #f
; if it is a transcoder, the open operation returns a transcoded port for the underlying binary file, while if it is #f
(the default), the open operation returns a binary port.
Binary ports created by the procedures in this section support the portposition
and setportposition!
operations. Whether textual ports created by the procedures in this section support these operations is implementationdependent.
syntax 

returns 
a fileoptions enumeration set 
libraries 

Fileoptions enumeration sets may be passed to fileopen operations to control aspects of the open operation. There are three standard file options: nocreate
, nofail
, and notruncate
, which affect only fileopen operations that create output (including input/output) ports.
With the default file options, i.e., the value of (fileoptions)
, when a program attempts to open a file for output, an exception is raised with condition type i/ofilealreadyexists
if the file already exists, and the file is created if it does not already exist. If the nofail
option is included, no exception is raised if the file already exists; instead, the file is opened and truncated to zero length. If the nocreate
option is included, the file is not created if it does not exist; instead, an exception is raised with condition type i/ofiledoesnotexist
. The nocreate
option implies the nofail
option. The notruncate
option is relevant only if the nofail
option is included or implied, in which case if an existing file is opened, it is not truncated, but the port’s position is still set to the beginning of the file.
It is perhaps easier to imagine that the default file options are the imaginary option symbols create
, failifexists
, and truncate
; nocreate
removes create
, nofail
removes failifexists
, and notruncate
removes truncate
.
Implementations may support additional file option symbols. Chez Scheme, for example, supports options that control whether the file is or should be compressed, whether it is locked for exclusive access, and what permissions are given to the file if it is created [9].
syntax 

returns 

libraries 

symbol
must be one of the symbols block
, line
, or none
. The expression (buffermode symbol)
is equivalent to the expression (quote symbol)
except that the former checks at expansion time that symbol
is one of the buffermode symbols. The buffermode
syntax provides useful documentation as well.
(buffermode block) ⇒ block
(buffermode cushion) ⇒ syntax violation
syntax 

returns 

libraries 

(buffermode? 'block) ⇒ #t
(buffermode? 'line) ⇒ #t
(buffermode? 'none) ⇒ #t
(buffermode? 'somethingelse) ⇒ #f
procedure 

procedure 

procedure 

procedure 

returns 
a new input port for the named file 
libraries 

If ?transcoder
is present and not #f
, it must be a transcoder, and this procedure returns a textual input port whose transcoder is ?transcoder
. Otherwise, this procedure returns a binary input port. See the leadin to this section for a description of the constraints on and effects of the other arguments.
procedure 

procedure 

procedure 

procedure 

returns 
a new output port for the named file 
libraries 

If ?transcoder
is present and not #f
, it must be a transcoder, and this procedure returns a textual output port whose transcoder is ?transcoder
. Otherwise, this procedure returns a binary output port. See the leadin to this section for a description of the constraints on and effects of the other arguments.
procedure 

procedure 

procedure 

procedure 

returns 
a new input/output port for the named file 
libraries 

If ?transcoder
is present and not #f
, it must be a transcoder, and this procedure returns a textual input/output port whose transcoder is ?transcoder
. Otherwise, this procedure returns a binary input/output port. See the leadin to this section for a description of the constraints on and effects of the other arguments.
Section 7.3. Standard Ports
The procedures described in this section return ports that are attached to a process’s standard input, standard output, and standard error streams. The first set returns "readymade" textual ports with implementationdependent transcoders (if any) and buffer modes. The second set creates fresh binary ports and can be used either for binary input/output or, with the help of transcodedport
, for textual input/output with programsupplied transcoders and buffer modes.
procedure 

returns 
the current input port 
procedure 

returns 
the current output port 
procedure 

returns 
the current error port 
libraries 

The currentinput, currentoutput, and currenterror ports return prebuilt textual ports that are initially associated with a process’s standard input, standard output, and standard error streams.
The values returned by currentinputport
and currentoutputport
can be altered temporarily by the convenience I/O procedures withinputfromfile
and withoutputtofile
(Section 7.9).
procedure 

returns 
a fresh binary input port connected to the standard input stream 
procedure 

returns 
a fresh binary output port connected to the standard output stream 
procedure 

returns 
a fresh binary output port connected to the standard error stream 
libraries 

Because ports may be buffered, confusion can result if operations on more than one port attached to one of a process’s standard streams are interleaved. Thus, these procedures are typically appropriate only when a program no longer needs to use any existing ports attached to the standard streams.
Section 7.4. String and Bytevector Ports
The procedures in this section allow bytevectors and strings to be used as input or output streams.
Binary ports created by the procedures in this section support the portposition
and setportposition!
operations. Whether textual ports created by the procedures in this section support these operations is implementationdependent.
procedure 

procedure 

returns 
a new input port that draws input from 
libraries 

If ?transcoder
is present and not #f
, it must be a transcoder, and this procedure returns a textual input port whose transcoder is ?transcoder
. Otherwise, this procedure returns a binary input port.
The effect of modifying bytevector
after this procedure is called is unspecified.
(let ([ip (openbytevectorinputport #vu8(1 2))])
(let* ([x1 (getu8 ip)] [x2 (getu8 ip)] [x3 (getu8 ip)])
(list x1 x2 (eofobject? x3)))) ⇒ (1 2 #t)
There is no need to close a bytevector port; it’s storage will be reclaimed automatically when it is no longer needed, as with any other object, and an open bytevector port does not tie up any operating system resources.
procedure 

returns 
a new textual input port that draws input from 
libraries 

The effect of modifying string
after this procedure is called is unspecified. The new port may or may not have a transcoder, and if it does, the transcoder is implementationdependent. While not required, implementations are encouraged to support portposition
and setportposition!
for string ports.
(getline (openstringinputport "hi.\nwhat's up?\n")) ⇒ "hi."
There is no need to close a string port; it’s storage will be reclaimed automatically when it is no longer needed, as with any other object, and an open string port does not tie up any operating system resources.
procedure 

procedure 

returns 
two values, a new output port and an extraction procedure 
libraries 

If ?transcoder
is present and not #f
, it must be a transcoder, and the port value is a textual output port whose transcoder is ?transcoder
. Otherwise, the port value is a binary output port.
The extraction procedure is a procedure that, when called without arguments, creates a bytevector containing the accumulated bytes in the port, clears the port of its accumulated bytes, resets its position to zero, and returns the bytevector. The accumulated bytes include any bytes written beyond the end of the current position, if the position has been set back from its maximum extent.
(letvalues ([(op g) (openbytevectoroutputport)])
(putu8 op 15)
(putu8 op 73)
(putu8 op 115)
(setportposition! op 2)
(let ([bv1 (g)])
(putu8 op 27)
(list bv1 (g)))) ⇒ (#vu8(15 73 115) #vu8(27))
There is no need to close a bytevector port; it’s storage will be reclaimed automatically when it is no longer needed, as with any other object, and an open bytevector port does not tie up any operating system resources.
procedure 

returns 
two values, a new textual output port and an extraction procedure 
libraries 

The extraction procedure is a procedure that, when called without arguments, creates a string containing the accumulated characters in the port, clears the port of its accumulated characters, resets its position to zero, and returns the string. The accumulated characters include any characters written beyond the end of the current position, if the position has been set back from its maximum extent. While not required, implementations are encouraged to support portposition
and setportposition!
for string ports.
(letvalues ([(op g) (openstringoutputport)])
(putstring op "some data")
(let ([str1 (g)])
(putstring op "new stuff")
(list str1 (g)))) ⇒ ("some data" "new stuff")
There is no need to close a string port; it’s storage will be reclaimed automatically when it is no longer needed, as with any other object, and an open string port does not tie up any operating system resources.
procedure 

procedure 

returns 
a bytevector containing the accumulated bytes 
libraries 

If ?transcoder
is present and not #f
, it must be a transcoder, and procedure
is called with a textual bytevector output port whose transcoder is ?transcoder
. Otherwise, procedure
is called with a binary bytevector output port. If procedure
returns, a bytevector containing the bytes accumulated in the port is created, the accumulated bytes are cleared from the port, the port’s position is reset to zero, and the bytevector is returned from callwithbytevectoroutputport
. These actions occur each time procedure
returns, if it returns multiple times due to the invocation of a continuation created while procedure
is active.
(let ([tx (maketranscoder (latin1codec) (eolstyle lf)
(errorhandlingmode replace))])
(callwithbytevectoroutputport
(lambda (p) (putstring p "abc"))
tx)) ⇒ #vu8(97 98 99)
procedure 

returns 
a string containing the accumulated characters 
libraries 

procedure
is called with one argument, a string output port. If procedure
returns, a string containing the characters accumulated in the port is created, the accumulated characters are cleared from the port, the port’s position is reset to zero, and the string is returned from callwithstringoutputport
. These actions occur each time procedure
returns, if it returns multiple times due to the invocation of a continuation created while procedure
is active.
callwithstringoutputport
can be used along with putdatum
to define a procedure, object>string
, that returns a string containing the printed representation of an object.
(define (object>string x)
(callwithstringoutputport
(lambda (p) (putdatum p x))))
(object>string (cons 'a '(b c))) ⇒ "(a b c)"
Section 7.5. Opening Custom Ports
procedure 

returns 
a new custom binary input port 
procedure 

returns 
a new custom binary output port 
procedure 

returns 
a new custom binary input/output port 
libraries 

These procedures allow programs to create ports from arbitrary byte streams. id
must be a string naming the new port; the name is used for informational purposes only, and an implementation may choose to include it in the printed syntax, if any, of a custom port. r!
and w!
must be procedures, while gp
, sp!
, and close
must each be a procedure or #f
. These arguments are described below.
r!

is called to draw input from the custom port, e.g., to support
getu8
orgetbytevectorn
. It is called with three arguments:bytevector
,start
, andn
.start
will be a nonnegative exact integer,n
will be a positive exact integer, and the sum ofstart
andn
will not exceed the length ofbytevector
. If the byte stream is at end of file,r!
should return exact 0. Otherwise, it should read at least one and at mostn
bytes from the stream, store these bytes in consecutive locations ofbytevector
starting atstart
, and return as an exact positive integer the number of bytes actually read. w!

is called to send output to the port, e.g., to support
putu8
orputbytevector
. It is called with three arguments:bytevector
,start
, andn
.start
andn
will be nonnegative exact integers, and the sum ofstart
andn
will not exceed the length ofbytevector
.w!
should write up ton
consecutive bytes frombytevector
starting atstart
and return, as an exact nonnegative integer, the number of bytes actually written. gp

is called to query the port’s position. If it is
#f
, the port will not supportportposition
. If it is not#f
, it will be passed zero arguments and should return the current position as a displacement in bytes from the start of the byte stream as an exact nonnegative integer. sp!

is called to set the port’s position. If it is
#f
, the port will not supportsetportposition!
. If it is not#f
, it will be passed one argument, an exact nonnegative integer representing the new position as a displacement in bytes from the start of the byte stream, and it should set the position to this value. close

is called to close the byte stream. If it is
#f
, no action will be taken to close the byte stream when the new port is closed. If it is not#f
, it will be passed zero arguments and should take whatever actions are necessary to close the byte stream.
If the new port is an input/output port and does not provide either a gp
or sp!
procedure, it may not be possible for the implementation to position the port properly if an output operation occurs after an input operation, due to input buffering that must be done to support lookaheadu8
and is often done anyway for efficiency. For the same reason, a call to portposition
after an input operation may not return an accurate position if the sp!
procedure is not provided. Thus, programs that create custom binary input/output ports should generally provide both gp
and sp!
procedures.
procedure 

returns 
a new custom textual input port 
procedure 

returns 
a new custom textual output port 
procedure 

returns 
a new custom textual input/output port 
libraries 

These procedures allow programs to create ports from arbitrary character streams. id
must be a string naming the new port; the name is used for informational purposes only, and an implementation may choose to include it in the printed syntax, if any, of a custom port. r!
and w!
must be procedures, while gp
, sp!
, and close
must each be a procedure or #f
. These arguments are described below.
r!

is called to draw input from the port, e.g., to support
getchar
orgetstringn
. It is called with three arguments:string
,start
, andn
.start
will be a nonnegative exact integer,n
will be a positive exact integer, and the sum ofstart
andn
will not exceed the length ofstring
. If the character stream is at end of file,r!
should return exact 0. Otherwise, it should read at least one and at mostn
characters from the stream, store these characters in consecutive locations ofstring
starting atstart
, and return as an exact positive integer the number of characters actually read. w!

is called to send output to the port, e.g., to support
putchar
orputstring
. It is called with three arguments:string
,start
, andn
.start
andn
will be nonnegative exact integers, and the sum ofstart
andn
will not exceed the length ofstring
.w!
should write up ton
consecutive characters fromstring
starting atstart
and return, as an exact nonnegative integer, the number of characters actually written. gp

is called to query the port’s position. If it is
#f
, the port will not supportportposition
. If it is not#f
, it will be passed zero arguments and should return the current position, which may be an arbitrary value. sp!

is called to set the port’s position. If it is
#f
, the port will not supportsetportposition!
. If it is not#f
, it will be passed one argument,pos
, a value representing the new position. Ifpos
is the result of a previous call togp
,sp!
should set the position topos
. close

is called to close the character stream. If it is
#f
, no action will be taken to close the character stream when the new port is closed. If it is not#f
, it will be passed zero arguments and should take whatever actions are necessary to close the character stream.
If the new port is an input/output port, it may not be possible for the implementation to position the port properly if an output operation occurs after an input operation, even if the gp
and sp!
procedures are provided, due to input buffering that must be done to support lookaheadchar
and is often done anyway for efficiency. Since the representations of port positions are not specified, it is not possible for the implementation to adjust the gp
return value to account for the number of buffered characters. For the same reason, a call to portposition
after an input operation may not return an accurate position, even if the sp!
procedure is provided.
It should, however, be possible to perform output reliably after reading if the position is reset to the starting position. Thus, programs that create custom textual input/output ports should generally provide both gp
and sp!
procedures, and consumers of these ports should obtain the starting position via portposition
before any input operations and reset the position back to the starting position before doing any output operations.
Section 7.6. Port Operations
This section describes a variety of operations on ports that do not directly involve either reading from or writing to a port. The input and output operations are described in subsequent sections.
procedure 

returns 

libraries 

procedure 

returns 

procedure 

returns 

libraries 

procedure 

returns 

procedure 

returns 

libraries 

procedure 

returns 
unspecified 
libraries 

If port
is not already closed, closeport
closes it, first flushing any buffered bytes or characters to the underlying stream if the port is an output port. Once a port has been closed, no more input or output operations may be performed on the port. Because the operating system may place limits on the number of file ports open at one time or restrict access to an open file, it is good practice to close any file port that will no longer be used for input or output. If the port is an output port, closing the port explicitly also ensures that buffered data is written to the underlying stream. Some Scheme implementations close file ports automatically after they become inaccessible to the program or when the Scheme program exits, but it is best to close file ports explicitly whenever possible. Closing a port that has already been closed has no effect.
procedure 

returns 
a new textual port with the same byte stream as 
libraries 

This procedure returns a new textual port with transcoder transcoder
and the same underlying byte stream as binaryport
, positioned at the current position of binaryport
.
As a side effect of creating the textual port, binaryport
is closed to prevent read or write operations on binaryport
from interfering with read and write operations on the new textual port. The underlying byte stream remains open, however, until the textual port is closed.
procedure 

returns 
the transcoder associated with 
libraries 

This procedure always returns #f
for binary ports and may return #f
for some textual ports.
procedure 

returns 
the port’s current position 
procedure 

returns 

libraries 

A port may allow queries to determine its current position in the underlying stream of bytes or characters. If so, the procedure porthasportposition?
returns #t
and portposition
returns the current position. For binary ports, the position is always an exact nonnegative integer byte displacement from the start of the byte stream. For textual ports, the representation of a position is unspecified; it may not be an exact nonnegative integer and, even if it is, it may not represent either a byte or character displacement in the underlying stream. The position may be used at some later time to reset the position if the port supports setportposition!
. If portposition
is called on a port that does not support it, an exception with condition type &assertion
is raised.
procedure 

returns 
unspecified 
procedure 

returns 

libraries 

A port may allow its current position to be moved directly to a different position in the underlying stream of bytes or characters. If so, the procedure porthassetportposition!?
returns #t
and setportposition!
changes the current position. For binary ports, the position pos
must be an exact nonnegative integer byte displacement from the start of the byte stream. For textual ports, the representation of a position is unspecified, as described in the entry for portposition
above, but pos
must be an appropriate position for the textual port, which is usually guaranteed to be the case only if it was obtained from a call to portposition
on the same port. If setportposition!
is called on a port that does not support it, an exception with condition type &assertion
is raised.
If port
is a binary output port and the position is set beyond the current end of the data in the underlying stream, the stream is not extended until new data is written at that position. If new data is written at that position, the contents of each intervening position is unspecified. Binary ports created with openfileoutputport
and openfileinput/outputport
can always be extended in this manner within the limits of the underlying operating system. In other cases, attempts to set the port beyond the current end of data in the underlying object may result in an exception with condition type &i/oinvalidposition
.
procedure  
returns 
the values returned by 
libraries 

callwithport
calls procedure
with port
as the only argument. If procedure
returns, callwithport
closes the port and returns the values returned by procedure
.
callwithport
does not automatically close the port if a continuation created outside of procedure
is invoked, since it is possible that another continuation created inside of procedure
will be invoked at a later time, returning control to procedure
. If procedure
does not return, an implementation is free to close the port only if it can prove that the output port is no longer accessible.
The example below copies the contents of infile to outfile, overwriting outfile if it exists. Unless an error occurs, the ports are closed after the copy has been completed.
(callwithport (openfileinputport "infile" (fileoptions)
(buffermode block) (nativetranscoder))
(lambda (ip)
(callwithport (openfileoutputport "outfile"
(fileoptions nofail)
(buffermode block)
(nativetranscoder))
(lambda (op)
(do ([c (getchar ip) (getchar ip)])
((eofobject? c))
(putchar op c))))))
A definition of callwithport
is given on page 135.
procedure 

returns 
the symbol representing the buffer mode of 
libraries 

Section 7.7. Input Operations
Procedures whose primary purpose is to read data from an input port are described in this section, along with related procedures for recognizing or creating endoffile (eof) objects.
procedure 

returns 

libraries 

The endoffile object is returned by input operations, e.g., getdatum
, when an input port has reached the end of input.
procedure 

returns 
the eof object 
libraries 

(eofobject? (eofobject)) ⇒ #t
procedure 

returns 
the next byte from 
libraries 

If binaryinputport
is at end of file, the eof object is returned. Otherwise, the next available byte is returned as an unsigned 8bit quantity, i.e., an exact unsigned integer less than or equal to 255, and the port’s position is advanced one byte.
procedure 

returns 
the next byte from 
libraries 

If binaryinputport
is at end of file, the eof object is returned. Otherwise, the next available byte is returned as an unsigned 8bit quantity, i.e., an exact unsigned integer less than or equal to 255. In contrast to getu8
, lookaheadu8
does not consume the byte it reads from the port, so if the next operation on the port is a call to lookaheadu8
or getu8
, the same byte is returned.
procedure 

returns 
a nonempty bytevector containing up to 
libraries 

n
must be an exact nonnegative integer. If binaryinputport
is at end of file, the eof object is returned. Otherwise, getbytevectorn
reads (as if with getu8
) as many bytes, up to n
, as are available before the port is at end of file, and returns a new (nonempty) bytevector containing these bytes. The port’s position is advanced past the bytes read.
procedure 

returns 
the count of bytes read or the eof object 
libraries 

start
and n
must be exact nonnegative integers, and the sum of start
and n
must not exceed the length of bytevector
.
If binaryinputport
is at end of file, the eof object is returned. Otherwise, getbytevectorn!
reads (as if with getu8
) as many bytes, up to n
, as are available before the port is at end of file, stores the bytes in consecutive locations of bytevector
starting at start
, and returns the count of bytes read as an exact positive integer. The port’s position is advanced past the bytes read.
procedure 

returns 
a nonempty bytevector or the eof object 
libraries 

If binaryinputport
is at end of file, the eof object is returned. Otherwise, getbytevectorsome
reads (as if with getu8
) at least one byte and possibly more, and returns a bytevector containing these bytes. The port’s position is advanced past the bytes read. The maximum number of bytes read by this operation is implementationdependent.
procedure 

returns 
a nonempty bytevector or the eof object 
libraries 

If binaryinputport
is at end of file, the eof object is returned. Otherwise, getbytevectorall
reads (as if with getu8
) all of the bytes available before the port is at end of file and returns a bytevector containing these bytes. The port’s position is advanced past the bytes read.
procedure 

returns 
the next character from 
libraries 

If textualinputport
is at end of file, the eof object is returned. Otherwise, the next available character is returned and the port’s position is advanced one character. If textualinputport
is a transcoded port, the position in the underlying byte stream may advance by more than one byte.
procedure 

returns 
the next character from 
libraries 

If textualinputport
is at end of file, the eof object is returned. Otherwise, the next available character is returned. In contrast to getchar
, lookaheadchar
does not consume the character it reads from the port, so if the next operation on the port is a call to lookaheadchar
or getchar
, the same character is returned.
lookaheadchar
is provided for applications requiring one character of lookahead. The procedure getword
defined below returns the next word from a textual input port as a string, where a word is defined to be a sequence of alphabetic characters. Since getword
does not know until it sees one character beyond the word that it has read the entire word, it uses lookaheadchar
to determine the next character and getchar
to consume the character.
(define getword
(lambda (p)
(list>string
(let f ()
(let ([c (lookaheadchar p)])
(cond
[(eofobject? c) '()]
[(charalphabetic? c) (getchar p) (cons c (f))]
[else '()]))))))
procedure 

returns 
a nonempty string containing up to 
libraries 

n
must be an exact nonnegative integer. If textualinputport
is at end of file, the eof object is returned. Otherwise, getstringn
reads (as if with getchar
) as many characters, up to n
, as are available before the port is at end of file, and returns a new (nonempty) string containing these characters. The port’s position is advanced past the characters read.
procedure 

returns 
the count of characters read or the eof object 
libraries 

start
and n
must be exact nonnegative integers, and the sum of start
and n
must not exceed the length of string
.
If textualinputport
is at end of file, the eof object is returned. Otherwise, getstringn!
reads (as if with getchar
) as many characters, up to n
, as are available before the port is at end of file, stores the characters in consecutive locations of string
starting at start
, and returns the count of characters read as an exact positive integer. The port’s position is advanced past the characters read.
getstringn!
may be used to implement stringset!
and stringfill!
, as illustrated below, although this is not its primary purpose.
(define stringset!
(lambda (s i c)
(let ([sip (openstringinputport (string c))])
(getstringn! sip s i 1)
; return unspecified values:
(if #f #f))))
(define stringfill!
(lambda (s c)
(let ([n (stringlength s)])
(let ([sip (openstringinputport (makestring n c))])
(getstringn! sip s 0 n)
; return unspecified values:
(if #f #f)))))
(let ([x (makestring 3)])
(stringfill! x #\)
(stringset! x 2 #\))
(stringset! x 0 #\;)
x) ⇒ ";)"
procedure 

returns 
a nonempty string or the eof object 
libraries 

If textualinputport
is at end of file, the eof object is returned. Otherwise, getstringall
reads (as if with getchar
) all of the characters available before the port is at end of file and returns a string containing these characters. The port’s position is advanced past the characters read.
procedure 

returns 
a string or the eof object 
libraries 

If textualinputport
is at end of file, the eof object is returned. Otherwise, getline
reads (as if with getchar
) all of the characters available before the port is at end of file or a linefeed character has been read and returns a string containing all but the linefeed character of the characters read. The port’s position is advanced past the characters read.
(let ([sip (openstringinputport "one\ntwo\n")])
(let* ([s1 (getline sip)] [s2 (getline sip)])
(list s1 s2 (porteof? sip)))) ⇒ ("one" "two" #t)
(let ([sip (openstringinputport "one\ntwo")])
(let* ([s1 (getline sip)] [s2 (getline sip)])
(list s1 s2 (porteof? sip)))) ⇒ ("one" "two" #t)
procedure 

returns 
a Scheme datum object or the eof object 
libraries 

This procedure scans past whitespace and comments to find the start of the external representation of a datum. If textualinputport
reaches end of file before the start of the external representation of a datum is found, the eof object is returned.
Otherwise, getdatum
reads as many characters as necessary, and no more, to parse a single datum, and returns a newly allocated object whose structure is determined by the external representation. The port’s position is advanced past the characters read. If an endoffile is reached before the external representation of the datum is complete, or an unexpected character is read, an exception is raised with condition types &lexical
and i/oread
.
(let ([sip (openstringinputport "; a\n\n one (two)\n")])
(let* ([x1 (getdatum sip)]
[c1 (lookaheadchar sip)]
[x2 (getdatum sip)])
(list x1 c1 x2 (porteof? sip)))) ⇒ (one #\space (two) #f)
procedure 

returns 

libraries 

This procedure is similar to lookaheadu8
on a binary input port or lookaheadchar
on a textual input port, except that instead of returning the next byte/character or eof object, it returns a boolean value to indicate whether the value would be the eof object.
Section 7.8. Output Operations
Procedures whose primary purpose is to send data to an output port are described in this section.
procedure 

returns 
unspecified 
libraries 

octet
must be an exact nonnegative integer less than or equal to 255. This procedure writes octet
to binaryoutputport
, advancing the port’s position by one byte.
procedure 

procedure 

procedure 

returns 
unspecified 
libraries 

start
and n
must be nonnegative exact integers, and the sum of start
and n
must not exceed the length of bytevector
. If not supplied, start
defaults to zero and n
defaults to the difference between the length of bytevector
and start
.
This procedure writes the n
bytes of bytevector
starting at start
to the port and advances the its position past the end of the bytes written.
procedure 

returns 
unspecified 
libraries 

This procedure writes char
to textualoutputport
, advancing the port’s position by one character. If textualoutputport
is a transcoded port, the position in the underlying byte stream may advance by more than one byte.
procedure 

procedure 

procedure 

returns 
unspecified 
libraries 

start
and n
must be nonnegative exact integers, and the sum of start
and n
must not exceed the length of string
. If not supplied, start
defaults to zero and n
defaults to the difference between the length of string
and start
.
This procedure writes the n
characters of string
starting at start
to the port and advances the its position past the end of the characters written.
procedure 

returns 
unspecified 
libraries 

This procedure writes an external representation of obj
to textualoutputport
. If obj
does not have an external representation as a datum, the behavior is unspecified. The precise external representation is implementationdependent, but when obj
does have an external representation as a datum, putdatum
should produce a sequence of characters that can later be read by getdatum
as an object equivalent (in the sense of equal?
) to obj
. See Section 12.5 for an implementation of putdatum
, write
, and display
.
procedure 

returns 
unspecified 
libraries 

This procedure forces any bytes or characters in the buffer associated with outputport
to be sent immediately to the underlying stream.
Section 7.9. Convenience I/O
The procedures in this section are referred to as "convenience" I/O operators because they present a somewhat simplified interface for creating and interacting with textual ports. They also provide backward compatibility with the Revised^{5} Report, which did not support separate binary and textual I/O.
The convenience input/output procedures may be called with or without an explicit port argument. If called without an explicit port argument, the current input or output port is used, as appropriate. For example, (readchar)
and (readchar (currentinputport))
both return the next character from the current input port.
procedure 

returns 
a new input port 
libraries 

path
must be a string or some other implementationdependent value that names a file. openinputfile
creates a new textual input port for the file named by path
, as if by openfileinputport
with default options, an implementationdependent buffer mode, and an implementationdependent transcoder.
The following shows the use of openinputfile
, read
, and closeport
in an expression that gathers a list of objects from the file named by "myfile.ss."
(let ([p (openinputfile "myfile.ss")])
(let f ([x (read p)])
(if (eofobject? x)
(begin
(closeport p)
'())
(cons x (f (read p))))))
procedure 

returns 
a new output port 
libraries 

path
must be a string or some other implementationdependent value that names a file. openoutputfile
creates a new output port for the file named by path
, as if by openfileoutputport
with default options, an implementationdependent buffer mode, and an implementationdependent transcoder.
The following shows the use of openoutputfile
to write a list of objects (the value of listtobeprinted
), separated by newlines, to the file named by "myfile.ss."
(let ([p (openoutputfile "myfile.ss")])
(let f ([ls listtobeprinted])
(if (not (null? ls))
(begin
(write (car ls) p)
(newline p)
(f (cdr ls)))))
(closeport p))
procedure 

returns 
the values returned by 
libraries 

path
must be a string or some other implementationdependent value that names a file. procedure
should accept one argument.
callwithinputfile
creates a new input port for the file named by path
, as if with openinputfile
, and passes this port to procedure
. If procedure
returns, callwithinputfile
closes the input port and returns the values returned by procedure
.
callwithinputfile
does not automatically close the input port if a continuation created outside of procedure
is invoked, since it is possible that another continuation created inside of procedure
will be invoked at a later time, returning control to procedure
. If procedure
does not return, an implementation is free to close the input port only if it can prove that the input port is no longer accessible. As shown in Section 5.6, dynamicwind
may be used to ensure that the port is closed if a continuation created outside of procedure
is invoked.
The following example shows the use of callwithinputfile
in an expression that gathers a list of objects from the file named by "myfile.ss." It is functionally equivalent to the example given for openinputfile
above.
(callwithinputfile "myfile.ss"
(lambda (p)
(let f ([x (read p)])
(if (eofobject? x)
'()
(cons x (f (read p)))))))
callwithinputfile
might be defined without error checking as follows.
(define callwithinputfile
(lambda (filename proc)
(let ([p (openinputfile filename)])
(letvalues ([v* (proc p)])
(closeport p)
(apply values v*)))))
procedure 

returns 
the values returned by 
libraries 

path
must be a string or some other implementationdependent value that names a file. procedure
should accept one argument.
callwithoutputfile
creates a new output port for the file named by path
, as if with openoutputfile
, and passes this port to procedure
. If procedure
returns, callwithoutputfile
closes the output port and returns the values returned by procedure
.
callwithoutputfile
does not automatically close the output port if a continuation created outside of procedure
is invoked, since it is possible that another continuation created inside of procedure
will be invoked at a later time, returning control to procedure
. If procedure
does not return, an implementation is free to close the output port only if it can prove that the output port is no longer accessible. As shown in Section 5.6, dynamicwind
may be used to ensure that the port is closed if a continuation created outside of procedure
is invoked.
The following shows the use of callwithoutputfile
to write a list of objects (the value of listtobeprinted
), separated by newlines, to the file named by "myfile.ss." It is functionally equivalent to the example given for openoutputfile
above.
(callwithoutputfile "myfile.ss"
(lambda (p)
(let f ([ls listtobeprinted])
(unless (null? ls)
(write (car ls) p)
(newline p)
(f (cdr ls))))))
callwithoutputfile
might be defined without error checking as follows.
(define callwithoutputfile
(lambda (filename proc)
(let ([p (openoutputfile filename)])
(letvalues ([v* (proc p)])
(closeport p)
(apply values v*)))))
procedure 

returns 
the values returned by 
libraries 

path
must be a string or some other implementationdependent value that names a file. thunk
must be a procedure and should accept zero arguments.
withinputfromfile
temporarily changes the current input port to be the result of opening the file named by path
, as if with openinputfile
, during the application of thunk
. If thunk
returns, the port is closed and the current input port is restored to its old value.
The behavior of withinputfromfile
is unspecified if a continuation created outside of thunk
is invoked before thunk
returns. An implementation may close the port and restore the current input port to its old valuebut it may not.
procedure 

returns 
the values returned by 
libraries 

path
must be a string or some other implementationdependent value that names a file. thunk
must be a procedure and should accept zero arguments.
withoutputtofile
temporarily rebinds the current output port to be the result of opening the file named by path
, as if with openoutputfile
, during the application of thunk
. If thunk
returns, the port is closed and the current output port is restored to its old value.
The behavior of withoutputtofile
is unspecified if a continuation created outside of thunk
is invoked before thunk
returns. An implementation may close the port and restore the current output port to its old valuebut it may not.
procedure 

procedure 

returns 
a Scheme datum object or the eof object 
libraries 

If textualinputport
is not supplied, it defaults to the current input port. This procedure is otherwise equivalent to getdatum
.
procedure 

procedure 

returns 
the next character from 
libraries 

If textualinputport
is not supplied, it defaults to the current input port. This procedure is otherwise equivalent to getchar
.
procedure 

procedure 

returns 
the next character from 
libraries 

If textualinputport
is not supplied, it defaults to the current input port. This procedure is otherwise equivalent to lookaheadchar
.
procedure 

procedure 

returns 
unspecified 
libraries 

If textualoutputport
is not supplied, it defaults to the current output port. This procedure is otherwise equivalent to putdatum
, with the arguments reversed. See Section 12.5 for an implementation of putdatum
, write
, and display
.
procedure 

procedure 

returns 
unspecified 
libraries 

If textualoutputport
is not supplied, it defaults to the current output port.
display
is similar to write
or putdatum
but prints strings and characters found within obj
directly. Strings are printed without quotation marks or escapes for special characters, as if by putstring
, and characters are printed without the #\
notation, as if by putchar
. With display
, the threeelement list (a b c)
and the twoelement list ("a b" c)
both print as (a b c)
. Because of this, display
should not be used to print objects that are intended to be read with read
. display
is useful primarily for printing messages, with obj
most often being a string. See Section 12.5 for an implementation of putdatum
, write
, and display
.
procedure 

procedure 

returns 
unspecified 
libraries 

If textualoutputport
is not supplied, it defaults to the current output port. This procedure is otherwise equivalent to putchar
, with the arguments reversed.
procedure 

procedure 

returns 
unspecified 
libraries 

If textualoutputport
is not supplied, it defaults to the current output port. newline
sends a linefeed character to the port.
procedure 

procedure 

returns 
unspecified 
libraries 

closeinputport
closes an input port, and closeoutputport
closes an output port. These procedures are provided for backward compatibility with the Revised^{5} Report; they are not actually more convenient to use than closeport
.
Section 7.10. Filesystem Operations
Scheme has two standard operations, beyond file input/output, for interacting with the filesystem: fileexists?
and deletefile
. Most implementations support additional operations.
procedure 

returns 

libraries 

path
must be a string or some other implementationdependent value that names a file. Whether fileexists?
follows symbolic links is unspecified.
procedure 

returns 
unspecified 
libraries 

path
must be a string or some other implementationdependent value that names a file. deletefile
removes the file named by path
if it exists and can be deleted, otherwise it raises an exception with condition type &i/ofilename
. Whether deletefile
follows symbolic links is unspecified.
Section 7.11. Bytevector/String Conversions
The procedures described in this section encode or decode character sequences, converting from strings to bytevectors or bytevectors to strings. They do not necessarily involve input/output, though they might be implemented using bytevector input and output ports.
The first two procedures, bytevector>string
and string>bytevector
, take an explicit transcoder argument that determines the character encodings, eol styles, and errorhandling modes. The others perform specific Unicode conversions with an implicit eolstyle of none
and errorhandling mode of replace
.
procedure 

returns 
a string containing the characters encoded in 
libraries 

This operation, at least in effect, creates a bytevector input port with the specified transcoder
from which all of the available characters are read, as if by getstringall
, and placed into the output string.
(let ([tx (maketranscoder (utf8codec) (eolstyle lf)
(errorhandlingmode replace))])
(bytevector>string #vu8(97 98 99) tx)) ⇒ "abc"
procedure 

returns 
a bytevector containing the encodings of the characters in 
libraries 

This operation, at least in effect, creates a bytevector output port with the specified transcoder
to which all of the characters of string
are written, then extracts a bytevector containing the accumulated bytes.
(let ([tx (maketranscoder (utf8codec) (eolstyle none)
(errorhandlingmode raise))])
(string>bytevector "abc" tx)) ⇒ #vu8(97 98 99)
procedure 

returns 
a bytevector containing the UTF8 encoding of 
libraries 

procedure 

procedure 

procedure 

procedure 

returns 
a bytevector containing the specified encoding of 
libraries 

endianness
must be one of the symbols big
or little
. If endianness
is not provided or is the symbol big
, string>utf16
returns the UTF16BE encoding of string
and string>utf32
returns the UTF32BE encoding of string
. If endianness
is the symbol little
, string>utf16
returns the UTF16LE encoding of string
and string>utf32
returns the UTF32LE encoding of string
. No byteorder mark is included in the encoding.
procedure 

returns 
a string containing the UTF8 decoding of 
libraries 

procedure 

procedure 

procedure 

procedure 

returns 
a string containing the specified decoding of 
libraries 

endianness
must be one of the symbols big
or little
. These procedures return a UTF16 or UTF32 decoding of bytevector
, with the endianness of the representation determined from the endianness argument or byteorder mark (BOM). If endiannessmandatory?
is not provided or is #f
, the endianness is determined by a BOM at the front of bytevector
or, if no BOM is present, by endianness
. If endiannessmandatory?
is #t
, the endianness is determined by endianness
, and, if a BOM appears at the front of bytevector
, it is treated as a regular character encoding.
The UTF16 BOM is the twobyte sequence #xFE
, #xFF
specifying "big" or the twobyte sequence #xFF
, #xFE
specifying "little." The UTF32 BOM is the fourbyte sequence #x00
, #x00
, #xFE
, #xFF
specifying "big" or the fourbyte sequence #xFF
, #xFE
, #x00
, #x00
specifying "little."
Chapter 8. Syntactic Extension
Syntactic extensions, or macros, are used to simplify and regularize repeated patterns in a program, to introduce syntactic forms with new evaluation rules, and to perform transformations that help make programs more efficient.
A syntactic extension most often takes the form (keyword subform ...)
, where keyword
is the identifier that names the syntactic extension. The syntax of each subform
varies from one syntactic extension to another. Syntactic extensions can also take the form of improper lists or even singleton identifiers.
New syntactic extensions are defined by associating keywords with transformation procedures, or transformers. Syntactic extensions are defined using definesyntax
forms or using letsyntax
or letrecsyntax
. Transformers may be created using syntaxrules
, which allows simple patternbased transformations to be performed. They may also be ordinary procedures that accept one argument and perform arbitrary computations. In this case, syntaxcase
is normally used to destructure the input and syntax
is normally used to construct the output. The identifiersyntax
form and makevariabletransformer
procedure allow the creation of transformers that match singleton identifiers and assignments to those identifiers, the former being restricted to simple patterns like syntaxrules
and the latter allowing arbitrary computations to be performed.
Syntactic extensions are expanded into core forms at the start of evaluation (before compilation or interpretation) by a syntax expander. If the expander encounters a syntactic extension, it invokes the associated transformer to expand the syntactic extension, then repeats the expansion process for the form returned by the transformer. If the expander encounters a core syntactic form, it recursively processes the subforms, if any, and reconstructs the form from the expanded subforms. Information about identifier bindings is maintained during expansion to enforce lexical scoping for variables and keywords.
The syntactic extension mechanisms described in this chapter are part of the "syntaxcase" system. A portable implementation of the system that also supports libraries and toplevel programs is available at http://www.cs.indiana.edu/syntaxcase/. A description of the motivations behind and implementation of the system can be found in the article "Syntactic Abstraction in Scheme" [12]. Additional features that have not yet been standardized, including modules
, local import
, and meta definitions, are described in the Chez Scheme User’s Guide [9].
Section 8.1. Keyword Bindings
This section describes forms that establish bindings between keywords and transformers. Keyword bindings may be established within a toplevel program or library body using definesyntax
and in any local scope using definesyntax
, letsyntax
, or letrecsyntax
.
syntax 

libraries 

expr
must evaluate to a transformer.
The following example defines let*
as a syntactic extension, specifying the transformer with syntaxrules
(see Section 8.2).
(definesyntax let*
(syntaxrules ()
[(_ () b1 b2 ...) (let () b1 b2 ...)]
[(_ ((i1 e1) (i2 e2) ...) b1 b2 ...)
(let ([i1 e1])
(let* ([i2 e2] ...) b1 b2 ...))]))
All bindings established by a set of internal definitions, whether keyword or variable definitions, are visible everywhere within the immediately enclosing body, including within the definitions themselves. For example, the expression
(let ()
(define even?
(lambda (x)
(or (= x 0) (odd? ( x 1)))))
(definesyntax odd?
(syntaxrules ()
[(_ x) (not (even? x))]))
(even? 10))
is valid and should evaluate to #t
.
The expander processes the initial forms in a library
, lambda
, or other body from left to right. If it encounters a variable definition, it records the fact that the defined identifier is a variable but defers expansion of the righthandside expression until after all of the definitions have been processed. If it encounters a keyword definition, it expands and evaluates the righthandside expression and binds the keyword to the resulting transformer. If it encounters an expression, it fully expands all deferred righthandside expressions along with the current and remaining body expressions.
An implication of the lefttoright processing order is that one internal definition can affect whether a subsequent form is also a definition. For example, the expression
(let ()
(definesyntax bindtozero
(syntaxrules ()
[(_ id) (define id 0)]))
(bindtozero x)
x)
evaluates to 0
, regardless of any binding for bindtozero
that might appear outside of the let
expression.
syntax 

syntax 

returns 
see below 
libraries 

Each expr
must evaluate to a transformer. For letsyntax
and letrecsyntax
both, each keyword
is bound within the forms form_{1} form_{2} ...
. For letrecsyntax
the binding scope also includes each expr
.
A letsyntax
or letrecsyntax
form may expand into one or more expressions anywhere expressions are permitted, in which case the resulting expressions are treated as if enclosed in a begin
expression. It may also expand into zero or more definitions anywhere definitions are permitted, in which case the definitions are treated as if they appeared in place of the letsyntax
or letrecsyntax
form.
The following example highlights how letsyntax
and letrecsyntax
differ.
(let ([f (lambda (x) (+ x 1))])
(letsyntax ([f (syntaxrules ()
[(_ x) x])]
[g (syntaxrules ()
[(_ x) (f x)])])
(list (f 1) (g 1)))) ⇒ (1 2)
(let ([f (lambda (x) (+ x 1))])
(letrecsyntax ([f (syntaxrules ()
[(_ x) x])]
[g (syntaxrules ()
[(_ x) (f x)])])
(list (f 1) (g 1)))) ⇒ (1 1)
The two expressions are identical except that the letsyntax
form in the first expression is a letrecsyntax
form in the second. In the first expression, the f
occurring in g
refers to the let
bound variable f
, whereas in the second it refers to the keyword f
whose binding is established by the letrecsyntax
form.
Section 8.2. SyntaxRules Transformers
The syntaxrules
form described in this section permits simple transformers to be specified in a convenient manner. These transformers may be bound to keywords using the mechanisms described in Section 8.1. While it is much less expressive than the mechanism described in Section 8.3, it is sufficient for defining many common syntactic extensions.
syntax 

returns 
a transformer 
libraries 

Each literal
must be an identifier other than an underscore ( _
) or ellipsis ( ...
). Each clause must take the form below.
(pattern template))
Each pattern
specifies one possible syntax that the input form might take, and the corresponding template
specifies how the output should appear.
Patterns consist of list structure, vector structure, identifiers, and constants. Each identifier within a pattern is either a literal
, a pattern variable, an underscore, or an ellipsis. The identifier _
is an underscore, and the identifier ...
is an ellipsis. Any identifier other than _
or ...
is a literal if it appears in the list of literals (literal ...)
; otherwise, it is a pattern variable. Literals serve as auxiliary keywords, such as else
in case
and cond
expressions. List and vector structure within a pattern specifies the basic structure required of the input, the underscore and pattern variables specify arbitrary substructure, and literals and constants specify atomic pieces that must match exactly. Ellipses specify repeated occurrences of the subpatterns they follow.
An input form F
matches a pattern P
if and only if

P
is an underscore or pattern variable, 
P
is a literal identifier andF
is an identifier with the same binding as determined by the predicatefreeidentifier=?
(Section 8.3), 
P
is of the form(P_{1} ... P_{n})
andF
is a list of n elements that matchP_{1}
throughP_{n}
, 
P
is of the form(P_{1} ... P_{n} . P_{x})
andF
is a list or improper list of n or more elements whose first n elements matchP_{1}
throughP_{n}
and whose nth cdr matchesP_{x}
, 
P
is of the form(P_{1} ... P_{k} P_{e} ellipsis P_{m+1} ... P_{n})
, whereellipsis
is the identifier...
andF
is a proper list of n elements whose first k elements matchP_{1}
throughP_{k}
, whose next m  k elements each matchP_{e}
, and whose remaining n  m elements matchP_{m+1}
throughP_{n}
, 
P
is of the form(P_{1} ... P_{k} P_{e} ellipsis P_{m+1} ... P_{n} . P_{x})
, whereellipsis
is the identifier...
andF
is a list or improper list of n elements whose first k elements matchP_{1}
throughP_{k}
, whose next m  k elements each matchP_{e}
, whose next n  m elements matchP_{m+1}
throughP_{n}
, and whose nth and final cdr matchesP_{x}
, 
P
is of the form#(P_{1} ... P_{n})
andF
is a vector of n elements that matchP_{1}
throughP_{n}
, 
P
is of the form#(P_{1} ... P_{k} P_{e} ellipsis P_{m+1} ... P_{n})
, whereellipsis
is the identifier...
andF
is a vector of n elements whose first k elements matchP_{1}
throughP_{k}
, whose next m  k elements each matchP_{e}
, and whose remaining n  m elements matchP_{m+1}
throughP_{n}
, or 
P
is a pattern datum (any nonlist, nonvector, nonsymbol object) andF
is equal toP
in the sense of theequal?
procedure.
The outermost structure of a syntaxrules
pattern
must actually be in one of the liststructured forms above, although subpatterns of the pattern may be in any of the above forms. Furthermore, the first element of the outermost pattern is ignored, since it is always assumed to be the keyword naming the syntactic form. (These statements do not apply to syntaxcase
; see Section 8.3.)
If an input form passed to a syntaxrules
transformer matches the pattern for a given clause, the clause is accepted and the form is transformed as specified by the associated template. As this transformation takes place, pattern variables appearing in the pattern are bound to the corresponding input subforms. Pattern variables appearing within a subpattern followed by one or more ellipses may be bound to a sequence or sequences of zero or more input subforms.
A template is a pattern variable, an identifier that is not a pattern variable, a pattern datum, a list of subtemplates (S_{1} ... S_{n})
, an improper list of subtemplates (S_{1} S_{2} ... S_{n} . T)
, or a vector of subtemplates #(S_{1} ... S_{n})
. Each subtemplate S_{i}
is a template followed by zero or more ellipses. The final element T
of an improper subtemplate list is a template.
Pattern variables appearing within a template are replaced in the output by the input subforms to which they are bound. Pattern data and identifiers that are not pattern variables are inserted directly into the output. List and vector structure within the template remains list and vector structure in the output. A subtemplate followed by an ellipsis expands into zero or more occurrences of the subtemplate. The subtemplate must contain at least one pattern variable from a subpattern followed by an ellipsis. (Otherwise, the expander could not determine how many times the subform should be repeated in the output.) Pattern variables that occur in subpatterns followed by one or more ellipses may occur only in subtemplates that are followed by (at least) as many ellipses. These pattern variables are replaced in the output by the input subforms to which they are bound, distributed as specified. If a pattern variable is followed by more ellipses in the template than in the associated pattern, the input form is replicated as necessary.
A template of the form (... template)
is identical to template
, except that ellipses within the template have no special meaning. That is, any ellipses contained within template
are treated as ordinary identifiers. In particular, the template (... ...)
produces a single ellipsis, ...
. This allows syntactic extensions to expand into forms containing ellipses, including syntaxrules
or syntaxcase
patterns and templates.
The definition of or
below demonstrates the use of syntaxrules
.
(definesyntax or
(syntaxrules ()
[(_) #f]
[(_ e) e]
[(_ e1 e2 e3 ...)
(let ([t e1]) (if t t (or e2 e3 ...)))]))
The input patterns specify that the input must consist of the keyword and zero or more subexpressions. An underscore ( _
), which is a special pattern symbol that matches any input, is often used for the keyword position to remind the programmer and anyone reading the definition that the keyword position never fails to contain the expected keyword and need not be matched. (In fact, as mentioned above, syntaxrules
ignores what appears in the keyword position.) If more than one subexpression is present (third clause), the expanded code both tests the value of the first subexpression and returns the value if it is not false. To avoid evaluating the expression twice, the transformer introduces a binding for the temporary variable t
.
The expansion algorithm maintains lexical scoping automatically by renaming local identifiers as necessary. Thus, the binding for t
introduced by the transformer is visible only within code introduced by the transformer and not within subforms of the input. Similarly, the references to the identifiers let
and if
are unaffected by any bindings present in the context of the input.
(let ([if #f])
(let ([t 'okay])
(or if t))) ⇒ okay
This expression is transformed during expansion to the equivalent of the expression below.
((lambda (if1)
((lambda (t1)
((lambda (t2)
(if t2 t2 t1))
if1))
'okay))
#f) ⇒ okay
In this sample expansion, if1
, t1
, and t2
represent identifiers to which if
and t
in the original expression and t
in the expansion of or
have been renamed.
The definition of a simplified version of cond
below (simplified because it requires at least one output expression per clause and does not support the auxiliary keyword =>
) demonstrates how auxiliary keywords such as else
are recognized in the input to a transformer, via inclusion in the list of literals.
(definesyntax cond
(syntaxrules (else)
[(_ (else e1 e2 ...)) (begin e1 e2 ...)]
[(_ (e0 e1 e2 ...)) (if e0 (begin e1 e2 ...))]
[(_ (e0 e1 e2 ...) c1 c2 ...)
(if e0 (begin e1 e2 ...) (cond c1 c2 ...))]))
syntax 

syntax 

libraries 

These identifiers are auxiliary keywords for syntaxrules
, identifiersyntax
, and syntaxcase
. The second ( ...
) is also an auxiliary keyword for syntax
and quasisyntax
. It is a syntax violation to reference these identifiers except in contexts where they are recognized as auxiliary keywords.
syntax 

syntax 

returns 
a transformer 
libraries 

When a keyword is bound to a transformer produced by the first form of identifiersyntax
, references to the keyword within the scope of the binding are replaced by tmpl
.
(let ()
(definesyntax a (identifiersyntax car))
(list (a '(1 2 3)) a)) ⇒ (1 #<procedure>)
With the first form of identifiersyntax
, an apparent assignment of the associated keyword with set!
is a syntax violation. The second, more general, form of identifiersyntax
permits the transformer to specify what happens when set!
is used.
(let ([ls (list 0)])
(definesyntax a
(identifiersyntax
[id (car ls)]
[(set! id e) (setcar! ls e)]))
(let ([before a])
(set! a 1)
(list before a ls))) ⇒ (0 1 (1))
A definition of identifiersyntax
in terms of makevariabletransformer
is shown on page 307.
Section 8.3. SyntaxCase Transformers
This section describes a more expressive mechanism for creating transformers, based on syntaxcase
, a generalized version of syntaxrules
. This mechanism permits arbitrarily complex transformations to be specified, including transformations that "bend" lexical scoping in a controlled manner, allowing a much broader class of syntactic extensions to be defined. Any transformer that may be defined using syntaxrules
may be rewritten easily to use syntaxcase
instead; in fact, syntaxrules
itself may be defined as a syntactic extension in terms of syntaxcase
, as demonstrated within the description of syntax
below.
With this mechanism, transformers are procedures of one argument. The argument is a syntax object representing the form to be processed. The return value is a syntax object representing the output form. A syntax object may be any of the following.

a nonpair, nonvector, nonsymbol value,

a pair of syntax objects,

a vector of syntax objects, or

a wrapped object.
The wrap on a wrapped syntax object contains contextual information about a form in addition to its structure. This contextual information is used by the expander to maintain lexical scoping. The wrap may also contain information used by the implementation to correlate source and object code, e.g., track file, line, and character information through the expansion and compilation process.
The contextual information must be present for all identifiers, which is why the definition of syntax object above does not allow symbols unless they are wrapped. A syntax object representing an identifier is itself referred to as an identifier; thus, the term identifier may refer either to the syntactic entity (symbol, variable, or keyword) or to the concrete representation of the syntactic entity as a syntax object.
Transformers normally destructure their input with syntaxcase
and rebuild their output with syntax
. These two forms alone are sufficient for defining many syntactic extensions, including any that can be defined using syntaxrules
. They are described below along with a set of additional forms and procedures that provide added functionality.
syntax 

returns 
see below 
libraries 

Each literal
must be an identifier. Each clause
must take one of the following two forms.
(pattern outputexpression)
(pattern fender outputexpression)
syntaxcase
patterns may be in any of the forms described in Section 8.2.
syntaxcase
first evaluates expr
, then attempts to match the resulting value against the pattern from the first clause
. This value may be any Scheme object. If the value matches the pattern and no fender
is present, outputexpression
is evaluated and its values returned as the values of the syntaxcase
expression. If the value does not match the pattern, the value is compared against the next clause, and so on. It is a syntax violation if the value does not match any of the patterns.
If the optional fender
is present, it serves as an additional constraint on acceptance of a clause. If the value of the syntaxcase
expr
matches the pattern for a given clause, the corresponding fender
is evaluated. If fender
evaluates to a true value, the clause is accepted; otherwise, the clause is rejected as if the input had failed to match the pattern. Fenders are logically a part of the matching process, i.e., they specify additional matching constraints beyond the basic structure of an expression.
Pattern variables contained within a clause’s pattern
are bound to the corresponding pieces of the input value within the clause’s fender
(if present) and outputexpression
. Pattern variables occupy the same namespace as program variables and keywords; pattern variable bindings created by syntaxcase
can shadow (and be shadowed by) program variable and keyword bindings as well as other pattern variable bindings. Pattern variables, however, can be referenced only within syntax
expressions.
See the examples following the description of syntax
.
syntax 

syntax 

returns 
see below 
libraries 

#'template
is equivalent to (syntax template)
. The abbreviated form is converted into the longer form when a program is read, prior to macro expansion.
A syntax
expression is like a quote
expression except that the values of pattern variables appearing within template
are inserted into template
, and contextual information associated both with the input and with the template is retained in the output to support lexical scoping. A syntax
template
is identical to a syntaxrules
template
and is treated similarly.
List and vector structures within the template become true lists or vectors (suitable for direct application of list or vector operations, like map
or vectorref
) to the extent that the list or vector structures must be copied to insert the values of pattern variables, and empty lists are never wrapped. For example, #'(x ...)
, #'(a b c)
, #'()
are all lists if x
, a
, b
, and c
are pattern variables.
The definition of or
below is equivalent to the one given in Section 8.2 except that it employs syntaxcase
and syntax
in place of syntaxrules
.
(definesyntax or
(lambda (x)
(syntaxcase x ()
[(_) #'#f]
[(_ e) #'e]
[(_ e1 e2 e3 ...)
#'(let ([t e1]) (if t t (or e2 e3 ...)))])))
In this version, the lambda
expression that produces the transformer is explicit, as are the syntax
forms in the output part of each clause. Any syntaxrules
form can be expressed with syntaxcase
by making the lambda
expression and syntax
expressions explicit. This observation leads to the following definition of syntaxrules
in terms of syntaxcase
.
(definesyntax syntaxrules
(lambda (x)
(syntaxcase x ()
[(_ (i ...) ((keyword . pattern) template) ...)
#'(lambda (x)
(syntaxcase x (i ...)
[(_ . pattern) #'template] ...))])))
An underscore is used in place of each keyword
since the first position of each syntaxrules
pattern is always ignored.
Since the lambda
and syntax
expressions are implicit in a syntaxrules
form, definitions expressed with syntaxrules
are often shorter than the equivalent definitions expressed with syntaxcase
. The choice of which to use when either suffices is a matter of taste, but many transformers that can be written easily with syntaxcase
cannot be written easily or at all with syntaxrules
(see Section 8.4).
procedure 

returns 

libraries 

identifier?
is often used within fenders to verify that certain subforms of an input form are identifiers, as in the definition of unnamed let
below.
(definesyntax let
(lambda (x)
(define ids?
(lambda (ls)
(or (null? ls)
(and (identifier? (car ls))
(ids? (cdr ls))))))
(syntaxcase x ()
[(_ ((i e) ...) b1 b2 ...)
(ids? #'(i ...))
#'((lambda (i ...) b1 b2 ...) e ...)])))
Syntactic extensions ordinarily take the form (keyword subform ...)
, but the syntaxcase
system permits them to take the form of singleton identifiers as well. For example, the keyword pcar
in the expression below may be used both as an identifier (in which case it expands into a call to car
) or as a structured form (in which case it expands into a call to setcar!
).
(let ([p (cons 0 #f)])
(definesyntax pcar
(lambda (x)
(syntaxcase x ()
[_ (identifier? x) #'(car p)]
[(_ e) #'(setcar! p e)])))
(let ([a pcar])
(pcar 1)
(list a pcar))) ⇒ (0 1)
The fender (identifier? x)
is used to recognize the singleton identifier case.
procedure 

procedure 

returns 
see below 
libraries 

Symbolic names alone do not distinguish identifiers unless the identifiers are to be used only as symbolic data. The predicates freeidentifier=?
and boundidentifier=?
are used to compare identifiers according to their intended use as free references or bound identifiers in a given context.
freeidentifier=?
is used to determine whether two identifiers would be equivalent if they were to appear as free identifiers in the output of a transformer. Because identifier references are lexically scoped, this means (freeidentifier=? id_{1} id_{2})
is true if and only if the identifiers id_{1}
and id_{2}
refer to the same binding. (For this comparison, two likenamed identifiers are assumed to have the same binding if neither is bound.) Literal identifiers (auxiliary keywords) appearing in syntaxcase
patterns (such as else
in case
and cond
) are matched with freeidentifier=?
.
Similarly, boundidentifier=?
is used to determine whether two identifiers would be equivalent if they were to appear as bound identifiers in the output of a transformer. In other words, if boundidentifier=?
returns true for two identifiers, a binding for one will capture references to the other within its scope. In general, two identifiers are boundidentifier=?
only if both are present in the original program or both are introduced by the same transformer application (perhaps implicitlysee datum>syntax
). boundidentifier=?
can be used for detecting duplicate identifiers in a binding construct or for other preprocessing of a binding construct that requires detecting instances of the bound identifiers.
The definition below is equivalent to the earlier definition of a simplified version of cond
with syntaxrules
, except that else
is recognized via an explicit call to freeidentifier?
within a fender rather than via inclusion in the literals list.
(definesyntax cond
(lambda (x)
(syntaxcase x ()
[(_ (e0 e1 e2 ...))
(and (identifier? #'e0) (freeidentifier=? #'e0 #'else))
#'(begin e1 e2 ...)]
[(_ (e0 e1 e2 ...)) #'(if e0 (begin e1 e2 ...))]
[(_ (e0 e1 e2 ...) c1 c2 ...)
#'(if e0 (begin e1 e2 ...) (cond c1 c2 ...))])))
With either definition of cond
, else
is not recognized as an auxiliary keyword if an enclosing lexical binding for else
exists. For example,
(let ([else #f])
(cond [else (write "oops")]))
does not write "oops"
, since else
is bound lexically and is therefore not the same else
that appears in the definition of cond
.
The following definition of unnamed let
uses boundidentifier=?
to detect duplicate identifiers.
(definesyntax let
(lambda (x)
(define ids?
(lambda (ls)
(or (null? ls)
(and (identifier? (car ls)) (ids? (cdr ls))))))
(define uniqueids?
(lambda (ls)
(or (null? ls)
(and (not (memp
(lambda (x) (boundidentifier=? x (car ls)))
(cdr ls)))
(uniqueids? (cdr ls))))))
(syntaxcase x ()
[(_ ((i e) ...) b1 b2 ...)
(and (ids? #'(i ...)) (uniqueids? #'(i ...)))
#'((lambda (i ...) b1 b2 ...) e ...)])))
With the definition of let
above, the expression
(let ([a 3] [a 4]) (+ a a))
is a syntax violation, whereas
(let ([a 0])
(letsyntax ([dolet (lambda (x)
(syntaxcase x ()
[(_ b)
#'(let ([a 3] [b 4]) (+ a b))]))])
(dolet a)))
evaluates to 7
since the identifier a
introduced by dolet
and the identifier a
extracted from the input form are not boundidentifier=?
. Since both occurrences of a
, however, if left as free references, would refer to the same binding for a
, freeidentifier=?
would not distinguish them.
Two identifiers that are freeidentifier=?
may not be boundidentifier=?
. An identifier introduced by a transformer may refer to the same enclosing binding as an identifier not introduced by the transformer, but an introduced binding for one will not capture references to the other. On the other hand, identifiers that are boundidentifier=?
are freeidentifier=?
, as long as the identifiers have valid bindings in the context where they are compared.
syntax 

returns 
the values of the final body expression 
libraries 

It is sometimes useful to construct a transformer’s output in separate pieces, then put the pieces together. withsyntax
facilitates this by allowing the creation of local pattern bindings.
pattern
is identical in form to a syntaxcase
pattern. The value of each expr
is computed and destructured according to the corresponding pattern
, and pattern variables within the pattern
are bound as with syntaxcase
to appropriate portions of the value within the body body_{1} body_{2} ...
, which is processed and evaluated like a lambda
body.
withsyntax
may be defined as a syntactic extension in terms of syntaxcase
.
(definesyntax withsyntax
(lambda (x)
(syntaxcase x ()
[(_ ((p e) ...) b1 b2 ...)
#'(syntaxcase (list e ...) ()
[(p ...) (let () b1 b2 ...)])])))
The following definition of full cond
demonstrates the use of withsyntax
to support transformers that employ recursion internally to construct their output.
(definesyntax cond
(lambda (x)
(syntaxcase x ()
[(_ c1 c2 ...)
(let f ([c1 #'c1] [cmore #'(c2 ...)])
(if (null? cmore)
(syntaxcase c1 (else =>)
[(else e1 e2 ...) #'(begin e1 e2 ...)]
[(e0) #'(let ([t e0]) (if t t))]
[(e0 => e1) #'(let ([t e0]) (if t (e1 t)))]
[(e0 e1 e2 ...) #'(if e0 (begin e1 e2 ...))])
(withsyntax ([rest (f (car cmore) (cdr cmore))])
(syntaxcase c1 (=>)
[(e0) #'(let ([t e0]) (if t t rest))]
[(e0 => e1) #'(let ([t e0]) (if t (e1 t) rest))]
[(e0 e1 e2 ...)
#'(if e0 (begin e1 e2 ...) rest)]))))])))
syntax 

syntax 

syntax 

syntax 

syntax 

syntax 

returns 
see below 
libraries 

#`template
is equivalent to (quasisyntax template)
, while #,template
is equivalent to (unsyntax template)
, and #,@template
to (unsyntaxsplicing template)
. The abbreviated forms are converted into the longer forms when the program is read, prior to macro expansion.
quasisyntax
is similar to syntax
, but it allows parts of the quoted text to be evaluated, in a manner similar to quasiquote
(Section 6.1).
Within a quasisyntax
template
, subforms of unsyntax
and unsyntaxsplicing
forms are evaluated, and everything else is treated as ordinary template material, as with syntax
. The value of each unsyntax
subform is inserted into the output in place of the unsyntax
form, while the value of each unsyntaxsplicing
subform is spliced into the surrounding list or vector structure. unsyntax
and unsyntaxsplicing
are valid only within quasisyntax
expressions.
quasisyntax
expressions may be nested, with each quasisyntax
introducing a new level of syntax quotation and each unsyntax
or unsyntaxsplicing
taking away a level of quotation. An expression nested within n quasisyntax
expressions must be within n unsyntax
or unsyntaxsplicing
expressions to be evaluated.
quasisyntax
can be used in place of withsyntax
in many cases. For example, the following definition of case
employs quasisyntax
to construct its output, using internal recursion in a manner similar to the definition of cond
given under the description of withsyntax
above.
(definesyntax case
(lambda (x)
(syntaxcase x ()
[(_ e c1 c2 ...)
#`(let ([t e])
#,(let f ([c1 #'c1] [cmore #'(c2 ...)])
(if (null? cmore)
(syntaxcase c1 (else)
[(else e1 e2 ...) #'(begin e1 e2 ...)]
[((k ...) e1 e2 ...)
#'(if (memv t '(k ...)) (begin e1 e2 ...))])
(syntaxcase c1 ()
[((k ...) e1 e2 ...)
#`(if (memv t '(k ...))
(begin e1 e2 ...)
#,(f (car cmore) (cdr cmore)))]))))])))
unsyntax
and unsyntaxsplicing
forms that contain zero or more than one subform are valid only in splicing (list or vector) contexts. (unsyntax template ...)
is equivalent to (unsyntax template) ...
, and (unsyntaxsplicing template ...)
is equivalent to (unsyntaxsplicing template) ...
. These forms are primarily useful as intermediate forms in the output of the quasisyntax
expander. They support certain useful nested quasiquotation (quasisyntax
) idioms [3], such as #,@#,@
, which has the effect of a doubly indirect splicing when used within a doubly nested and doubly evaluated quasisyntax
expression, as with the nested quasiquote
examples shown in Section 6.1.
unsyntax
and unsyntaxsplicing
are auxiliary keywords for quasisyntax
. It is a syntax violation to reference these identifiers except in contexts where they are recognized as auxiliary keywords.
procedure  
returns 
a variable transformer 
libraries 

As described in the leadin to this section, transformers may simply be procedures that accept one argument, a syntax object representing the input form, and return a new syntax object representing the output form. The form passed to a transformer usually represents a parenthesized form whose first subform is the keyword bound to the transformer or just the keyword itself. makevariabletransformer
may be used to convert a procedure into a special kind of transformer to which the expander also passes set!
forms in which the keyword appears just after the set!
keyword, as if it were a variable to be assigned. This allows the programmer to control what happens when the keyword appears in such contexts. The argument, procedure
, should accept one argument.
(let ([ls (list 0)])
(definesyntax a
(makevariabletransformer
(lambda (x)
(syntaxcase x ()
[id (identifier? #'id) #'(car ls)]
[(set! _ e) #'(setcar! ls e)]
[(_ e ...) #'((car ls) e ...)]))))
(let ([before a])
(set! a 1)
(list before a ls))) ⇒ (0 1 (1))
This syntactic abstraction can be defined more succinctly using identifiersyntax
, as shown in Section 8.2, but makevariabletransformer
can be used to create transformers that perform arbitrary computations, while identifiersyntax
is limited to simple term rewriting, like syntaxrules
. identifiersyntax
can be defined in terms of makevariabletransformer
, as shown below.
(definesyntax identifiersyntax
(lambda (x)
(syntaxcase x (set!)
[(_ e)
#'(lambda (x)
(syntaxcase x ()
[id (identifier? #'id) #'e]
[(_ x (... ...)) #'(e x (... ...))]))]
[(_ (id exp1) ((set! var val) exp2))
(and (identifier? #'id) (identifier? #'var))
#'(makevariabletransformer
(lambda (x)
(syntaxcase x (set!)
[(set! var val) #'exp2]
[(id x (... ...)) #'(exp1 x (... ...))]
[id (identifier? #'id) #'exp1])))])))
procedure 

returns 

libraries 

The procedure syntax>datum
strips all syntactic information from a syntax object and returns the corresponding Scheme "datum." Identifiers stripped in this manner are converted to their symbolic names, which can then be compared with eq?
. Thus, a predicate symbolicidentifier=?
might be defined as follows.
(define symbolicidentifier=?
(lambda (x y)
(eq? (syntax>datum x)
(syntax>datum y))))
Two identifiers that are freeidentifier=?
need not be symbolicidentifier=?
: two identifiers that refer to the same binding usually have the same name, but the rename
and prefix
subforms of the library’s import
form (page 345) may result in two identifiers with different names but the same binding.
procedure 

returns 
a syntax object 
libraries 

datum>syntax
constructs a syntax object from obj
that contains the same contextual information as templateidentifier
, with the effect that the syntax object behaves as if it were introduced into the code when templateidentifier
was introduced. The template identifier is often the keyword of an input form, extracted from the form, and the object is often a symbol naming an identifier to be constructed.
datum>syntax
allows a transformer to "bend" lexical scoping rules by creating implicit identifiers that behave as if they were present in the input form, thus permitting the definition of syntactic extensions that introduce visible bindings for or references to identifiers that do not appear explicitly in the input form. For example, we can define a loop
expression that binds the variable break
to an escape procedure within the loop body.
(definesyntax loop
(lambda (x)
(syntaxcase x ()
[(k e ...)
(withsyntax ([break (datum>syntax #'k 'break)])
#'(call/cc
(lambda (break)
(let f () e ... (f)))))])))
(let ([n 3] [ls '()])
(loop
(if (= n 0) (break ls))
(set! ls (cons 'a ls))
(set! n ( n 1)))) ⇒ (a a a)
Were we to define loop
as
(definesyntax loop
(lambda (x)
(syntaxcase x ()
[(_ e ...)
#'(call/cc
(lambda (break)
(let f () e ... (f))))])))
the variable break
would not be visible in e ...
.
It is also useful for obj
to represent an arbitrary Scheme form, as demonstrated by the following definition of include
.
(definesyntax include
(lambda (x)
(define readfile
(lambda (fn k)
(let ([p (openinputfile fn)])
(let f ([x (read p)])
(if (eofobject? x)
(begin (closeport p) '())
(cons (datum>syntax k x) (f (read p))))))))
(syntaxcase x ()
[(k filename)
(let ([fn (syntax>datum #'filename)])
(withsyntax ([(expr ...) (readfile fn #'k)])
#'(begin expr ...)))])))
(include "filename")
expands into a begin
expression containing the forms found in the file named by "filename"
. For example, if the file fdef.ss
contains the expression (define f (lambda () x))
, the expression
(let ([x "okay"])
(include "fdef.ss")
(f))
evaluates to "okay"
.
The definition of include
uses datum>syntax
to convert the objects read from the file into syntax objects in the proper lexical context, so that identifier references and definitions within those expressions are scoped where the include
form appears.
procedure 

returns 
a list of distinct generated identifiers 
libraries 

Transformers can introduce a fixed number of identifiers into their output by naming each identifier. In some cases, however, the number of identifiers to be introduced depends upon some characteristic of the input expression. A straightforward definition of letrec
, for example, requires as many temporary identifiers as there are binding pairs in the input expression. The procedure generatetemporaries
is used to construct lists of temporary identifiers.
list
may be any list; its contents are not important. The number of temporaries generated is the number of elements in list
. Each temporary is guaranteed to be different from all other identifiers.
A definition of letrec
that uses generatetemporaries
is shown below.
(definesyntax letrec
(lambda (x)
(syntaxcase x ()
[(_ ((i e) ...) b1 b2 ...)
(withsyntax ([(t ...) (generatetemporaries #'(i ...))])
#'(let ([i #f] ...)
(let ([t e] ...)
(set! i t)
...
(let () b1 b2 ...))))])))
Any transformer that uses generatetemporaries
in this fashion can be rewritten to avoid using it, albeit with a loss of clarity. The trick is to use a recursively defined intermediate form that generates one temporary per expansion step and completes the expansion after enough temporaries have been generated. Here is a definition of letvalues
(page 99) that uses this technique to support multiple sets of bindings.
(definesyntax letvalues
(syntaxrules ()
[(_ () f1 f2 ...) (let () f1 f2 ...)]
[(_ ((fmls1 expr1) (fmls2 expr2) ...) f1 f2 ...)
(lvhelp fmls1 () () expr1 ((fmls2 expr2) ...) (f1 f2 ...))]))
(definesyntax lvhelp
(syntaxrules ()
[(_ (x1 . fmls) (x ...) (t ...) e m b)
(lvhelp fmls (x ... x1) (t ... tmp) e m b)]
[(_ () (x ...) (t ...) e m b)
(callwithvalues
(lambda () e)
(lambda (t ...)
(letvalues m (let ([x t] ...) . b))))]
[(_ xr (x ...) (t ...) e m b)
(callwithvalues
(lambda () e)
(lambda (t ... . tmpr)
(letvalues m (let ([x t] ... [xr tmpr]) . b))))]))
The implementation of lvhelp
is complicated by the need to evaluate all of the righthandside expressions before creating any of the bindings and by the need to support improper formals lists.
Section 8.4. Examples
This section presents a series of illustrative syntactic extensions defined with either syntaxrules
or syntaxcase
, starting with a few simple but useful syntactic extensions and ending with a fairly complex mechanism for defining structures with automatically generated constructors, predicates, field accessors, and field setters.
The simplest example in this section is the following definition of rec
. rec
is a syntactic extension that permits internally recursive anonymous (not externally named) procedures to be created with minimal effort.
(definesyntax rec
(syntaxrules ()
[(_ x e) (letrec ([x e]) x)]))
(map (rec sum
(lambda (x)
(if (= x 0)
0
(+ x (sum ( x 1))))))
'(0 1 2 3 4 5)) ⇒ (0 1 3 6 10 15)
Using rec
, we can define the full let
(both unnamed and named) as follows.
(definesyntax let
(syntaxrules ()
[(_ ((x e) ...) b1 b2 ...)
((lambda (x ...) b1 b2 ...) e ...)]
[(_ f ((x e) ...) b1 b2 ...)
((rec f (lambda (x ...) b1 b2 ...)) e ...)]))
We can also define let
directly in terms of letrec
, although the definition is a bit less clear.
(definesyntax let
(syntaxrules ()
[(_ ((x e) ...) b1 b2 ...)
((lambda (x ...) b1 b2 ...) e ...)]
[(_ f ((x e) ...) b1 b2 ...)
((letrec ([f (lambda (x ...) b1 b2 ...)]) f) e ...)]))
These definitions rely upon the fact that the first pattern cannot match a named let
, since the first subform of a named let
must be an identifier, not a list of bindings. The following definition uses a fender to make this check more robust.
(definesyntax let
(lambda (x)
(syntaxcase x ()
[(_ ((x e) ...) b1 b2 ...)
#'((lambda (x ...) b1 b2 ...) e ...)]
[(_ f ((x e) ...) b1 b2 ...)
(identifier? #'f)
#'((rec f (lambda (x ...) b1 b2 ...)) e ...)])))
With the fender, we can even put the clauses in the opposite order.
(definesyntax let
(lambda (x)
(syntaxcase x ()
[(_ f ((x e) ...) b1 b2 ...)
(identifier? #'f)
#'((rec f (lambda (x ...) b1 b2 ...)) e ...)]
[(_ ((x e) ...) b1 b2 ...)
#'((lambda (x ...) b1 b2 ...) e ...)])))
To be completely robust, the ids?
and uniqueids?
checks employed in the definition of unnamed let
in Section 8.3 should be employed here as well.
Both variants of let
are easily described by simple oneline patterns, but do
requires a bit more work. The precise syntax of do
cannot be expressed directly with a single pattern because some of the bindings in a do
expression’s binding list may take the form (var val)
while others take the form (var val update)
. The following definition of do
uses syntaxcase
internally to parse the bindings separately from the overall form.
(definesyntax do
(lambda (x)
(syntaxcase x ()
[(_ (binding ...) (test res ...) expr ...)
(withsyntax ([((var val update) ...)
(map (lambda (b)
(syntaxcase b ()
[(var val) #'(var val var)]
[(var val update) #'(var val update)]))
#'(binding ...))])
#'(let doloop ([var val] ...)
(if test
(begin (if #f #f) res ...)
(begin expr ... (doloop update ...)))))])))
The oddlooking expression (if #f #f)
is inserted before the result expressions res ...
in case no result expressions are provided, since begin
requires at least one subexpression. The value of (if #f #f)
is unspecified, which is what we want since the value of do
is unspecified if no result expressions are provided. At the expense of a bit more code, we could use syntaxcase
to determine whether any result expressions are provided and to produce a loop with either a one or twoarmed if
as appropriate. The resulting expansion would be cleaner but semantically equivalent.
As mentioned in Section 8.2, ellipses lose their special meaning within templates of the form (... template)
. This fact allows syntactic extensions to expand into syntax definitions containing ellipses. This usage is illustrated by the definition below of belikebegin
.
(definesyntax belikebegin
(syntaxrules ()
[(_ name)
(definesyntax name
(syntaxrules ()
[(_ e0 e1 (... ...))
(begin e0 e1 (... ...))]))]))
With belikebegin
defined in this manner, (belikebegin sequence)
has the same effect as the following definition of sequence
.
(definesyntax sequence
(syntaxrules ()
[(_ e0 e1 ...) (begin e0 e1 ...)]))
That is, a sequence
form becomes equivalent to a begin
form so that, for example:
(sequence (display "Say what?") (newline))
prints "Say what?" followed by a newline.
The following example shows how one might restrict if
expressions within a given expression to require the "else" (alternative) subexpression by defining a local if
in terms of the builtin if
. Within the body of the letsyntax
binding below, twoarmed if
works as always:
(letsyntax ([if (lambda (x)
(syntaxcase x ()
[(_ e1 e2 e3)
#'(if e1 e2 e3)]))])
(if (< 1 5) 2 3)) ⇒ 2
but onearmed if results in a syntax error.
(letsyntax ([if (lambda (x)
(syntaxcase x ()
[(_ e1 e2 e3)
#'(if e1 e2 e3)]))])
(if (< 1 5) 2)) ⇒ syntax violation
Although this local definition of if
looks simple enough, there are a few subtle ways in which an attempt to write it might go wrong. If letrecsyntax
were used in place of letsyntax
, the identifier if
inserted into the output would refer to the local if
rather than the builtin if
, and expansion would loop indefinitely.
Similarly, if the underscore were replaced with the identifier if
, expansion would again loop indefinitely. The if
appearing in the template (if e1 e2 e3)
would be treated as a pattern variable bound to the corresponding identifier if
from the input form, which denotes the local version of if
.
Placing if
in the list of literals in an attempt to patch up the latter version would not work either. This would cause syntaxcase
to compare the literal if
in the pattern, which would be scoped outside the letsyntax
expression, with the if
in the input expression, which would be scoped inside the letsyntax
. Since they would not refer to the same binding, they would not be freeidentifier=?
, and a syntax violation would result.
The conventional use of underscore ( _
) helps the programmer avoid situations like these in which the wrong identifier is matched against or inserted by accident.
It is a syntax violation to generate a reference to an identifier that is not present within the context of an input form, which can happen if the "closest enclosing lexical binding" for an identifier inserted into the output of a transformer does not also enclose the input form. For example,
(letsyntax ([divide (lambda (x)
(let ([/ +])
(syntaxcase x ()
[(_ e1 e2) #'(/ e1 e2)])))])
(let ([/ *]) (divide 2 1)))
should result in a syntax violation with a message to the effect that /
is referenced in an invalid context, since the occurrence of /
in the output of divide
is a reference to the variable /
bound by the let
expression within the transformer.
The next example defines a defineintegrable
form that is similar to define
for procedure definitions except that it causes the code for the procedure to be integrated, or inserted, wherever a direct call to the procedure is found.
(definesyntax defineintegrable
(syntaxrules (lambda)
[(_ name (lambda formals form1 form2 ...))
(begin
(define xname (lambda formals form1 form2 ...))
(definesyntax name
(lambda (x)
(syntaxcase x ()
[_ (identifier? x) #'xname]
[(_ arg (... ...))
#'((lambda formals form1 form2 ...)
arg
(... ...))]))))]))
The form (defineintegrable name lambdaexpression)
expands into a pair of definitions: a syntax definition of name
and a variable definition of xname
. The transformer for name
converts apparent calls to name
into direct calls to lambdaexpression
. Since the resulting forms are merely direct lambda
applications (the equivalent of let
expressions), the actual parameters are evaluated exactly once and before evaluation of the procedure’s body, as required. All other references to name
are replaced with references to xname
. The definition of xname
binds it to the value of lambdaexpression
. This allows the procedure to be used as a firstclass value. The defineintegrable
transformer does nothing special to maintain lexical scoping within the lambda
expression or at the call site, since lexical scoping is maintained automatically by the expander. Also, because xname
is introduced by the transformer, the binding for xname
is not visible anywhere except where references to it are introduced by the the transformer for name
.
The above definition of defineintegrable
does not work for recursive procedures, since a recursive call would cause an indefinite number of expansion steps, likely resulting in exhaustion of memory at expansion time. A solution to this problem for directly recursive procedures is to wrap each occurrence of the lambda
expression with a letsyntax
binding that unconditionally expands name
to xname
.
(definesyntax defineintegrable
(syntaxrules (lambda)
[(_ name (lambda formals form1 form2 ...))
(begin
(define xname
(letsyntax ([name (identifiersyntax xname)])
(lambda formals form1 form2 ...)))
(definesyntax name
(lambda (x)
(syntaxcase x ()
[_ (identifier? x) #'xname]
[(_ arg (... ...))
#'((letsyntax ([name (identifiersyntax xname)])
(lambda formals form1 form2 ...))
arg (... ...))]))))]))
This problem can be solved for mutually recursive procedures by replacing the letsyntax
forms with the nonstandard fluidletsyntax
form, which is described in the Chez Scheme User’s Guide [9].
Both definitions of defineintegrable
treat the case where an identifier appears in the first position of a structured expression differently from the case where it appears elsewhere, as does the pcar
example given in the description for identifier?
. In other situations, both cases must be treated the same. The form identifiersyntax
can make doing so more convenient.
(let ([x 0])
(definesyntax x++
(identifiersyntax
(let ([t x])
(set! x (+ t 1)) t)))
(let ([a x++]) (list a x))) ⇒ (0 1)
The following example uses identifiersyntax
, datum>syntax
, and local syntax definitions to define a form of method, one of the basic building blocks of objectoriented programming (OOP) systems. A method
expression is similar to a lambda
expression, except that in addition to the formal parameters and body, a method
expression also contains a list of instance variables (ivar ...)
. When a method is invoked, it is always passed an object (instance), represented as a vector of fields corresponding to the instance variables, and zero or more additional arguments. Within the method body, the object is bound implicitly to the identifier self
and the additional arguments are bound to the formal parameters. The fields of the object may be accessed or altered within the method body via instance variable references or assignments.
(definesyntax method
(lambda (x)
(syntaxcase x ()
[(k (ivar ...) formals b1 b2 ...)
(withsyntax ([(index ...)
(let f ([i 0] [ls #'(ivar ...)])
(if (null? ls)
'()
(cons i (f (+ i 1) (cdr ls)))))]
[self (datum>syntax #'k 'self)]
[set! (datum>syntax #'k 'set!)])
#'(lambda (self . formals)
(letsyntax ([ivar (identifiersyntax
(vectorref self index))]
...)
(letsyntax ([set!
(syntaxrules (ivar ...)
[(_ ivar e) (vectorset! self index e)]
...
[(_ x e) (set! x e)])])
b1 b2 ...))))])))
Local bindings for ivar ...
and for set!
make the fields of the object appear to be ordinary variables, with references and assignments translated into calls to vectorref
and vectorset!
. datum>syntax
is used to make the introduced bindings of self
and set!
visible in the method body. Nested letsyntax
expressions are needed so that the identifiers ivar ...
serving as auxiliary keywords for the local version of set!
are scoped properly.
By using the general form of identifiersyntax
to handle set!
forms more directly, we can simplify the definition of method
.
(definesyntax method
(lambda (x)
(syntaxcase x ()
[(k (ivar ...) formals b1 b2 ...)
(withsyntax ([(index ...)
(let f ([i 0] [ls #'(ivar ...)])
(if (null? ls)
'()
(cons i (f (+ i 1) (cdr ls)))))]
[self (datum>syntax #'k 'self)])
#'(lambda (self . formals)
(letsyntax ([ivar (identifiersyntax
[_ (vectorref self index)]
[(set! _ e)
(vectorset! self index e)])]
...)
b1 b2 ...)))])))
The examples below demonstrate simple uses of method
.
(let ([m (method (a) (x) (list a x self))])
(m #(1) 2)) ⇒ (1 2 #(1))
(let ([m (method (a) (x)
(set! a x)
(set! x (+ a x))
(list a x self))])
(m #(1) 2)) ⇒ (2 4 #(2))
In a complete OOP system based on method
, the instance variables ivar ...
would likely be drawn from class declarations, not listed explicitly in the method
forms, although the same techniques would be used to make instance variables appear as ordinary variables within method bodies.
The final example of this section defines a simple structure definition facility that represents structures as vectors with named fields. Structures are defined with definestructure
, which takes the form
(definestructure name field ...)
where name
names the structure and field ...
names its fields. definestructure
expands into a series of generated definitions: a constructor makename
, a type predicate name?
, and one accessor namefield
and setter setnamefield!
per field name.
(definesyntax definestructure
(lambda (x)
(define genid
(lambda (templateid . args)
(datum>syntax templateid
(string>symbol
(apply stringappend
(map (lambda (x)
(if (string? x)
x
(symbol>string (syntax>datum x))))
args))))))
(syntaxcase x ()
[(_ name field ...)
(withsyntax ([constructor (genid #'name "make" #'name)]
[predicate (genid #'name #'name "?")]
[(access ...)
(map (lambda (x) (genid x #'name "" x))
#'(field ...))]
[(assign ...)
(map (lambda (x)
(genid x "set" #'name "" x "!"))
#'(field ...))]
[structurelength (+ (length #'(field ...)) 1)]
[(index ...)
(let f ([i 1] [ids #'(field ...)])
(if (null? ids)
'()
(cons i (f (+ i 1) (cdr ids)))))])
#'(begin
(define constructor
(lambda (field ...)
(vector 'name field ...)))
(define predicate
(lambda (x)
(and (vector? x)
(= (vectorlength x) structurelength)
(eq? (vectorref x 0) 'name))))
(define access
(lambda (x)
(vectorref x index)))
...
(define assign
(lambda (x update)
(vectorset! x index update)))
...))])))
The constructor accepts as many arguments as there are fields in the structure and creates a vector whose first element is the symbol name
and whose remaining elements are the argument values. The type predicate returns true if its argument is a vector of the expected length whose first element is name
.
Since a definestructure
form expands into a begin
containing definitions, it is itself a definition and can be used wherever definitions are valid.
The generated identifiers are created with datum>syntax
to allow the identifiers to be visible where the definestructure
form appears.
The examples below demonstrate the use of definestructure
.
(definestructure tree left right)
(define t
(maketree
(maketree 0 1)
(maketree 2 3)))
t ⇒ #(tree #(tree 0 1) #(tree 2 3))
(tree? t) ⇒ #t
(treeleft t) ⇒ #(tree 0 1)
(treeright t) ⇒ #(tree 2 3)
(settreeleft! t 0)
t ⇒ #(tree 0 #(tree 2 3))
Chapter 9. Records
This chapter describes the means by which the programmer may define new data types, or records types, each distinct from all other types. A record type determines the number and names of the fields each instance of the type has. Records are defined via the definerecordtype
form or the makerecordtypedescriptor
procedure.
Section 9.1. Defining Records
A definerecordtype
form defines a record type and, along with it, a constructor procedure for records of the type, a type predicate that returns true only for records of the type, an access procedure for each field, and an assignment procedure for each mutable field. For example, the definition
(definerecordtype point (fields x y))
creates a point
record type with two fields, x
and y
, and defines the following procedures:
(makepoint x y)

constructor 
(point? obj)

predicate 
(pointx p)

accessor for field 
(pointy p)

accessor for field 
With this definition in place, we can use these procedures to create and manipulate records of the point
type, as illustrated below.
(define p (makepoint 36 17))
(point? p) ⇒ #t
(point? '(cons 36 17)) ⇒ #f
(pointx p) ⇒ 36
(pointy p) ⇒ 17
Fields are immutable by default, but may be declared mutable. In the alternate definition of point
below, the x
field is mutable while y
remains immutable.
(definerecordtype point (fields (mutable x) y))
In this case, definerecordtype
defines a mutator for the x
field in addition to the other products shown above.
(pointxset! p x)

mutator for field 
The mutator can be used to change the contents of the x
field.
(define p (makepoint 36 17))
(pointxset! p ( (pointx p) 12))
(pointx p) ⇒ 24
A field may be declared immutable explicitly for clarity; the definition of point
below is equivalent to the second definition above.
(definerecordtype point (fields (mutable x) (immutable y)))
The names of the procedures defined by definerecordtype
follow the regular naming convention illustrated by the examples above, by default, but the programmer can override the defaults if desired. With the following definition of point
, the constructor is mkpoint
, the predicate is ispoint?
, and the accessors for x
and y
are xval
and yval
. The mutator for x
is setxval!
.
(definerecordtype (point mkpoint ispoint?)
(fields (mutable x xval setxval!)
(immutable y yval)))
By default, a record definition creates a new type each time it is evaluated, as illustrated by the example below.
(define (f p)
(definerecordtype point (fields x y))
(if (eq? p 'make) (makepoint 3 4) (point? p)))
(f (f 'make)) ⇒ #f
The first (inner) call to f
returns a point p
, which is passed to f
in the second (outer) call, which applies point?
to p
. This point?
is looking for points of the type created by the second call, while p
is a point of the type created by the first call. So point?
returns #f
.
This default generative behavior may be overridden by including a nongenerative
clause in the record definition.
(define (f p)
(definerecordtype point (fields x y) (nongenerative))
(if (eq? p 'make) (makepoint 3 4) (point? p)))
(define p (f 'make))
(f p) ⇒ #t
Record types created in this manner are still distinct from record types created by a definition appearing in a different part of the program, even if the definitions are syntactically identical:
(define (f)
(definerecordtype point (fields x y) (nongenerative))
(makepoint 3 4))
(define (g p)
(definerecordtype point (fields x y) (nongenerative))
(point? p))
(g (f)) ⇒ #f
(define (f)
(definerecordtype point (fields x y)
(nongenerative reallythesamepoint))
(makepoint 3 4))
(define (g p)
(definerecordtype point (fields x y)
(nongenerative reallythesamepoint))
(point? p))
(g (f)) ⇒ #t
The uid may be any identifier, but programmers are encouraged to select uids from the RFC 4122 UUID namespace [20], possibly with the recordtype name as a prefix.
A record type may be defined as a subtype of an existing "parent" type with a parent
clause that declares the name of the existing record type. If a parent is specified, the new "child" record type inherits the parent record’s fields, and each instance of the child type is considered to be an instance of the parent type, so that accessors and mutators for the parent type may be used on instances of the child type.
(definerecordtype point (fields x y))
(definerecordtype cpoint (parent point) (fields color))
The child type has all of the fields of the parent type, plus the additional fields declared in the child’s definition. This is reflected in the constructor for cpoint
, which now takes three arguments, with the parent arguments followed by the child argument.
(define cp (makecpoint 3 4 'red))
A record of the child type is considered a record of the parent type, but a record of the parent type is not a record of the new type.
(point? (makecpoint 3 4 'red)) ⇒ #t
(cpoint? (makepoint 3 4)) ⇒ #f
Only one new accessor is created for cpoint
, the one for the new field color
. The existing accessors and mutators for the parent type may be used to access and modify the parent fields of the child type.
(define cp (makecpoint 3 4 'red))
(pointx cp) ⇒ 3
(pointy cp) ⇒ 4
(cpointcolor cp) ⇒ red
As the examples given so far illustrate, the default constructor defined by definerecordtype
accepts as many arguments as the record has fields, including parent fields, and parent’s parent fields, and so on. The programmer may override the default and specify the arguments to the constructor for the new type and how it determines the initial values of the constructed record’s fields, via the protocol
clause. The following definition creates a point
record with three fields: x
, y
, and d
, where d
represents the displacement from the origin. The constructor still takes only two arguments, the x
and y
values, and initializes d
to the square root of the sum of the squares of x
and y
.
(definerecordtype point
(fields x y d)
(protocol
(lambda (new)
(lambda (x y)
(new x y (sqrt (+ (* x x) (* y y))))))))
(define p (makepoint 3 4))
(pointx p) ⇒ 3
(pointy p) ⇒ 4
(pointd p) ⇒ 5
The procedure value of the expression within the protocol
clause receives as an argument a primitive constructor new
and returns a final constructor c
. There are essentially no limits on what c
is allowed to do, but if it returns, it should return the result of calling new
. Before it does so, it may modify the new record instance (if the record type has mutable fields), register it with some external handler, print messages, etc. In this case, c
accepts two arguments, x
and y
, and applies new
to x
, y
, and the result of computing the origin displacement based on x
and y
.
If a parent record is specified, the construction protocol becomes more involved. The following definition of cpoint
assumes that point
has been defined as shown just above.
(definerecordtype cpoint
(parent point)
(fields color)
(protocol
(lambda (pargs>new)
(lambda (c x y)
((pargs>new x y) c)))))
(define cp (makecpoint 'red 3 4))
(pointx cp) ⇒ 3
(pointy cp) ⇒ 4
(pointd cp) ⇒ 5
(cpointcolor cp) ⇒ red
Because a parent clause is present, the procedure value of the expression within the protocol
clause receives a procedure pargs>new
that, when applied to parent arguments, returns a new
procedure. The new
procedure, when passed the values of the child fields, returns the result of applying the parent protocol to an appropriate new
procedure of its own. In this case, pargs>new
is passed the values of the child constructor’s second and third arguments (the x
and y
values) and the resulting new
procedure is passed the value of the child constructor’s first argument (the color). Thus, the protocol supplied in this example effectively reverses the normal order of arguments in which the parent arguments come before the child arguments, while arranging to pass along the arguments needed by the parent protocol.
The default protocol is equivalent to
(lambda (new) new)
for record types with no parents, while for record types with parents, the default protocol is equivalent to the following
(lambda (pargs>new)
(lambda (x_{1} ... x_{n} y_{1} ... y_{m})
((pargs>new x_{1} ... x_{n}) y_{1} ... y_{m})))
where n
is the number of parent (including grandparent, etc.) fields and m
is the number of child fields.
Use of the protocol
clause insulates the child record definition from some changes to the parent record type. The parent definition may be modified to add or remove fields, or even add, remove, or change a parent, yet the child protocol and constructor need not change as long as the parent protocol does not change.
Additional details and options for definerecordtype
are given in its formal description below.
syntax 

syntax 

libraries 

A definerecordtype
form, or record definition, is a definition and may appear anywhere other definitions may appear. It defines a record type identified by recordname
, plus a predicate, constructor, accessors, and mutators for the record type. If the record definition takes the first form above, the names of the constructor and predicate are derived from recordname
: makerecordname
for the constructor and recordname?
for the predicate. If the record definition takes the second form above, the name of the constructor is constructor
and the name of the predicate is pred
. All names defined by a record definition are scoped where the record definition appears.
The clauses clause ...
of the record definition determine the fields of the record type and the names of their accessors and mutators; its parent type, if any; its construction protocol; whether it is nongenerative and, if so, whether its uid is specified; whether it is sealed; and whether it is opaque. The syntax and impact of each clause is described below.
None of the clauses is required; thus, the simplest record definition is
(definerecordtype recordname)
which defines a new, generative, nonsealed, nonopaque record type with no parent and no fields, plus a constructor of no arguments and a predicate.
At most one of each kind of clause may be present in the set of clauses, and if a parent
clause is present, a parentrtd
clause must not be present. The clauses that appear may appear in any order.
Fields clause. A (fields fieldspec ...)
clause declares the fields of the record type. Each fieldspec
must take one of the following forms:
fieldname
(immmutable fieldname)
(mutable fieldname)
(immmutable fieldname accessorname)
(mutable fieldname accessorname mutatorname)
where fieldname
, accessorname
, and mutatorname
are identifiers. The first form, fieldname
, is equivalent to (immutable fieldname)
. The value of a field declared immutable may not be changed, and no mutator is created for it. With the first three forms, the name of the accessor is rnamefname
, where rname
is the record name and fname
is the field name. With the third form, the name of the accessor is rnamefnameset!
. The fourth and fifth forms explicitly declare the accessor and mutator names.
If no fields
clause is present or the list fieldspec ...
is empty, the record type has no fields (other than parent fields, if any).
Parent clause. A (parent parentname)
clause declares the parent record type; parentname
must be the name of a nonsealed record type previously defined via definerecordtype
. Instances of a record type are also considered instances of its parent record type and have all the fields of its parent record type in addition to those declared via the fields
clause.
Nongenerative clause. A nongenerative
clause may take one of two forms:
(nongenerative)
(nongenerative uid)
where uid
is a symbol. The first form is equivalent to the second, with a uid generated by the implementation at macroexpansion time. When a definerecordtype
form with a nongenerative clause is evaluated, a new type is created if and only if the uid is not the uid of an existing record type.
If it is the uid of an existing record type, the parent, fieldnames, sealed property, and opaque property must match as follows.

If a parent is specified, the existing record type must have the same parent rtd (by
eqv?
). If a parent is not specified, the existing record type must not have a parent. 
The same number of fields must be provided, with the same names and in the same order, and the mutability of each field must be the same.

If a
(sealed #t)
clause is present, the existing record type must be sealed. Otherwise, the existing record type must not be sealed. 
If an
(opaque #t)
clause is present, the existing record type must be opaque. Otherwise, the existing record type must be opaque if and only if an opaque parent type is specified.
If these constraints are met, no new record type is created, and the other products of the recordtype definition (constructor, predicate, accessors, and mutators) operate on records of the existing type. If these constraints are not met, the implementation may treat it as a syntax violation, or it may raise a runtime exception with condition type &assertion
.
With the first form of nongenerative
clause, the generated uid can be the uid of an existing record type only if the same definition is executed multiple times, e.g., if it appears in the body of a procedure that is invoked multiple times.
If uid
is not the uid of an existing record type, or if no nongenerative
clause is present, a new record type is created.
Protocol clause. A (protocol expression)
determines the protocol that the generated constructor uses to construct instances of the record type. It must evaluate to a procedure, and this procedure should be an appropriate protocol for the record type, as described on page 326.
Sealed clause. A sealed
clause of the form (sealed #t)
declares that the record type is sealed. This means that it cannot be extended, i.e., cannot be used as the parent for another record definition or makerecordtypedescriptor
call. If no sealed
clause is present or if one of the form (sealed #f)
is present, the record type is not sealed.
Opaque clause. An opaque
clause of the form (opaque #t)
declares that the record type is opaque. Instances of an opaque record type are not considered records by the record?
predicate or, more importantly, the rtdextraction procedure recordrtd
, which are both described in Section 9.3. Thus, it is not possible for code that does not have access to the recordname
, accessors, or mutators to access or modify any of the fields of an opaque record type. A record type is also opaque if its parent is opaque. If no opaque
clause is present or if one of the form (opaque #f)
is present, and the parent, if any, is not opaque, the record type is not opaque.
Parentrtd clause. A (parentrtd parentrtd parentrcd)
clause is an alternative to the parent
clause for specifying the parent record type, along with a parent record constructor descriptor. It is primarily useful when the parent rtd and rcd were obtained via calls to makerecordtypedescriptor
and makerecordconstructordescriptor
.
parentrtd
must evaluate to an rtd or #f
. If parentrtd
evaluates to #f
, parentrcd
must also evaluate to #f
. Otherwise, parentrcd
must evaluate to an rcd or #f
. If parentrcd
evaluates to an rcd, it must encapsulate an rtd equivalent (by eqv?
) to the value of parentrtd
. If the value of parentrcd
is #f
, it is treated as an rcd for the value of parentrtd
with a default protocol.
The definerecordtype
form is designed in such a way that it is normally possible for a compiler to determine the shapes of the record types it defines, including the offsets for all fields. This guarantee does not hold, however, when the parentrtd
clause is used, since the parent rtd might not be determinable until run time. Thus, the parent
clause is preferred over the parentrtd
clause whenever the parent
clause suffices.
syntax 

syntax 

syntax 

syntax 

syntax 

syntax 

syntax 

syntax 

syntax 

libraries 

These identifiers are auxiliary keywords for definerecordtype
. It is a syntax violation to reference these identifiers except in contexts where they are recognized as auxiliary keywords.
Section 9.2. Procedural Interface
The procedural (makerecordtypedescriptor
) interface may also be used to create new record types. The procedural interface is more flexible than the syntactic interface, but this flexibility can lead to less readable and efficient programs, so programmers should use the syntactic interface whenever it suffices.
procedure 

returns 
a recordtype descriptor (rtd) for a new or existing record type 
libraries 

name
must be a symbol, parent
must be #f
or the rtd of a nonsealed record type, uid
must be #f
or a symbol, and fields
must be a vector, each element of which is a twoelement list of the form (mutable fieldname)
or (immutable fieldname)
. The field names fieldname ...
must be symbols and need not be distinct from each other.
If uid
is #f
or is not the uid of an existing record type, this procedure creates a new record type and returns a recordtype descriptor (rtd) for the new type. The type has the parent type (page 325) described by parent
, if nonfalse; the uid specified by uid
, if nonfalse; and the fields specified by fields
. It is sealed (page 330) if s?
is nonfalse. It is opaque (page 330) if opaque
is nonfalse or the parent (if specified) is opaque. The name of the new record type is name
and the names of the fields are fieldname ...
.
If uid
is nonfalse and is the uid (page 325) of an existing record type, the parent
, fields
, s?
, and o?
arguments must match the corresponding characteristics of the existing record type. That is, parent
must be the same (by eqv?
); the number of fields must be the same; the fields must have the same names, be in the same order, and have the same mutability; s?
must be false if and only if the existing record type is sealed; and, if a parent is not specified or is not opaque, o?
must be false if and only if the existing record type is opaque. If this is the case, makerecordtypedescriptor
returns the rtd for the existing record type. Otherwise, an exception with condition type &assertion
is raised.
Using the rtd returned by makerecordtypedescriptor
, programs can generate constructors, type predicates, field accessors, and field mutators dynamically. The following code demonstrates how the procedural interface might be used to create a point
record type and associated definitions similar to those of the second point
record definition in Section 9.1, with a mutable x
field and an immutable y
field.
(define pointrtd (makerecordtypedescriptor 'point #f #f #f #f
'#((mutable x) (immutable y))))
(define pointrcd (makerecordconstructordescriptor pointrtd
#f #f))
(define makepoint (recordconstructor pointrcd))
(define point? (recordpredicate pointrtd))
(define pointx (recordaccessor pointrtd 0))
(define pointy (recordaccessor pointrtd 1))
(define pointxset! (recordmutator pointrtd 0))
See the additional examples given at the end of this section.
procedure 

returns 

libraries 

See the examples given at the end of this section.
procedure 

returns 
a recordconstructor descriptor (rcd) 
libraries 

An rtd alone is sufficient to create predicates, accessors, and mutators. To create a constructor, however, it is first necessary to create a recordconstructor descriptor (rcd) for the record type. An rcd encapsulates three pieces of information: the rtd of the record type for which the rcd has been created, the parent rcd (if any), and the protocol.
The parentrcd
argument must be an rcd or #f
. If it is an rcd, rtd
must have a parent rtd, and the parent rtd must be the same as the rtd encapsulated within parentrcd
. If parentrcd
is false, either rtd
has no parent or an rcd with a default protocol is assumed for the parent.
The protocol
argument must be a procedure or #f
. If it is #f
, a default protocol is assumed. Protocols are discussed on page 326.
See the examples given at the end of this section.
syntax 

returns 
the rtd for the record type identified by 
syntax 

returns 
the rcd for the record type identified by 
libraries 

Each record definition creates, behind the scenes, an rtd and rcd for the defined record type. These procedures allow the rtd and rcd to be obtained and used like any other rtd or rcd. recordname
must be the name of a record previously defined via definerecordtype
.
procedure 

returns 
a record constructor for the record type encapsulated within 
libraries 

The behavior of the record constructor is determined by the protocol and parent rcd (if any) also encapsulated within rcd
.
See the examples given at the end of this section.
procedure 

returns 
a predicate for 
libraries 

This procedure returns a predicate that accepts one argument and returns #t
if the argument is an instance of the recordtype described by rtd
, #f
otherwise.
See the examples given at the end of this section.
procedure 

returns 
an accessor for the field of 
libraries 

idx
must be a nonnegative integer less than the number of fields of rtd
, not counting parent fields. An idx
value of 0 specifies the first field given in the definerecordtype
form or makerecordtypedescriptor
call that created the record type, 1 specifies the second, and so on.
A child rtd cannot be used directly to create accessors for parent fields. To create an accessor for a parent field, the recordtype descriptor of the parent must be used instead.
See the examples given at the end of this section.
procedure 

returns 
a mutator for the field of 
libraries 

idx
must be a nonnegative integer less than the number of fields of rtd
, not counting parent fields. An idx
value of 0 specifies the first field given in the definerecordtype
form or makerecordtypedescriptor
call that created the record type, 1 specifies the second, and so on. The indicated field must be mutable; otherwise, an exception with condition type &assertion
is raised.
A child rtd cannot be used directly to create mutators for parent fields. To create a mutator for a parent field, the recordtype descriptor of the parent must be used instead.
The following example illustrates the creation of parent and child record types, predicates, accessors, mutators, and constructors using the procedures described in this section.
(define rtd/parent
(makerecordtypedescriptor 'parent #f #f #f #f
'#((mutable x))))
(recordtypedescriptor? rtd/parent) ⇒ #t
(define parent? (recordpredicate rtd/parent))
(define parentx (recordaccessor rtd/parent 0))
(define setparentx! (recordmutator rtd/parent 0))
(define rtd/child
(makerecordtypedescriptor 'child rtd/parent #f #f #f
'#((mutable x) (immutable y))))
(define child? (recordpredicate rtd/child))
(define childx (recordaccessor rtd/child 0))
(define setchildx! (recordmutator rtd/child 0))
(define childy (recordaccessor rtd/child 1))
(recordmutator rtd/child 1) ⇒ exception: immutable field
(define rcd/parent
(makerecordconstructordescriptor rtd/parent #f
(lambda (new) (lambda (x) (new (* x x))))))
(recordtypedescriptor? rcd/parent) ⇒ #f
(define makeparent (recordconstructor rcd/parent))
(define p (makeparent 10))
(parent? p) ⇒ #t
(parentx p) ⇒ 100
(setparentx! p 150)
(parentx p) ⇒ 150
(define rcd/child
(makerecordconstructordescriptor rtd/child rcd/parent
(lambda (pargs>new)
(lambda (x y)
((pargs>new x) (+ x 5) y)))))
(define makechild (recordconstructor rcd/child))
(define c (makechild 10 'cc))
(parent? c) ⇒ #t
(child? c) ⇒ #t
(child? p) ⇒ #f
(parentx c) ⇒ 100
(childx c) ⇒ 15
(childy c) ⇒ cc
(childx p) ⇒ exception: invalid argument type
Section 9.3. Inspection
This section describes various procedures for asking questions about or extracting information from recordtype descriptors (rtds). It also describes the recordrtd
procedure, with which the rtd of a nonopaque record instance may be extracted, allowing the record type of the instance to be inspected and, via record accessors and mutators generated from the rtd, the record itself to be inspected or modified. This is a powerful feature that permits the coding of portable record printers and inspectors.
The recordtype descriptor cannot be extracted from an instance of an opaque record type; this is the feature that distinguishes opaque from nonopaque record types.
procedure 

returns 
the name associated with 
libraries 

(define record>name
(lambda (x)
(and (record? x) (recordtypename (recordrtd x)))))
(definerecordtype dim (fields w l h))
(record>name (makedim 10 15 6)) ⇒ dim
(definerecordtype dim (fields w l h) (opaque #t))
(record>name (makedim 10 15 6)) ⇒ #f
procedure 

returns 
the parent of 
libraries 

(definerecordtype point (fields x y))
(definerecordtype cpoint (parent point) (fields color))
(recordtypeparent (recordtypedescriptor point)) ⇒ #f
(recordtypeparent (recordtypedescriptor cpoint)) ⇒ #<rtd>
procedure 

returns 
the uid of 
libraries 

Whether a record type created without a programmersupplied uid actually has one anyway is left up to the implementation, so this procedure is never guaranteed to return #f
.
(definerecordtype point (fields x y))
(definerecordtype cpoint
(parent point)
(fields color)
(nongenerative e40cc9268cf44559a47ccac636630314))
(recordtypeuid (recordtypedescriptor point)) ⇒ unspecified
(recordtypeuid (recordtypedescriptor cpoint)) ⇒
e40cc9268cf44559a47ccac636630314
procedure 

returns 

procedure 

returns 

procedure 

returns 

libraries 

(definerecordtype table
(fields keys vals)
(opaque #t))
(define rtd (recordtypedescriptor table))
(recordtypegenerative? rtd) ⇒ #t
(recordtypesealed? rtd) ⇒ #f
(recordtypeopaque? rtd) ⇒ #t
(definerecordtype cachetable
(parent table)
(fields key val)
(nongenerative))
(define rtd (recordtypedescriptor cachetable))
(recordtypegenerative? rtd) ⇒ #f
(recordtypesealed? rtd) ⇒ #f
(recordtypeopaque? rtd) ⇒ #t
procedure 

returns 
a vector containing the names of the fields of the type described by 
libraries 

The vector returned by this procedure is immutable: the effect on rtd
of modifying it is unspecified. The vector does not include parent field names. The order of the names in the vector is the same as the order in which the fields were specified in the definerecordtype
form or makerecordtypedescriptor
call that created the record type.
(definerecordtype point (fields x y))
(definerecordtype cpoint (parent point) (fields color))
(recordtypefieldnames
(recordtypedescriptor point)) ⇒ #(x y)
(recordtypefieldnames
(recordtypedescriptor cpoint)) ⇒ #(color)
procedure 

returns 

libraries 

idx
must be a nonnegative integer less than the number of fields of rtd
, not counting parent fields. An idx
value of 0 specifies the first field given in the definerecordtype
form or makerecordtypedescriptor
call that created the record type, 1 specifies the second, and so on.
(definerecordtype point (fields (mutable x) (mutable y)))
(definerecordtype cpoint (parent point) (fields color))
(recordfieldmutable? (recordtypedescriptor point) 0) ⇒ #t
(recordfieldmutable? (recordtypedescriptor cpoint) 0) ⇒ #f
procedure 

returns 

libraries 

When passed an instance of an opaque record type, record?
returns #f
. While an instance of an opaque record type is, in essence, a record, the point of opacity is to hide all representation information from the parts of a program that should not have access to the information, and this includes whether an object is a record. Furthermore, the primary purpose of this predicate is to allow programs to check whether it is possible to obtain from the argument an rtd via the recordrtd
procedure described below.
(definerecordtype statement (fields str))
(define q (makestatement "He's dead, Jim"))
(statement? q) ⇒ #t
(record? q) ⇒ #t
(definerecordtype opaquestatement (fields str) (opaque #t))
(define q (makeopaquestatement "He's moved on, Jim"))
(opaquestatement? q) ⇒ #t
(record? q) ⇒ #f
procedure 

returns 
the recordtype descriptor (rtd) of 
libraries 

The argument must be an instance of a nonopaque record type. In combination with some of the other procedures described in this section and Section 9.2, recordrtd
allows the inspection or mutation of record instances, even if the type of the instance is unknown to the inspector. This capability is illustrated by the procedure printfields
below, which accepts a record argument and writes the name and value of each field of the record.
(define printfields
(lambda (r)
(unless (record? r)
(assertionviolation 'printfields "not a record" r))
(let loop ([rtd (recordrtd r)])
(let ([prtd (recordtypeparent rtd)])
(when prtd (loop prtd)))
(let* ([v (recordtypefieldnames rtd)]
[n (vectorlength v)])
(do ([i 0 (+ i 1)])
((= i n))
(write (vectorref v i))
(display "=")
(write ((recordaccessor rtd i) r))
(newline))))))
With the familiar definitions of point
and cpoint
:
(definerecordtype point (fields x y))
(definerecordtype cpoint (parent point) (fields color))
the expression (printfields (makecpoint 3 7 'blue))
displays the following three lines.
x=3
y=7
color=blue
Chapter 10. Libraries and TopLevel Programs
Libraries and toplevel programs are the basic units of portable code in the language defined by the Revised^{6} Report on Scheme [24]. Toplevel programs may import from one or more libraries, and libraries may import from other libraries.
Libraries are named using a parenthesized syntax that encloses a sequence of identifiers, optionally followed by a version; the version is itself a parenthesized form that encloses a sequence of subversions represented as exact nonnegative integers. So, for example, (a)
, (a b)
, (a b ())
, and (a b (1 2 3))
are all valid library names. Implementations typically treat the sequence of names as a path by which a library’s source or object code can be found, possibly rooted in some standard set of locations in the hostmachine’s filesystem.
An implementation of the standard library mechanism is available with the portable implementation of syntaxcase
at http://www.cs.indiana.edu/syntaxcase/.
Section 10.1. Standard Libraries
The Revised^{6} Report [24] describes a base library
(rnrs base (6))
that defines the most commonly used features of the language. A separate Standard Libraries document [26] describes the libraries listed below.
(rnrs arithmetic bitwise (6))
(rnrs arithmetic fixnums (6))
(rnrs arithmetic flonums (6))
(rnrs bytevectors (6))
(rnrs conditions (6))
(rnrs control (6))
(rnrs enums (6))
(rnrs eval (6))
(rnrs exceptions (6))
(rnrs files (6))
(rnrs hashtables (6))
(rnrs io ports (6))
(rnrs io simple (6))
(rnrs lists (6))
(rnrs mutablepairs (6))
(rnrs mutablestrings (6))
(rnrs programs (6))
(rnrs r5rs (6))
(rnrs records procedural (6))
(rnrs records syntactic (6))
(rnrs records inspection (6))
(rnrs sorting (6))
(rnrs syntaxcase (6))
(rnrs unicode (6))
One more library is described in the Standard Libraries document, a composite library
(rnrs (6))
that exports all of the (rnrs base (6))
bindings along with those of the other libraries listed above, except those of (rnrs eval (6))
, (rnrs mutablepairs (6))
, (rnrs mutablestrings (6))
, and (rnrs r5rs (6))
.
Although each of these libraries has the version (6)
, references to them can and in most cases should leave the version out, e.g., the composite library should be referenced simply as (rnrs)
.
Section 10.2. Defining New Libraries
New libraries are defined with the library
form, which has the following syntax.
(library libraryname
(export exportspec ...)
(import importspec ...)
librarybody)
A libraryname
specifies the name and possibly version by which the library is identified by the import
form of another library or toplevel program. It also serves as kind of path that the implementation uses to locate the library, via some implementationspecific process, whenever it needs to be loaded. A libraryname
has one of the following two forms:
(identifier identifier ...)
(identifier identifier ... version)
where version
has the following form:
(subversion ...)
and each subversion
represents an exact nonnegative integer. A library name with no version
is treated the same as a library name with the empty version
()
. For example, (listtools setops)
and (listtools setops ())
are equivalent and specify a library name with no version, while (listtools setops (1 2))
specifies a versioned library name, which can be thought of as Version 1.2 of the (listtools setops)
library.
The export
subform names the exports and, optionally, the names by which they should be known outside of the library. Each exportspec
takes one of the following two forms:
identifier
(rename (internalname exportname) ...)
where each internalname
and exportname
is an identifier. The first form names a single export, identifier
, whose export name is the same as its internal name. The second names a set of exports, each of whose export name is given explicitly and may differ from its internal name.
The import
subform names the other libraries upon which the new library depends and, possibly, the set of identifiers to be imported and the names by which they should be known inside the new library. It may also specify when the bindings should be made available for implementations that require such information. Each importspec
takes one of the following two forms:
importset
(for importset importlevel ...)
where importlevel
is one of the following:
run
expand
(meta level)
and level
represents an exact integer.
The for
syntax declares when the imported bindings might be used by the importing library and thus when the implementation must make the bindings available. run
and (meta 0)
are equivalent and specify that the bindings imported from a library might be referenced by the runtime expressions (define
righthandside expressions and initialization expressions) of the importing library. expand
and (meta 1)
are equivalent and specify that the bindings imported from a library might be referenced by the transformer expressions (definesyntax
, letsyntax
, or letrecsyntax
righthandside expressions) of the importing library. (meta 2)
specifies that the bindings imported from a library might be referenced by a transformer expression that appears within a transformer expression of the importing library, and so on for higher meta levels. Negative meta levels may also be specified and are needed in certain circumstances when a transformer expands into the transformer for another keyword binding used at a lower meta level.
A library export may have a nonzero export meta level, in which case the effective import level is the sum of the level specified by for
and the export level. The exports of each standard library except (rnrs base)
and (rnrs)
have export level zero. For (rnrs base)
, all exports have export level zero except for syntaxrules
, identifiersyntax
, and their auxiliary keywords _
, ...
, and set!
. set!
has export levels zero and one, while the others have export level one. All exports of the (rnrs)
library have export levels zero and one.
It can be difficult for the programmer to specify the import levels that allow a library or toplevel program to compile or run properly. Moreover, it is often impossible to cause a library’s bindings to be made available when they are needed without causing them to be made available in some cases when they are not needed. For example, it is not possible to say that the runtime bindings of a library A are needed when a library B is expanded without also having the runtime bindings of A made available when code importing B is expanded. Making bindings available involves executing the code for the righthand sides of the bindings and possibly executing initialization expressions as well, so the inability to specify when bindings are needed precisely can add both compile and runtime overhead to a program.
Because of this, implementations are permitted to ignore export levels and the for
wrapper on an importset
and instead automatically determine, while expanding an importing library or toplevel program, when an imported library’s bindings must be made available, based on where references to the imported library’s exports actually appear. When using such an implementation, the for
wrapper need never be used, i.e., all importspec
s can be importset
s. If code is intended for use with systems that do not automatically determine when a library’s bindings must be made available, however, the for
must be used if the imported library’s bindings would not otherwise be available at the right time.
An importset
takes one of the following forms:
libraryspec
(only importset identifier ...)
(except importset identifier ...)
(prefix importset prefix)
(rename importset (importname internalname) ...)
where prefix
, importname
, and internalname
are identifiers. An importset
is a recursive specification of the identifiers to be imported from a library and possibly the names by which they should be known within the importing library. At the base of the recursive structure must sit a libraryspec
, which identifies a library and imports all of the identifiers from that library. An only
wrapper restricts the imported identifiers of the enclosed importset
to the ones listed, an except
wrapper restricts the imported identifiers of the enclosed importset
to those not listed, a prefix
wrapper adds a prefix to each of the imported identifiers of the enclosed importset
, and a rename
wrapper specifies internal names for selected identifiers of the enclosed importset
, while leaving the names of the other imports alone. So, for example, the importset
(prefix
(only
(rename (listtools setops) (difference diff))
union
diff)
set:)
imports only union
and difference
from the (listtools setops)
library, renames difference
to diff
while leaving union
alone, and adds the prefix set:
to the two names so that the names by which the two imports are known inside the importing library are set:union
and set:diff
.
A libraryspec
takes one of the following forms:
libraryreference
(library libraryreference)
where a libraryreference
is in either of the following two forms:
(identifier identifier ...)
(identifier identifier ... versionreference)
Enclosing a libraryreference
in a library
wrapper is necessary when the first identifier of the libraryreference
is for
, library
, only
, except
, prefix
, or rename
, to distinguish it from an importspec
or importset
identified by one of these keywords.
A versionreference
identifies a particular version of the library or a set of possible versions. A versionreference
has one of the following forms:
(subversionreference_{1} ... subversionreference_{n})
(and versionreference ...)
(or versionreference ...)
(not versionreference)
A versionreference
of the first form matches a version
with at least n elements if each subversionreference
matches version
's corresponding subversion
. An and
versionreference
form matches a version
if each of its versionreference
subforms matches version
. An or
versionreference
form matches a version
if any of its versionreference
subforms matches version
. A not
versionreference
form matches a version
if its versionreference
subform does not match version
.
A subversionreference
takes one of the following forms:
subversion
(>= subversion)
(<= subversion)
(and subversionreference ...)
(or subversionreference ...)
(not subversionreference)
A subversionreference
of the first form matches a subversion
if it is identical to it. A >=
subversionreference
matches a version
's subversion
if the version
's subversion
is greater than or equal to the subversion
appearing within the >=
form. Similarly, a <=
subversionreference
matches a version
's subversion
if the version
's subversion
is less than or equal to the subversion
appearing within the <=
form. An and
subversionreference
form matches a version
's subversion
if each of its subversionreference
subforms matches the version
's subversion
. An or
subversionreference
matches a version
's subversion
if any of its subversionreference
subforms match the version
's subversion
. A not
subversionreference
matches a version
's subversion
if its subversionreference
subform does not match the version
's subversion
.
For example, if two versions of a library are available, one with version (1 2)
and the other with version (1 3 1)
, the version references ()
and (1)
match both, (1 2)
matches the first but not the second, (1 3)
matches the second but not the first, (1 (>= 2))
matches both, and (and (1 (>= 3)) (not (1 3 1)))
matches neither.
When a library reference identifies more than one available library, one of the available libraries is selected in some implementationdependent manner.
Libraries and toplevel programs should not, directly or indirectly, specify the import of two libraries that have the same names but different versions. To avoid problems such as incompatible types and replicated state, implementations are encouraged, though not required, to prohibit programs from importing two versions of the same library.
A librarybody
contains definitions of exported identifiers, definitions of identifiers not intended for export, and initialization expressions. It consists of a (possibly empty) sequence of definitions followed by a (possibly empty) sequence of initialization expressions. When begin
, letsyntax
, or letrecsyntax
forms occur in a library body prior to the first expression, they are spliced into the body. Any body form may be produced by a syntactic extension, including definitions, the splicing forms just mentioned, or initialization expressions. A library body is expanded in the same manner as a lambda
or other body (page 292), and it expands into the equivalent of a letrec*
form so that the definitions and initialization forms in the body are evaluated from left to right.
Each of the exports listed in a library’s export
form must either be imported from another library or defined within the librarybody
, in either case with the internal rather than the export name, if the two differ.
Each identifier imported into or defined within a library must have exactly one binding. If imported into a library, it must not be defined in the library body, and if defined in the library body, it must be defined only once. If imported from two libraries, it must have the same binding in both cases, which can happen only if the binding originates in one of the two libraries and is reexported by the other or if the binding originates in a third library and is reexported by both.
The identifiers defined within a library and not exported by the library are not visible in code that appears outside of the library. A syntactic extension defined within a library may, however, expand into a reference to such an identifier, so that the expanded code does contain a reference to the identifier; this is referred to as an indirect export.
The exported variables of a library are immutable both inside the library and outside, whether they are explicitly or implicitly exported. It is a syntax violation if an explicitly exported variable appears on the lefthand side of a set!
expression within or outside of the exporting library. It is also a syntax violation if any other variable defined by a library appears on the lefthand side of a set!
expression and is indirectly exported.
Libraries are loaded and the code contained within them evaluated on an "as needed" basis by the implementation, as determined by the import relationships among libraries. A library’s transformer expressions (the expressions on the righthand sides of a library body’s definesyntax
forms) may be evaluated at different times from the library’s body expressions (the expressions on the righthand side of the body’s define
forms, plus initialization expressions). At a minimum, the transformer expressions of a library must be evaluated when (if not before) a reference to one of the library’s exported keywords is found while expanding another library or toplevel program, and the body expressions must be evaluated when (if not before) a reference to one of the library’s exported variables is evaluated, which may occur either when a program using the library is run or when another library or toplevel program is being expanded, if the reference is evaluated by a transformer called during the expansion process. An implementation may evaluate a library’s transformer and body expressions as many times as it pleases in the process of expanding other libraries. In particular, it may evaluate the expressions zero times if they are not actually needed, exactly one time, or one time for each meta level of the expansion. It is generally a bad idea for the evaluation of a library’s transformer or body expressions to involve externally visible side effects, e.g., popping up a window, since the time or times at which these side effects occur is unspecified. Localized effects that affect only the library’s initialization, e.g., to create a table used by the library, are generally okay.
Examples are given in Section 10.4.
Section 10.3. TopLevel Programs
A toplevel program is not a syntactic form per se but rather a set of forms that are usually delimited only by file boundaries. Toplevel programs can be thought of as library forms without the library
wrapper, library name, and export form. The other difference is that definitions and expressions can be intermixed within the body of a toplevel program but not within the body of a library. Thus the syntax of a toplevel program is, simply, an import
form followed by a sequence of definitions and expressions:
(import importspec ...)
definitionorexpression
...
An expression that appears within a toplevel program body before one or more definitions is treated as if it appeared on the righthand side of a definition for a dummy variable that is not visible anywhere within the program.
procedure 

returns 
a list of strings representing commandline arguments 
libraries 

This procedure may be used within a toplevel program to obtain a list of the commandline arguments passed to the program.
procedure 

procedure 

returns 
does not return 
libraries 

This procedure may be used to exit from a toplevel program to the operating system. If no obj
is given, the exit value returned to the operating system should indicate a normal exit. If obj
is false, the exit value returned to the operating system should indicate an abnormal exit. Otherwise, obj
is translated into an exit value as appropriate for the operating system.
Section 10.4. Examples
The example below demonstrates several features of the library
syntax. It defines "Version 1" of the (listtools setops)
library, which exports two keywords and several variables. The library imports the (rnrs base)
library, which provides everything it needs except the member
procedure, which it imports from (rnrs lists)
. Most of the variables exported by the library are bound to procedures, which is typical.
The syntactic extension set
expands into a reference to the variable list>set
, and member?
similarly expands into a reference to the variable memberhelp?
. While list>set
is explicitly exported, memberhelp?
is not. This makes memberhelp?
an indirect export. The procedure udhelp
is not explicitly exported, and since neither of the exported syntactic extensions expand into references to udhelp
, it is not indirectly export