Scheme 由 Gerald J. Sussman 和 Guy L. Steele Jr. 发明，支持 lexical scoping、first-class procedures 和 continuations。
本书的目标是提供关于 Scheme 编程语言（R6RS 标准）的介绍。
Scheme is a call-by-value language, but for at least mutable (objects that can be modified), the values are pointers to the actual storage.
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.
To support lexical scoping, a procedure carries the lexical context (environment) along with its code.
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.
A good rule is to use short identifiers when the scope of the identifier is small and longer identifiers when the scope is larger.
Structured forms and list constants are enclosed within parentheses, e.g., (a b c) or (* (- x 2) y).
Strings are enclosed in double quotation marks, e.g., “I am a string”. Characters are preceded by #, e.g., #\a.
; single line,
#| block |#,
') forces the list to be treated as data.
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.
Numbers and strings may be quoted, too. Numbers and strings are treated as constants in any case, however, so quoting them is unnecessary.
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.
每一个 variable 都有它的 scope，同名的 variable，更里面的 variable 会 shadow 外层的 variable。这种 scope 叫做 lexical scoping。
(let ((var expr) ...) body1 body2 ...)
(lambda (var ...) body1 body2 ...)
A predicate is a procedure that answers a specific question about its arguments and returns one of the two values #t or #f.
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.
Although many programs can be written without them, assignments to top-level 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!.
The core syntactic forms include top-level
defineforms, constants, variables, procedure applications,
<program> -> <form>*
expr ...are most often
lambdaexpressions, though this need not be the case. One restriction on the expressions must be obeyed, however. It must be possible to evaluate each
exprwithout evaluating any of the variables
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. We call “what to do with the value” the continuation of a computation.
对 continuation 的记录，意味着下次使用该 continuation 时会回到之前计算的某个点，再往下走。也就是说可以回到过去。
使函数调用的隐式 continuation 通过 CPS 转换变为显式。
- 可以传入多个 continuation
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.
Since the scope of the definitions in a
library, top-level 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.
(lambda formals body1 body2 ...)
case-lambdasyntactic form directly supports procedures with optional arguments as well as procedures with fixed or indefinite numbers of arguments.
(case-lambda clause ...)
[formals body1 body2 ...]
A set of definitions may be grouped by enclosing them in a
beginform. 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
Procedure application is the most basic Scheme control structure. Any structured form without a syntax keyword in the first position is a procedure application.
(apply procedure obj ... list)
applyis 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.
(begin expr1 expr2 ...)
The bodies of many syntactic forms, including
letrec*, as well as the result clauses of
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.
(let name ((var expr) ...) body1 body2 ...)
(do ((var init update) ...) (test result ...) expr ...)
(map procedure list1 list2 ...)
(for-each procedure list1 list2 ...)
for-eachis similar to
for-eachdoes not create and return a list of the resulting values, and
for-eachguarantees to perform the applications in sequence over the elements from left to right.
(exists procedure list1 list2 ...)
(for-all procedure list1 list2 ...)
(fold-left procedure obj list1 list2 ...)
(fold-right procedure obj list1 list2 ...)
(dynamic-wind in body out)
The benefit of using
forceis 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.
(call-with-values producer consumer)
evalprocedure allows programmers to write programs that construct and evaluate other programs. This ability to do run-time meta programming should not be overused but is handy when needed.
(eval obj environment)
(environment import-spec ...)
This chapter describes the operations on objects, including lists, numbers, characters, strings, vectors, bytevectors, symbols, booleans, hashtables, and enumerations.
eq?is most often used to compare symbols or to check for pointer equivalence of allocated objects
(list '+) 与
(list +) 的区别在于，第一个 list 包含的是符号 symbol +，而第二个 list 包含的是程序 procedure +。
也就是说， list 的内容可以包含任意类型的值，包括 procedure。
'(a b c) 表示含有 symbol
c 的 list，而不是一个叫
(a b c) 的 symbol。
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.
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.
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.
Bytevectors are vectors of raw binary data.
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.
Hashtables represent sets of associations between arbitrary Scheme values. They serve essentially the same purpose as association lists but are typically much faster when large numbers of associations are involved.
All input and output operations are performed through ports.
Ports are first-class objects, like any other object in Scheme.
It is perhaps easier to imagine that the default file options are the imaginary option symbols
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.
Syntactic extensions are expanded into core forms at the start of evaluation (before compilation or interpretation) by a syntax expander.
(define keyword expr)
P is of the form (P1 … Pn) and F is a list of n elements that match P1 through Pn
上面一句话的意思如果模式 P 是
(p1 p2 p3 p4) 这样子的格式的话，则 F 也必须是包含 4 个元素的列表。这里的
... 表示的是确定的指定了 n 个子模式。而不是在模式出现
(let ([if #f])
With this mechanism (
syntax-case), 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.
#'templateis equivalent to
(syntax template). The abbreviated form is converted into the longer form when a program is read, prior to macro expansion.
Syntactic extensions ordinarily take the form
(keyword subform ...), but the
syntax-casesystem permits them to take the form of singleton identifiers as well.
(with-syntax ((pattern expr) ...) body1 body2 ...)
quasisyntaxcan be used in place of
with-syntaxin many cases.
(datum->syntax template-identifier obj) 的作用。
注意每次定义 record type ，即使名字一样，也是不同的。
学习 Scheme 库的建立。
Top-level programs can be thought of as
libraryforms without the library wrapper, library name, and export form.
Exceptions and conditions provide the means for system and user code to signal, detect, and recover from errors that occur when a program is run.
a. (+ (* 1.2 (- 2 1/3) -8.7))
b. (/ (+ 2/3 4/9) (- 5/11 -4/3))
c. (+ 1 (/ 1 (+ 2 (/ 1 (+ 1 1/2)))))
d. (* 1 -2 3 -4 5 -6 7)
a. (car cdr)
(car (car '((a b) (c d)))) => a
'((a . b) ((c) d) ())
(1 (2 (3)) (()) 4 . 5)
试着解释 Scheme 表达式是如何求值。
(cdr (list + - * /)) => (list - * /)
(let ([x (* 3 a)])
(let ([ls (list a b c)])
(let ([x1 'a] [y1 'b])
(let ([x1 '((a b) c)])
d. f, y
(define caar (compose car car))
交换 cons 的参数顺序将会导致复制的 tree 的每一个节点的子节点被调换。
(let ([x (memv 'a ls)])
(or (memv x '(a b c)) (list x))
(define-syntax when ;; 如果对
let, beacuse it’s more simple.
(let xxx ([t 'even?] [x 20])
;; use set!
(define even? ; incorrect!
First is the most important problem to solve.
(define exit (call/cc (lambda (k) k)))
(define lwp-list (make-queue))
(define retry #f)
(define calc #f)
(list (car ls)) 的原因是因为虽然此时
n 是 1，但是
(if (null? (cdr ls)) ls (list (car ls)))，可以省去