Chez Scheme 程序設計語言(第4版本)
- 簡介(Introduction)
Scheme is a general-purpose computer programming language. It is a high-level 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已經被用于編寫文本編輯器、優化編譯器、操作系統、圖形軟件包、專家系統、數值應用程序、金融分析軟件包、虛擬現實系統,以及你所能想象的所有其他類型應用。然而,Scheme語言也確實是一種簡單易學的編程語言,這是由于Scheme是基于許多語法形式(syntacitc forms)和語義概念,此外也由于大多數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 "Revised6 Report" [24], emphasizes portability through a set of standard libraries and a standard mechanism for defining new portable libraries and top-level programs.
Scheme程序具有高度的可移植性(在不同機器上相同的Scheme實現),這是由于對于程序員,其機器依賴性幾乎完全被隱藏了起來。在不同的Scheme實現上,Scheme程序也幾乎擁有可一致性,這是因為一群Scheme語言設計者發布了一系列的報告,即Revised Reports on Scheme(RnRS)。其中最近的,是第6版(R6RS)[24],其中強調了通過一組標準庫、定義新的可移植性庫的機制以及頂層程序的方式來確保可移植性。
Although some early Scheme systems were inefficient and slow, many newer compiler-based implementations are fast, with programs running on par with equivalent programs written in lower-level languages. The relative inefficiency that sometimes remains results from run-time checks that support generic arithmetic and help programmers detect and correct various common programming errors. These checks may be disabled in many implementations.
盡管某些早期的Scheme系統確實既低效又緩慢,但是許多新的基于編譯器的實現則是快速的,可以與那些使用較低級別的語言編寫的程序相當。(Scheme的實現)運行期檢測(run-time checks)可以支持通用算法和幫助程序員檢查以及修正多種常見程序錯誤,而這種運行期檢測有時會導致相對的低效。這些檢測在許多Scheme實現種可以被關閉。
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 arbitrary-precision rational numbers.
Scheme支持多種數據類型,對象,包括字符、字符串、符號、對象的列表或向量,以及許多數值數據類型,包括復數、實數以及精確有理數等。
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.
在Scheme中,對象所需的內存是按需動態分配的,并且會在不再需要時被自動釋放,該特性主要通過一個垃圾收集器(garbage collector)周期性的恢復那些不可用對象的存儲空間來實現。簡單原子值,類似小整數、字符、布爾值以及空列表則以立即值的方式表示,不需要額外的分配和釋放開銷。
Regardless of representation, all objects are first-class 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 call-by-value 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.
Scheme是一種按值調用的語言,但是對于可變對象(mutable objects - 可以被修改的對象),它們的值就是實際存儲的指針。這些指針處于場景之后,盡管如此,程序員不需要意識到它們,除非有需要理解這個對象的存儲在傳參和返回值的時候并沒有被拷貝。
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語言的心臟是一個關于語法形式(syntactic forms)的小核心(core),通過這個核心可以構建其他所有的語法形式。這些核心形式,以及一組從它推導出的語法形式的集合和一組基本過程構成了完整的Scheme語言。一個Scheme的解釋器或者編譯器可以非常小,同時可能很快以及高度可靠。這些擴展形式和很多基本過程可以用Scheme自身定義出來,從而簡化了整個Scheme的實現和其可靠性。
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程序共用了關于Scheme數據結構的通用打印表示。這使得任何的Scheme程序本身也可以作為Scheme對象,具有自然和顯而易見的內部表示。例如,當結構化的語法形式與列表關聯(用列表形式表達)的時候,變量和語法關鍵詞就和符號關聯了起來。使用已經存在的語法形式和過程來定義新的語法形式,是Scheme所提供的語法擴展工具的基礎。在Scheme中也可以因此而直接使用Scheme的解釋器、編譯器以及其他程序變形工具,而一些其他語言的變形器也是一樣。
Scheme variables and keywords are lexically scoped, and Scheme programs are block-structured. 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.
Scheme變量和關鍵詞都是基于詞法作用域的,并且Scheme程序是塊結構。標識符可以被導入到一個程序或者庫,(標識符)也可以被局部綁定在一個給定的代碼塊(如程序、庫或者過程體)中。一個局部綁定僅僅在其可見詞法域可見,也就是說僅在組成這段特定的代碼塊的程序文本中可見。出現在某標識符所在代碼塊以外的同名符號對應不同的綁定;若塊外的標識符沒有綁定,那么引用無效。代碼塊可以嵌套,且內部的代碼塊中的綁定可以屏蔽掉外部的同名綁定。一個綁定的作用域等于其標識符的可見范圍扣除其被同名綁定屏蔽的區域。塊結構與詞法作用域有助于創建模塊式的程序,且易于閱讀和維護,也更可靠。針對詞法作用域的高效代碼生成是可能的,因為編譯器可以在程序求值之前確定所有將被解析的引用所在的的綁定的作用域。當然,這并非是說編譯器可以確定所有變量的值,因為在絕大多數情況下在執行程序前,變量的實際值還沒有被計算出來。
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.
在多數語言中,一個過程定義是一個名字與代碼塊的簡單聯系。塊中的某些局部變量是過程的參數。在一些語言中,一個過程定義可以出在其他代碼塊或過程中,因此只有在執行到這個內部塊時這個過程才被觸發。另一些語言,過程僅能被定義在最頂層。在Scheme中,一個過程定義可以出現在其他代碼塊或過程中,在此之后該過程都可能被觸發,即使它所在的代碼塊已經結束執行。為了支持詞法作用域,一個過程會連同它的代碼并攜帶它的詞法上下文(環境)。
Furthermore, Scheme procedures are not always named. Instead, procedures are first-class data objects like strings or numbers, and variables are bound to procedures in the same way they are bound to other objects.
此外,Scheme的過程并非總被命名。與此不同,過程是第一類數據對象,就像字符串或數那樣,而且那些變量綁定到過程的方式與綁定到其他對象的方式一樣。
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 tail-calls 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的過程可以被遞歸調用。這就是說,任何過程可以直接或簡接的調用自己。許多算法可以用遞歸的形式高雅或高效地定義出來。一種遞歸特殊情形,被稱為尾遞歸,被用來表達迭代或循環。一個尾調用總是發生在一個過程在尾部,直接或簡接地遞歸地調用自身。Scheme的實現被要求尾調用要以jumps(goto) 的方式實現,這樣通常可避免與遞歸有關的存儲開銷。作為一個結果,Scheme程序員僅需掌握簡單過程調用和遞歸,而無需通常負擔常見的多種循環結構。
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 first-class 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支持定義帶有continuation的任意控制結構。一個continuation是一個特殊的過程,它在程序的一個位置可以包含其剩余(尚未執行的)部分。在程序執行的任何時間都可以獲取一個continuation。與其它過程一樣,一個continuation也是第一類對象,而且可以在被創建后的任何時候調用。一旦被調用,程序會立即從continuation所得到的那個位置開始繼續執行。Continuation允許實現復雜的控制機制,包括回溯、多線程和協程。
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 high-level 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 in-line 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也允許程序員定義新的語法形式,或者語法擴展,每個新的語法形式是通過編寫變形器確定如何映射到現存的語法形式的。這些變形器過程在Scheme中表達有助于一些方便的高級模式語言,包括自動語法檢查、輸入析構和輸出重構等。默認情況下,詞法作用域在語法變形過程中依然有效,但是程序員可以控制轉換器輸出的標識符的作用域。語法擴展對于定義新的語言結構,或者模擬一些其他語言中的語言結構,或者獲得一些內聯代碼展開,甚至包括模擬整個編程語言都非常有用。多數大型Scheme程序都是從一組語法擴展和過程定義中構建出來的。
Scheme evolved from the Lisp language and is considered to be a dialect of Lisp. Scheme inherited from Lisp the treatment of values as first-class 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, first-class procedures, the treatment of tail calls as jumps, continuations, and lexically scoped syntactic extensions.
Scheme從LISP語言演化而來,也被認為是LISP的一種方言。Scheme語言繼承了LISP處理第一類對象數值的方式,一些重要的數據類型,包括符號和列表,以及程序作為對象的表示,還有其他一些。詞法作用域和塊結構是從Algo 60[21]語言中借鑒過來的。Scheme是第一種采用了詞法作用域和塊結構、第一類過程對象以及將尾調用處理成jumps的LISP方言。
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 first-class 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 first-class 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 general-purpose building blocks out of which such constructs (and others) may be built.
Common Lisp [27] 和Scheme都是現代的LISP語言,兩者互相影響中發展。像Scheme,但又不像早期Lisp語言,Common Lisp采用了詞法作用域和第一類過程,不過Common Lisp的語法擴展工具卻不支持詞法作用域。Common Lisp的過程求值規則和其他對象的求值規則不太一樣,盡管如此,它仍然保持了針對過程變量的分離命名空間(namespace),所以這不便于將過程當作第一類對象使用。Common Lisp也不支持continuation或者要求對尾調用的處理,但是它支持少數Scheme中沒有的通用控制結構。由于兩種語言非常相似,Common Lisp包括了一些特殊結構,而對應的Scheme則提供了一些更一般的通用構建塊,可以構造出前面Common Lisp提供的那些結構。
譯者說明:Common Lisp定義過程(DEFUN)和定義普通變量(DEFVAR)的時候需要用不同的過程,對過程變量賦值自然和對過程變量賦值就存在區別了。
The remainder of this chapter describes Scheme's syntax and naming conventions and the typographical conventions used throughout this book.
本章剩余部分講述了Scheme的語法和命名規范,以及全書的書寫約定。
1.1 Scheme 語法(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.
Scheme程序由關鍵詞、變量、結構化形式、常量數據(數、字符、字符串、引用向量、引用列表和引用符號等)、空格和注釋組成。
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
;, wheresv
is the scalar value of the character in hexadecimal notation.
關鍵詞、變量和符號統一被稱為標識符。標識符可以由字母、數字和某些特定的符號所組成,這些符號包括?
, !
, .
, +
, -
, *
, /
, <
, =
, >
, :
, $
, %
, ^
, &
, _
, ~
和@
符號,還有一些額外的Unicode字符。標識符不能由符號@
開始,通常(譯者:有些也是可以的,可以自己嘗試)不能從任何可能表示數字開始的符號開始(譯者:標識符不可以被當作數字先解析),例如一個數字、加號+
、減號-
或者小數點.
。除此之外的都是有效標識符,而且任何標識符可以從->
開始(譯者:這是特殊規定,大概其他的沒有特殊規定)。例如:hi
、Hello
、n
、x
、x3
、x+2
還有?$&*!!!
(譯者:這什么鬼?)這種都可以是合法的標識符。一個標識符或者任何其他Unicode字符都可以在任何位置作為標識符,其形式需要用轉義形式寫如\xsv
,其中sv
是這個字符的十六進制表示的標量數值。
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.
Scheme的標識符沒有長度限制;程序員可以按需使用任何字符。長標識符并不能替代注釋,而且,頻繁使用長標識符可能導致程序難以格式化和難于閱讀。一個不錯的規則是:當標識符的作用域比較小的時候采用短小標識符,當作用域較大時則采用長標識符。
Identifiers may be written in any mix of upper- and lower-case letters, and case is significant, i.e., two identifiers are different even if they differ only in case. For example,
abcde
,Abcde
,AbCdE
, andABCDE
all refer to different identifiers. This is a change from previous versions of the Revised Report.
標識符可以任意混合大小寫字母,而且區分大小寫字母,也就是說兩個標識符即使只是大小寫差異也算是不同的標識符。例如abcde
、Abcde
、AbCdE
、ABCDE
是不同的標識符。這和之前版本的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).
結構化形式和列表常量必須用圓括號括起來,如(a b c)
或(* (- x 2) y)
。空表寫作()
。方括號[]
可以用來替代方括號,常用于一些標準語法形式的子表達式中,可以改善可讀性,本書會給出一些例子。向量(Vector)類似列表,只是以#(
開始,)
結束,例如#(this is a vector of symbols)
。字節向量(Bytevector)寫作一個無符號字節值(0到255之間的整數),并用#vu8(
和)
括起來,如#vu(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 floating-point or scientific notation, e.g.,1.3
or1e23
, or as complex numbers in rectangular or polar notation, e.g.,1.3-2.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, so3
,0
,()
,"false"
, andnil
all count as true.
字符串用雙引號括起來,如"I am a string"
。字符用#\
開頭,例如#\a
表示字符a
。大小寫對于字符和字符串常量是很重要的,和標識符一樣。數值可以寫成整數,如-123
,也可以是分數,如1/2
,在浮點或者科學計數法中寫作1.3
或1e23
,此外復數數值可以用矩形記法或者幅角記法,如1.3-2.7i
或者-1.2@73
(譯者:這里幅角記法中的角度是弧度值)。數值寫法中的字母大小寫不重要。布爾值中的“真”(true)和“假”(false)分別寫作#t
和#f
。Scheme條件表達式一般都將#f
作為假,而其他對象都作為真,例如3
、0
、()
、"false"
和nil
等全部當作真來處理。
Details of the syntax for each type of constant data are given in the individual sections of Chapter 6.
關于每種常數類型的語法在第6章的一節中給出。
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 ....
Scheme 表達式可以展開成多行,且不需要顯式的終結符。因為空白字符的數量沒有要求,Scheme程序應當通過恰當的縮進來體現代碼的結構,這樣才能使代碼更加具有可讀性。注釋可以出現在Scheme程序的任何一行,使用分號;
直到改行結束。解釋一段表達式的注釋通常置于該表達式同等縮進級別的前一行。用來注釋一個過程、或者一組過程的內容通常放在這個過程的前面,且不帶縮進。多個縮進字符通常用于后面這種注釋,如:;;; 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)
.
Scheme還支持另外兩種注釋:塊注釋和數據注釋。塊注釋使用#|
和|#
對,并且支持嵌套注釋;一個數據注釋由前綴#;
和數據(打印值)跟隨。數據注釋經常用于對單個的定義或者表達式進行注釋。例如(three #;(not four) element list)
正是如此。數據注釋也可以被嵌套,所以#;#;(a)(b)
某種意義上注釋效果不如直接注釋(a)
和(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>
.
某些Scheme的數值,諸如過程和端口,沒有標準的打印表示,也沒有對應的程序中的可打印語法(譯者:用程序代碼寫出、表示)。這本書使用#<_description_>#
來顯式這類值,比如#<procedure>
或者#<port>
。
1.2 Scheme 命名規范(Scheme Naming Convention)
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 aspair?
, are created from the name of the type, in this case pair, and the question mark.
The names of most character, string, and vector procedures start with the prefixchar-
,string-
, andvector-
, e.g., string-append. (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 astype1->type2
, e.g.,vector->list
.
The names of procedures and syntactic forms that cause side effects end with an exclamation point!
. These includeset!
andvector-set!
. 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.
Scheme的命名規范被設計具有高度的規范性。下面是命名規范的一個列表:
- 謂詞名稱結尾總是問號
?
。謂詞是返回值為布爾值(要么為真,要么為假)的一類過程,例如eq?
、zero?
還有string=?
。常見的數值比較操作=
、<
、>
、<=
、>=
則是例外。 - 類型謂詞如
pair?
是從類型名和問號組成。 - 多數字符、字符串和向量過程的名稱以
char-
、string-
和vector-
開始。 - 將一個類型的對象轉換為另一個類型的過程的名字則寫作
type1->type2
,例如vector->list
。 - 會產生副作用的過程和語法形式的名字則以驚嘆號
!
結尾。比如有set!
和vector-set!
。處理輸入和輸出的過程技術上會產生副作用,但是它們的名字不遵守這條規則。
程序員應當盡可能的使自己的代碼采用上述約定。
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.
一個標準的過程或者語法形式,如果它的目的就是產生某些副作用,那么它的返回值是未被規定的。這就是說一個Scheme實現可以自行規定此類對象返回任何數值或者任何Scheme對象,也可以是過程或者語法形式。這些值在相同的實現、相同實現的多個版本之間、甚至這些過程或語法形式的兩次使用中會相同。一些Scheme系統使用了特殊對象用來表示這些未規定的數值。在交互式的Scheme系統中,一般不打印這個對象,所以返回這種未指定值的表達式不被打印。
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.
多數標準過程返回單一值,語言也支持返回零個、一個、或多個值,甚至通過5.8節中描述的機制可以返回可變數量的值。一些標準表達式也可能求值得到多個值,如果它的一個子表達式求值得到了多個返回值,例如調用一個返回多值的過程。當這種情況發生的時候,我們稱這個表達式返回了多個值,而不是簡單的說是它的子表達式的返回值。類似的,一個標準過程若其返回值是其調用一個過程參數的,被稱為其返回了由過程參數返回的值。
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
vector-ref
. 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.
此書使用“必須”和“應當”來描述程序的要求,例如要求調用vector-ref
時傳入的索引必須小于相應向量的長度。如果使用了“必須”一詞,意味著該Scheme實現是強制的,例如一個異常被拋出,通常帶有條件類型&assertion
。如果“應當”被使用,那么異常也許或未必被拋出,如若不是的話這個程序行為就沒有被定義。
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.
短語“違反語法”被用于描述一段程序出現了病態。違反語法的情況會在程序執行前就被檢測出來。當一個違反語法的情況被檢測出來,一個類型&syntax
的異常就會被拋出,而此時程序尚未執行。
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.
本書中的印刷格式的約定很簡單。所有的Scheme對象用打印機字體,如同從鍵盤中打出來的。包括語法關鍵詞、變量、常量對象、Scheme表達式和例程。斜體用于表達語法形式的語法變量和過程中的參數。斜體也可以被用于一些術語第一次出現的位置。一般來說,語法形式和過程的名字不會首字母大寫,即使在一句話的最前。這對于以斜體書寫的語法變量相同。
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 theor
syntactic form, which has zero or more subexpressions, and(member
obj list)
describes themember
procedure, which expects two arguments, an object and a list.
在語法形式或過程的描述中,一個或者多個原型模式給出應用過程時一種正確或多種正確的參數數量。關鍵詞或者過程名稱為打印機字體,包括括號。語法的剩余部分或者參數用斜體表示,使用一個可以暗示該語法形式或過程所需參數或表達式的類型的名稱。省略號表示一個子表達式或者參數出現0次或者多次。例如(or
expr ...)
表示or
的語法形式,后續參數可以為0個或多個子表達式,而(member
obj list )
表示了member
這個過程需要兩個參數,一個是對象,一個是列表。
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 forvector-set!
is
(vector-set!
vector n obj)
and the description says that n must be an exact nonnegative integer strictly less than the length of vector. Thus,vector-set!
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.
若一段語法結構不匹配其圓形時,將發生違法語法的情況。類似的,如果傳入標準過程的參數不匹配其規定,則會拋出一個帶有條件類型&assertion
的異常。同樣的,一個標準過程如果接收到的參數類型與其名字所指的類型不匹配或者無法滿足其他判斷準則時,也會產生這樣的遺傳。例如,下列vector-set!
原型:
(vector-set!
vector n obj)
著段表示中n必須是一個非負整數(嚴格小于vector的長度)。所以,vector-set!
必須是三個參數,第一個是一個向量,第二個必須是一個非負整數,切小于該向量的長度,第三個參數則可以是任何Scheme值。不滿足上述條件時,將會產生一個帶有條件類型&assertion
的異常 。
In most cases, the type of argument required is obvious, as with vector, obj, or binary-input-port. 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.
在多數情況下,參數類型是顯然的,例如vector、obj或者binary-input-port。另一些情況下,主要是一些數值類程序,一般使用簡寫,如int對應整數,exint對應精確整數,fx對應定點數。這些簡寫可以在有關章節的開頭部分找到解釋。