-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathbase.tex
3782 lines (3020 loc) · 139 KB
/
base.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%\vfill\eject
\chapter{基本库(Base library)}
\label{baselibrarychapter}
本章描述Scheme的\defrsixlibrary{base}库,其导出了很多通常和Scheme一起的过程和语法绑定。
第\ref{basetailcontextsection}小节定义了来自\rsixlibrary{base}库的从结构上识别尾调用和尾上下文的规则。
\section{基本类型(Base types)}
\label{disjointness}
没有变量满足下列谓词中的多个:
\begin{scheme}
boolean? pair?
symbol? number?
char? string?
vector? procedure?
null?%
\end{scheme}
这些谓词定义了基本的类型{\em 布尔},{\em 点对},{\em 符号},{\em 数字},{\em 字符},{\em 字符串},{\em 向量},以及{\em 过程}。此外,空表是一个特殊的对象,它有自己的类型。
\mainindex{type,类型}\schindex{boolean?}\schindex{pair?}\schindex{symbol?}
\schindex{number?}\schindex{char?}\schindex{string?}\schindex{vector?}
\schindex{procedure?}\index{empty list,空表}\schindex{null?}
注意,尽管有一个单独的布尔类型,但是,任何Scheme值在条件测试中都可以被当作一个布尔值使用;见\ref{booleanvaluessection}小节。
\section{定义(Definitions)}
\label{defines}
定义\mainindex{definition,定义}出现在一个\meta{top-level body}(\ref{programsyntaxsection}小节)中,\meta{library body}的最上面(\ref{librarysyntaxsection}小节),或\meta{body}的最上面(\ref{bodiessection}小节)。
一个\hyper{definition}可以是一个变量定义(\ref{variabledefinitionsection}小节),或一个关键词定义(\ref{variabledefinitionsection}小节)。扩展到定义或定义组(打包在一个{\cf begin}, {\cf let-syntax}, 或{\cf letrec-syntax}形式中;见\ref{begin}小节)中的宏使用也可以出现在任何其它定义可以出现的地方。
\subsection{变量定义}
\label{variabledefinitionsection}
本节描述的{\cf define}形式是一个用作创建变量绑定的\hyper{definition}\mainindex{definition,定义},且可以出现在其它定义可以出现的任何地方。
% TODO
\begin{entry}{%
\proto{define}{ \hyper{variable} \hyper{expression}}{\exprtype}
\rproto{define}{ \hyper{variable}}{\exprtype}
\pproto{(define (\hyper{variable} \hyper{formals}) \hyper{body})}{\exprtype}
\pproto{(define (\hyper{variable} .\ \hyper{formal}) \hyper{body})}{\exprtype}}
{\cf define}的第一个形式绑定\hyper{variable}到一个新的位置,然后将\hyper{expression}的值赋值给这个位置。
\begin{scheme}
(define add3
(lambda (x) (+ x 3)))
(add3 3) \ev 6
(define first car)
(first '(1 2)) \ev 1%
\end{scheme}
%
\hyper{expression}的继续不应该被调用多于一次。
% TODO
\implresp 实现应当检测\hyper{expression}的继续被调用多于一次的情况。如果实现检测到这个的话,它必须抛出一个条件类型是{\cf\&assertion}的异常。
{\cf define}的第二种形式等价于
\begin{scheme}
(define \hyper{variable} \hyper{unspecified})%
\end{scheme}
其中\hyper{unspecified}是一个返回未定义值得无副作用的表达式。
在{\cf define}的第三个形式中,\hyper{formals}必须或者是零个或多个变量的序列,或者是一个或多个变量的序列,其跟着一个点{\cf .}和另一个变量(就像在一个lambda表达式中一样,见\ref{lambda}小节)。这个形式等价于
\begin{scheme}
(define \hyper{variable}
(lambda (\hyper{formals}) \hyper{body}))\rm.%
\end{scheme}
在{\cf define}的第四个形式中,\hyper{formal}必须是一个单独的变量。这个形式等价于
\begin{scheme}
(define \hyper{variable}
(lambda \hyper{formal} \hyper{body}))\rm.%
\end{scheme}
\end{entry}
\subsection{语法定义(Syntax definitions)}
\label{syntaxdefinitionsection}
本节描述的{\cf define-syntax}形式是一个用作创建关键词绑定的\hyper{definition}\mainindex{definition,定义},其可以出现在任何其它定义可以出现的地方。
\begin{entry}{%
\proto{define-syntax}{ \hyper{keyword} \hyper{expression}}{\exprtype}}
绑定\hyper{keyword}到\hyper{expression}的值,其必须在宏扩展的阶段求值得到一个转换器。宏转换器可以使用\ref{syntaxrulessection}小节描述的{\cf syntax-rules}和{\cf identifier-syntax}形式创建。见库的第\extref{lib:transformerssection}{Transformers}小节,那儿有一个转换器更全面的描述。
通过{\cf define-syntax}建立的关键词绑定在其出现的整个内部都是可见的,除非被其它绑定覆盖外都是可见的,就像{\cf define}建立的变量绑定一样。通过一组定义建立的绑定,不管是关键词还是变量定义,在定义它们自己中是可见的。
\implresp 实现应该检测\hyper{expression}的值是不是一个适当的转换器。
例子:
\begin{scheme}
(let ()
(define even?
(lambda (x)
(or (= x 0) (odd? (- x 1)))))
(define-syntax odd?
(syntax-rules ()
((odd? x) (not (even? x)))))
(even? 10)) \ev \schtrue{}%
\end{scheme}
从左到右的处理顺序(第\ref{expansionchapter}章)的言外之意是一个定义可以影响后续的形式是否也是一个定义。
例子:
\begin{scheme}
(let ()
(define-syntax bind-to-zero
(syntax-rules ()
((bind-to-zero id) (define id 0))))
(bind-to-zero x)
x) \ev 0%
\end{scheme}
任何出现在{\cf let}表达式外面的{\cf bind-to-zero}的绑定都不会影响其行为。
\end{entry}
\section{内部(Bodies)}
\label{bodiessection}
\index{body,内部}\ide{lambda}, \ide{let}, \ide{let*}, \ide{let-values}, \ide{let*-values}, \ide{letrec}, 或\ide{letrec*}表达式的\hyper{body},或由零个或多个跟着一个或多个表达式的定义。
{\cf \hyper{definition} \ldots{} \hyperi{expression} \hyperii{expression} \ldots}
通过一个定义定义的标识符在\hyper{body}中局部的。也就是说,标识符被绑定到,且绑定的作用域是这个\hyper{body}(见第\ref{variablesection}小节)。
例子
%
\begin{scheme}
(let ((x 5))
(define foo (lambda (y) (bar x y)))
(define bar (lambda (a b) (+ (* a b) a)))
(foo (+ x 3))) \ev 45%
\end{scheme}
%
当{\cf begin}, {\cf let-syntax}, 或{\cf letrec-syntax}形式先于第一个表达式出现在内部的时候,它们被拼接到内部;见第\ref{begin}小节。内部的一些或所以<!-- TODO -->,包括{\cf begin}, {\cf let-syntax}, 或{\cf letrec-syntax}形式里面的部分,可以通过一个宏使用指定(见第\ref{macrosection}小节)。
一个包含变量定义的被扩展的\hyper{body}(见第\ref{expansionchapter}章)总是可以被转换成一个等价的{\cf letrec*}表达式。比如,上面例子中的{\cf let}表达式等价于
\begin{scheme}
(let ((x 5))
(letrec* ((foo (lambda (y) (bar x y)))
(bar (lambda (a b) (+ (* a b) a))))
(foo (+ x 3))))%
\end{scheme}
\section{表达式}
\label{expressionsection}
本节的条目描述\rsixlibrary{base}库中的表达式,除了第\ref{primitiveexpressionsection}小节描述的基本表达式类型,其可以出现在\hyper{expression}句法变量的位置中。
\subsection{引用(Quotation)}\unsection
\label{quotesection}
\begin{entry}{%
\proto{quote}{ \hyper{datum}}{\exprtype}}
\syntax \hyper{Datum}应该是一个句法数据。 % TODO
\semantics
{\cf (quote \hyper{datum})}的值是\hyper{datum}表示的数据值(见第\ref{datumsyntaxsection}小节)。这个符号被用作包含常量。 % TODO
\begin{scheme}%
(quote a) \ev a
(quote \sharpsign(a b c)) \ev \#(a b c)
(quote (+ 1 2)) \ev (+ 1 2)%
\end{scheme}
正如第\ref{abbreviationsection}小节所说,{\cf (quote \hyper{datum})}可以使用缩写\singlequote\hyper{datum}:
\begin{scheme}
'"abc" \ev "abc"
'145932 \ev 145932
'a \ev a
'\#(a b c) \ev \#(a b c)
'() \ev ()
'(+ 1 2) \ev (+ 1 2)
'(quote a) \ev (quote a)
''a \ev (quote a)%
\end{scheme}
正如第\ref{storagemodel}小节所说,常量是不可变得。
\begin{note}
一个{\cf quote}表达式值的不同常数可以共享相同的位置。
\end{note}
\end{entry}
\subsection{过程}\unsection
\label{lamba}
\begin{entry}{%
\proto{lambda}{ \hyper{formals} \hyper{body}}{\exprtype}}
\syntax
\hyper{Formals}必须是一个下面描述的形参(formal parameter)列表,且\hyper{body}必须和第\ref{bodiessection}小节描述的一样。
\semantics
\vest \lambdaexp{}表达式的值是过程。当\lambdaexp{}表达式被求值时的有效环境被作为过程的一部分被记忆。当过程随后以一些参数被调用的时候,\lambdaexp{}表达式被求值时使用的环境通过绑定参数列表中的变量到新的位置的方式被扩展,且相应的实参值被存储到那些位置。然后,\lambdaexp{}表达式内部的表达式(其可能包含定义,因此可能表现为一个{\cf letrec*}形式,见第\ref{bodiessection}小节)在扩展的环境中被顺序地求值。内部最后一个表达式的结果作为过程调用的结果被返回。
\begin{scheme}
(lambda (x) (+ x x)) \ev {\em{}一个过程}
((lambda (x) (+ x x)) 4) \ev 8
((lambda (x)
(define (p y)
(+ y 1))
(+ (p x) x))
5) \ev 11
(define reverse-subtract
(lambda (x y) (- y x)))
(reverse-subtract 7 10) \ev 3
(define add4
(let ((x 4))
(lambda (y) (+ x y))))
(add4 6) \ev 10%
\end{scheme}
\hyper{Formals}必须有下列的形式之一:
\begin{itemize}
\item {\tt(\hyperi{variable} \dotsfoo)}:
过程拥有固定数量的参数。当过程被调用时,参数将被存储在相应变量的绑定中。
\item \hyper{variable}:
过程拥有任意数量的参数。当过程被调用时,实参的序列被转换为一个新创建的表,该表存储在\hyper{variable}的绑定中。
\item {\tt(\hyperi{variable} \dotsfoo{} \hyper{variable$_{n}$}\ {\bf.}\
\hyper{variable$_{n+1}$})}:
如果一个由空格分隔的{\cf .}出现在最后一个变量之前,该过程就拥有$n$个或更多个参数,这里的$n$是句点前面形参的个数(至少要有一个)。存储在最后一个参数绑定中的值是一个新创建的表。除了已和其他形参匹配的所有其他实参外,剩余的实参都被存入该表中。
\end{itemize}
\begin{scheme}
((lambda x x) 3 4 5 6) \ev (3 4 5 6)
((lambda (x y . z) z)
3 4 5 6) \ev (5 6)%
\end{scheme}
在\hyper{formals}中任何\hyper{variable}必须不能出现超过一次。
\end{entry}
\subsection{条件表达式(Conditionals)}\unsection
\begin{entry}{%
\proto{if}{ \hyper{test} \hyper{consequent} \hyper{alternate}}{\exprtype}
\rproto{if}{ \hyper{test} \hyper{consequent}}{\exprtype}} %\/ if hyper = italic
\syntax
\hyper{Test},\hyper{consequent}和\hyper{alternate}必须是表达式。
\semantics
{\cf if}表达式按如下方式计算:首先,计算\hyper{test}的值。如果产生一个真值\index{true,真值}(见第\ref{booleanvaluessection}小节),然后\hyper{consequent}被计算,且它的值被返回。否则,\hyper{alternate}被计算,且它的值被返回。如果\hyper{test}产生\schfalse{}且没有指定\hyper{alternate},那么,表达式的结果是未定义的(\isunspecified)。
\begin{scheme}
(if (> 3 2) 'yes 'no) \ev yes
(if (> 2 3) 'yes 'no) \ev no
(if (> 3 2)
(- 3 2)
(+ 3 2)) \ev 1
(if \#f \#f) \ev \theunspecified%
\end{scheme}
\hyper{consequent}和\hyper{alternate}表达式在尾上下文中,如果{\cf if}表达式它自己在的话;见第\ref{basetailcontextsection}小节。
\end{entry}
\subsection{赋值(Assignments)}\unsection
\label{assignment}
\begin{entry}{%
\proto{set!}{ \hyper{variable} \hyper{expression}}{\exprtype}}
\hyper{Expression}被计算,且结果值被存进\hyper{variable}绑定的位置。\hyper{Variable}必须在包含{\cf set!}表达式的区域或顶层被绑定。{\cf set!}表达式的结果是未定义的。
\begin{scheme}
(let ((x 2))
(+ x 1)
(set! x 4)
(+ x 1)) \ev 5%
\end{scheme}
如果\hyper{variable}引用一个不可修改的绑定,那么这时一个语法错误。
\begin{note}
标识符{\cf set!}同时以级别$1$被导出。见第\ref{identifier-syntax}小节。
\end{note}
\end{entry}
\subsection{派生(Derived)条件表达式}\unsection
\begin{entry}{%
\proto{cond}{ \hyperi{cond clause} \hyperii{cond clause} \dotsfoo}{\exprtype}
\litproto{=>}
\litproto{else}}
\syntax
每一个\hyper{cond clause}必须是形式
\begin{scheme}
(\hyper{test} \hyperi{expression} \dotsfoo)%
\end{scheme}
其中\hyper{test}是一个表达式。或有另一种选择,一个\hyper{cond clause}可以是形式\begin{scheme}
(\hyper{test} => \hyper{expression})%
\end{scheme}
最后一个\hyper{cond clause}可以是一个“{\cf else}子句”,其有形式
\begin{scheme}
(else \hyperi{expression} \hyperii{expression} \dotsfoo)\rm。%
\end{scheme}
\semantics
一个{\cf cond}表达式通过以下方式求值,按顺序连续地对\hyper{test}表达式进行求值直到它们其中一个的值是真值(见第\ref{booleanvaluessection}小节)。当一个\hyper{test}的值是真值的时候,就会顺序地对它\hyper{cond clause}中剩余的\hyper{expression}进行求值,且\hyper{cond clause}中最后一个\hyper{expression}的结果会作为整个{\cf cond}表达式的结果被返回。如果被选择的\hyper{cond clause}只包含\hyper{test}且没有\hyper{expression},那么\hyper{test}的值会作为结果被返回。如果被选择的\hyper{cond clause}使用\ide{=>}辅助形式,那么\hyper{expression}被计算。它的值必须是一个过程。这个过程必须接受一个参数;它被以\hyper{test}的值调用,且过程返回的值作为{\cf cond}表达式的值返回。如果所有的\hyper{test}的值都是\schfalse,并且没有{\cf else}子句,那么条件表达式返回未定义的值(\unspecifiedreturn);如果有一个{\cf else}子句,那么它的\hyper{expression}被计算,且最后一个的值被返回。
\begin{scheme}
(cond ((> 3 2) 'greater)
((< 3 2) 'less)) \ev greater%
(cond ((> 3 3) 'greater)
((< 3 3) 'less)
(else 'equal)) \ev equal%
(cond ('(1 2 3) => cadr)
(else \schfalse{})) \ev 2%
\end{scheme}
对于一个有下列的形式之一的\hyper{cond clause}
%
\begin{scheme}
(\hyper{test} \hyperi{expression} \dotsfoo)
(else \hyperi{expression} \hyperii{expression} \dotsfoo)%
\end{scheme}
%
最后一个\hyper{expression}在尾上下文中,如果{\cf cond}形式它自己在的话。一个如下形式的\hyper{cond clause}
\begin{scheme}
(\hyper{test} => \hyper{expression})%
\end{scheme}
来自\hyper{expression}求值结果的过程的(隐式)调用在尾上下文中如果{\cf cond}形式它自己在的话。见第\ref{basetailcontextsection}小节。
一个更简单形式的{\cf cond}的参考定义可以在附录\ref{derivedformsappendix}中被找到。
\end{entry}
\begin{entry}{%
\proto{case}{ \hyper{key} \hyperi{case clause} \hyperii{case clause} \dotsfoo}{\exprtype}}
\syntax
\hyper{Key}必须是一个表达式。每一个\hyper{case clause}必须有下列形式之一:
\begin{scheme}
((\hyperi{datum} \dotsfoo) \hyperi{expression} \hyperii{expression} \dotsfoo)
(else \hyperi{expression} \hyperii{expression} \dotsfoo)%
\end{scheme}
\schindex{else}
第二个形式,其指定一个“{\cf else}子句”,只可以作为最后一个\hyper{case clause}出现。每一个\hyper{datum}是一些对象的一个外部表示。\hyper{Datum}表示的数据不需要有区别。
\semantics
一个{\cf case}按如下求值。\hyper{key}被求值,且它的结果被和每个\hyper{case clause}中的\hyper{datum}表示的数据轮流比较,比较的依据是{\cf eqv?}(见第\ref{eqv?}小节),以从左到右的顺序在整个子句的集合中进行。如果求值后\hyper{key}的值等于一个\hyper{case clause}的数据,对应的表达式被从左向右地求值,且\hyper{case clause}最后一个表达式的结果将作为{\cf case}表达式的结果被返回。如果求值后的\hyper{key}的值和每个子句中的数据都不一样,那么如果有一个{\cf else}子句的话,它的表达式被计算且最后一个的结果作为{\cf case}表达式的结果被返回;否则{\cf case}表达式的返回未定义的值。
\begin{scheme}
; 本示例已根据勘误表修改
(case (* 2 3)
((2 3 5 7) 'prime)
((4 6 8 9) 'composite)) \ev composite
(case (car '(c d))
((a) 'a)
((b) 'b)) \ev \theunspecified
(case (car '(c d))
((a e i o u) 'vowel)
((w y) 'semivowel)
(else 'consonant)) \ev consonant%
\end{scheme}
一个\hyper{case clause}的最后一个\hyper{expression}在尾上下文中,如果{\cf case}表达式它自己在的话;见第\ref{basetailcontextsection}小节。
% A sample definition of {\cf case} in terms of simpler forms is in
% appendix~\ref{derivedformsappendix}.
\end{entry}
\begin{entry}{%
\proto{and}{ \hyperi{test} \dotsfoo}{\exprtype}}
\syntax \hyper{Test}必须是一个表达式。
\semantics 如果没有\hyper{test},\schtrue{}被返回。否则\hyper{test}表达式被从左向右地求值,直到一个\hyper{test}返回\schfalse{},或到达最后一个\hyper{test}。前一种情况下,{\cf and}表达式在不计算剩余表达式的情况下返回\schfalse{}。后一种情况,最后一个表达式被计算且它的值被返回。
\begin{scheme}
(and (= 2 2) (> 2 1)) \ev \schtrue
(and (= 2 2) (< 2 1)) \ev \schfalse
(and 1 2 'c '(f g)) \ev (f g)
(and) \ev \schtrue%
\end{scheme}
{\cf and}关键词可以使用{\cf syntax-rules}(见第\ref{syntaxrulessection}小节)根据{\cf if}进行定义,如下所示:
\begin{scheme}
(define-syntax \ide{and}
(syntax-rules ()
((and) \sharpfoo{t})
((and test) test)
((and test1 test2 ...)
(if test1 (and test2 ...) \sharpfoo{f}))))%
\end{scheme}
最后一个\hyper{test}表达式在尾上下文中,如果{\cf and}表达式它自己在的话;见第\ref{basetailcontextsection}小节。
\end{entry}
\begin{entry}{%
\proto{or}{ \hyperi{test} \dotsfoo}{\exprtype}}
\syntax \hyper{Test}必须是表达式。
\semantics 如果没有\hyper{test},那么\schfalse{}被返回。否则,\hyper{test}按照从左到右的顺序被求值,直到一个\hyper{tesst}返回真值\var{val}(见第\ref{booleanvaluessection}小节),或到达最后一个\hyper{test}。在前一种情况,{\cf or}表达式在不计算剩余表达式的情况下返回\var{val}。后一种情况,最后一个表达式被求值,且它的值被返回。
\begin{scheme}
(or (= 2 2) (> 2 1)) \ev \schtrue
(or (= 2 2) (< 2 1)) \ev \schtrue
(or \schfalse \schfalse \schfalse) \ev \schfalse
(or '(b c) (/ 3 0)) \ev (b c)%
\end{scheme}
{\cf or}关键词可以使用{\cf syntax-rules}(见第\ref{syntaxrulessection}小节)根据{\cf if}进行定义,如下所示:
\begin{scheme}
(define-syntax \ide{or}
(syntax-rules ()
((or) \sharpfoo{f})
((or test) test)
((or test1 test2 ...)
(let ((x test1))
(if x x (or test2 ...))))))%
\end{scheme}
最后一个\hyper{test}表达式在尾上下文中,如果{\cf or}表达式它自己也在的话;见第\ref{basetailcontextsection}小节。
\end{entry}
\subsection{绑定结构(Binding constructs)}
本节描述的绑定结构为变量创建本地绑定,它们只可以在一个限定的区域可见。结构{\cf let}, {\cf let*}, {\cf letrec}, 和{\cf letrec*}的语法是一样的,但是它们为它们的变量绑定建立的作用域(region)\index{region,作用域}(见\ref{variablesection}小节)是不一样的,且绑定的值计算的顺序是不一样的。在一个{\cf let}表达式中,初始值被计算在任何变量被绑定之前;在一个{\cf let*}表达式中,绑定和求值依次地执行。在一个{\cf letrec}或{\cf letrec*}表达式中,当所有的绑定正在被计算的时候所以的绑定生效,因此允许相互递归的定义。在一个{\cf letrec}表达式中,初始值在赋值给变量之前被计算;在一个{\cf letrec*}中,计算和赋值依次地进行。
此外,绑定结构{\cf let-values}和{\cf let*-values}使得{\cf let}和{\cf let*}更加通用,起允许多个变量绑定到值是多个值得表达式的结果。在建立作用域的方面,它们类似于{\cf let}和{\cf let*}:在一个{\cf let-values}表达式中,初始值被计算在任何变量被绑定之前;在一个{\cf let*-values}表达式中,绑定依次进行。
本节提到的所有绑定形式根据更简单形式的参考定义可以在附录\ref{derivedformsappendix}中找到。
\begin{entry}{%
\proto{let}{ \hyper{bindings} \hyper{body}}{\exprtype}}
\syntax
\hyper{Bindings}必须有形式
\begin{scheme}
((\hyperi{variable} \hyperi{init}) \dotsfoo)\rm,%
\end{scheme}
其中,每一个\hyper{init}是一个表达式,且\hyper{body}如第\ref{bodiessection}小节描述。在\hyper{variable}中任何变量不能出现超过一次。
\semantics
\hyper{Init}在当前的环境被求值(以一个未定义的顺序),\hyper{variable}被绑定到存有结果的新鲜的位置,\hyper{body}在扩展后的环境被求值,且\hyper{body}的最后一个表达式的值被返回。每个\hyper{variable}的绑定都将\hyper{body}作为它的作用域。\index{region,作用域}
\begin{scheme}
(let ((x 2) (y 3))
(* x y)) \ev 6
(let ((x 2) (y 3))
(let ((x 7)
(z (+ x y)))
(* z x))) \ev 35%
\end{scheme}
另参见命名{\cf let},见第\ref{namedlet}小节。
\end{entry}
\begin{entry}{%
\proto{let*}{ \hyper{bindings} \hyper{body}}{\exprtype}}\nobreak
\nobreak
\syntax
\hyper{Bindings}必须是形式
\begin{scheme}
((\hyperi{variable} \hyperi{init}) \dotsfoo)\rm,%
\end{scheme}
其中,每一个\hyper{init}是一个表达式,且\hyper{body}如第\ref{bodiessection}小节描述。
\semantics
{\cf let*}形式类似于{\cf let},但是\hyper{init}的求值和绑定的创建是从左向右顺序进行的,但其作用域不但包括\hyper{body},还包括其右边的部分。因此,第二个\hyper{init}在第一个绑定可见且初始化的环境中被计算,以此类推。
\begin{scheme}
(let ((x 2) (y 3))
(let* ((x 7)
(z (+ x y)))
(* z x))) \ev 70%
\end{scheme}
\begin{note}
通过{\cf let}表达式绑定的变量必须是不一样的,而通过{\cf let*}表达式绑定的变量则没有这个限制。
\end{note}
\end{entry}
\begin{entry}{%
\proto{letrec}{ \hyper{bindings} \hyper{body}}{\exprtype}}
\syntax
\hyper{Bindings}必须有形式
\begin{scheme}
((\hyperi{variable} \hyperi{init}) \dotsfoo)\rm,%
\end{scheme}
其中,每一个\hyper{init}是一个表达式,且\hyper{body}如第\ref{bodiessection}小节描述。在\hyper{variable}中任何变量不能出现超过一次。
\semantics
\hyper{variable}被绑定到新的位置,\hyper{init}在结果环境中被求值(以一些未定义的顺序),每一个\hyper{variable}被分配给对应的\hyper{init}的结果,\hyper{body}在结果环境中被求值,且\hyper{body}中最后一个表达式的值被返回。每个\hyper{variable}的绑定将整个{\cf letrec}表达式作为它的作用域\index{region,作用域},这使得定义相互递归的过程成为可能。
\begin{scheme}
%(letrec ((x 2) (y 3))
% (letrec ((foo (lambda (z) (+ x y z))) (x 7))
% (foo 4))) \ev 14
%
(letrec ((even?
(lambda (n)
(if (zero? n)
\schtrue
(odd? (- n 1)))))
(odd?
(lambda (n)
(if (zero? n)
\schfalse
(even? (- n 1))))))
(even? 88))
\ev \schtrue%
\end{scheme}
在不赋值或引用任何\hyper{variable}的值的情况下,计算每个\hyper{init}应该是可能的。在{\cf letrec}的大部分常规使用中,所有的\hyper{init}是\lambdaexp{}表达式,此时限制被自动满足。另一个限制是,每个\hyper{init}的继续不能被调用多于一次。
\implresp 实现必须在\hyper{init}表达式求值(使用一个特定的求值顺序且顺序\hyper{init}表达式的值)期间检测\hyper{variable}的引用。如果实现检测到这样一个限制的违反,它必须抛出一个条件类型是{\cf\&assertion}的异常。实现可以也可以不检测每个\hyper{init}的继续是否被调用多于一次。可是,如果实现检测到的话,它必须抛出一个条件类型是{\cf\&assertion}的异常。
\end{entry}
\begin{entry}{%
\proto{letrec*}{ \hyper{bindings} \hyper{body}}{\exprtype}}
\syntax
\hyper{Bindings}必须有形式
\begin{scheme}
((\hyperi{variable} \hyperi{init}) \dotsfoo)\rm,%
\end{scheme}
其中,每一个\hyper{init}是一个表达式,且\hyper{body}如第\ref{bodiessection}小节描述。在\hyper{variable}中任何变量不能出现超过一次。
\semantics
\hyper{Variable}被绑定到新鲜的位置,每个\hyper{variable}被按从左向右的顺序分配给对应的\hyper{init}的求值结果,\hyper{body}在结果环境中被求值,且\hyper{body}中最后一个表达式的值被返回。尽管求值和赋值的顺序是从左向右的,但是每一个\hyper{variable}的绑定将整个{\cf letrec*}表达式作为其作用域\index{region,作用域},这使得定义相互递归的过程成为可能。
\begin{scheme}
(letrec* ((p
(lambda (x)
(+ 1 (q (- x 1)))))
(q
(lambda (y)
(if (zero? y)
0
(+ 1 (p (- y 1))))))
(x (p 5))
(y x))
y)
\ev 5%
\end{scheme}
在不赋值或引用对应的\hyper{variable}或任何在\hyper{bindings}跟随它的任何绑定的\hyper{variable}的值的情况下,计算每个\hyper{init}必须是可能的。另一个限制是每个\hyper{init}的继续不能被调用多于一次。
\implresp 实现必须在\hyper{init}表达式求值期间检测\hyper{variable}或任何在\hyper{bindings}跟随它的任何绑定的\hyper{variable}% TODO
的引用。如果实现检测到这样一个限制的违反,它必须抛出一个条件类型是{\cf\&assertion}的异常。实现可以也可以不检测每个\hyper{init}的继续是否被调用多于一次。可是,如果实现检测到的话,它必须抛出一个条件类型是{\cf\&assertion}的异常。
\end{entry}
\begin{entry}{%
\proto{let-values}{ \hyper{mv-bindings} \hyper{body}}{\exprtype}}
\syntax
\hyper{Mv-bindings}必须有形式
\begin{scheme}
((\hyperi{formals} \hyperi{init}) \dotsfoo)\rm,%
\end{scheme}
其中,每一个\hyper{init}是一个表达式,且\hyper{body}如第\ref{bodiessection}小节描述。在\hyper{formals}集合中任何变量必须不能出现超过一次。
\semantics \hyper{Init}在当前的环境中被求值(以一些未定义的顺序),且出现在\hyper{formals}中的变量被绑定到包含\hyper{init}返回值的新鲜位置,其中\hyper{formals}匹配返回值就像\lambdaexp{}表达式中的\hyper{formals}在过程调用中匹配参数一样。然后,\hyper{body}在扩展后的环境中被求值,且\hyper{body}中最后一个表达式的值被返回。每个变量绑定将\hyper{body}作为它的作用域。\index{region,作用域}如果\hyper{formals}不匹配的话,那么一个条件类型是{\cf\&assertion}的异常被抛出。
\begin{scheme}
(let-values (((a b) (values 1 2))
((c d) (values 3 4)))
(list a b c d)) \ev (1 2 3 4)
(let-values (((a b . c) (values 1 2 3 4)))
(list a b c)) \ev (1 2 (3 4))
(let ((a 'a) (b 'b) (x 'x) (y 'y))
(let-values (((a b) (values x y))
((x y) (values a b)))
(list a b x y))) \ev (x y a b)%
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{let*-values}{ \hyper{mv-bindings} \hyper{body}}{\exprtype}}
\syntax
\hyper{Mv-bindings}必须有形式
\begin{scheme}
((\hyperi{formals} \hyperi{init}) \dotsfoo)\rm,%
\end{scheme}
其中,每一个\hyper{init}是一个表达式,且\hyper{body}如第\ref{bodiessection}小节描述。在每个\hyper{formals}中,任何变量必须不能出现超过一次。
\semantics
{\cf let*-value}形式类似于{\cf let-value},但是\hyper{init}被计算和绑定被创建是按从左到右的顺序进行的,每个\hyper{formals}绑定的作用域\index{region,作用域}除了\hyper{body}还包括它的右边。因此,第二个\hyper{init}在第一个\hyper{formals}可见且被初始化的环境中被求值,以此类推。
\begin{scheme}
(let ((a 'a) (b 'b) (x 'x) (y 'y))
(let*-values (((a b) (values x y))
((x y) (values a b)))
(list a b x y))) \ev (x y x y)%
\end{scheme}
\begin{note}
通过{\cf let-values}表达式绑定的变量必须是不一样的,而通过{\cf let*-values}表达式的不同\hyper{formals}绑定的变量则没有这个限制。
\end{note}
\end{entry}
\subsection{顺序结构(Sequencing)}\unsection
\begin{entry}{%
\proto{begin}{ \hyper{form} \dotsfoo}{\exprtype}
\rproto{begin}{ \hyper{expression} \hyper{expression} \dotsfoo}{\exprtype}}
\hyper{Begin}关键词有两个不同的作用,取决于它的上下文:
\begin{itemize}
\item 它可以作为一个形式出现在一个\hyper{body}中(见第\ref{bodiessection}小节),一个\hyper{library body}中(见第\ref{librarybodysection}小节),或一个\hyper{top-level body}(见第\ref{programchapter}章),或直接嵌套在一个内部的{\cf begin}形式中。在这种情况下,{\cf begin}形式必须有第一个标题行指定的形状。{\cf begin}的这种用法作为一种\defining{拼接(splicing)}形式—\hyper{body}里面的形式被拼接到内部周围,就好像原来的{\cf begin}包装不存在一样。
\hyper{Body}或\hyper{library body}中的{\cf begin}形式必须是非空的,如果它在内部出现在第一个\hyper{expression}之后。
\item 它可以作为一个普通的表达式出现,且必须有第二个标题行指定的形状。在这种情况下,\hyper{expression}被按从左到右的顺序求值,且最后一个\hyper{expression}的值被返回。这种表达式类型被用作按顺序排列副作用,如赋值或输入输出。
\end{itemize}
\begin{scheme}
(define x 0)
(begin (set! x 5)
(+ x 1)) \ev 6
(begin (display "4 plus 1 equals ")
(display (+ 4 1))) \ev \unspecified
\>{\em 并打印} 4 plus 1 equals 5%
\end{scheme}
\end{entry}
\section{等价谓词(Equivalence predicates)}
\label{equivalencesection}
一个\defining{谓词}是一个总是返回布尔值(\schtrue{}或\schfalse{})的过程。一个\defining{等价谓词}在计算上模拟数学上的等价关系(它是[对称的(symmetric),自反的(reflexive),且传递的(transitive)](/r6rs-translation-experience/#symmetric-reflexive-transitive))。在本节表述的等价谓词中,{\cf eq?}是最好或最精细的,{\cf equal?}是最粗糙的。{\cf eqv?}比{\cf eq?}的辨别能力稍差。 \todo{Pitman doesn't like
this paragraph. Lift the discussion from the Maclisp manual. Explain
why there's more than one predicate.}
\begin{entry}{%
\proto{eqv?}{ \vari{obj} \varii{obj}}{procedure}}
{\cf eqv?}定义在对象上定义一个有用的等价关系。简单地说,它返回\schtrue{},如果\vari{obj}和\varii{obj}在通常情况下被认为是相等的对象的话,否则返回\schfalse{}。这种关系不太好解释,但下面所列的{\cf eqv?}部分规范必须被所有的实现遵守。
{\cf eqv?}过程在以下情况返回\schtrue{}:
\begin{itemize}
\item \vari{Obj}和\varii{obj}都是布尔,且根据{\cf boolean=?}过程它们是一样的(第\ref{boolean=?}小节)。
\item \vari{Obj}和\varii{obj}都是符号,且根据{\cf symbol=?}过程它们是一样的(第\ref{symbol=?}小节)。
\item \vari{Obj}和\varii{obj}都是精确\index{exact,精确}数,且在数学上相等(见{\cf =},第\ref{genericarithmeticsection}小节)。
\item \vari{Obj}和\varii{obj}都是非精确数字对象,且在数学上相等(见{\cf =},第\ref{genericarithmeticsection}小节),且作为参数传递给任意其它可以通过Scheme标准算术过程定义的过程时产生的结果都是一样的(从{\cf eqv?}的意义上说),只要计算过程中不涉及非数。(本句已根据勘误表补全。)
\item \vari{Obj}和\varii{obj}都是字符,且根据{\cf char=?}过程它们是一样的(见第\ref{charactersection}小节)。
\item \vari{Obj}和\varii{obj}都是空表。
\item \vari{Obj}和\varii{obj}都是对象,比如点对,向量,字节向量(库的第\extref{lib:bytevectorschapter}{Bytevectors}章),字符串,记录(库的第\extref{lib:recordschapter}{Records}章),端口(库的第\extref{lib:portsiosection}{Port I/O}小节),或哈希表(库的第\extref{lib:hashtablechapter}{Hash tables}章),且指向相同的存储位置(第\ref{storagemodel}小节)。(原文中有一个重复的“哈希表”,已被删除。)
\item \vari{Obj}和\varii{obj}都是记录类型(record-type)描述符,它们在库的第\extref{lib:recordsproceduralsection}{Procedural layer}小节被指定为是{\cf eqv?}等价的。
\end{itemize}
{\cf eqv?}过程在以下情况返回\schfalse{}:
\begin{itemize}
\item \vari{Obj}和\varii{obj}是不同的类型(第\ref{disjointness}小节)。
\item \vari{Obj}和\varii{obj}是布尔,但{\cf boolean=?}过程返回\schfalse{}。
\item \vari{Obj}和\varii{obj}是符号,但{\cf symbol=?}过程返回\schfalse{}。
\item \vari{Obj}和\varii{obj}一个是精确数字对象,另一个是非精确数字对象。
\item \vari{Obj}和\varii{obj}是有理数字对象,但{\cf =}过程返回\schfalse{}。
\item \vari{Obj}和\varii{obj}作为参数传递给任意其它可以通过Scheme标准算术过程定义的过程时产生不一样的结果(从{\cf eqv?}的意义上说),只要计算过程中不涉及非数。(本句已根据勘误表补全。)
\item \vari{Obj}和\varii{obj}是字符,但{\cf char=?}过程返回\schfalse{}。
\item \vari{Obj}和\varii{obj}一个是空表,但另一个不是。% <!-- TODO:和类型不同重复 -->
\item \vari{Obj}和\varii{obj}是对象,比如点对,向量,字节向量(库的第\extref{lib:bytevectorschapter}{Bytevectors}章),字符串,记录(库的第\extref{lib:recordschapter}{Records}章),端口(库的第\extref{lib:portsiosection}{Port I/O}小节),或哈希表(库的第\extref{lib:hashtablechapter}{Hashtables}章),但指向不同的位置。
\item \vari{Obj}和\varii{obj}是点对,向量,字符串,或记录,或哈希表,向其内部应用相同的访问器(也就是{\cf car}, {\cf cdr}, {\cf vector-ref}, {\cf string-ref}, 或记录访问器)但产生的值在{\cf eqv?}下返回\schfalse{}。
\item \vari{Obj}和\varii{obj}是过程,但对于某些参数有不同的行为(返回不同的值或有不同的副作用)。
\end{itemize}
\begin{note}
当\vari{obj}和\varii{obj}是数字对象时,{\cf eqv?}过程返回\schtrue{}并不意味着{\cf =}在相同的\vari{obj}和\varii{obj}参数下也返回\schtrue{}。
\end{note}
\begin{scheme}
(eqv? 'a 'a) \ev \schtrue
(eqv? 'a 'b) \ev \schfalse
(eqv? 2 2) \ev \schtrue
(eqv? '() '()) \ev \schtrue
(eqv? 100000000 100000000) \ev \schtrue
(eqv? (cons 1 2) (cons 1 2)) \ev \schfalse
(eqv? (lambda () 1)
(lambda () 2)) \ev \schfalse
(eqv? \#f 'nil) \ev \schfalse%
\end{scheme}
下面的例子展示了上面的规则没有完全定义的{\cf eqv?}的行为。对于这些情况,我们只能说{\cf eqv?}的返回值必须是一个布尔。
\begin{scheme}
(let ((p (lambda (x) x)))
(eqv? p p)) \ev \unspecified
(eqv? "" "") \ev \unspecified
(eqv? '\#() '\#()) \ev \unspecified
(eqv? (lambda (x) x)
(lambda (x) x)) \ev \unspecified
(eqv? (lambda (x) x)
(lambda (y) y)) \ev \unspecified
(eqv? +nan.0 +nan.0) \ev \unspecified%
\end{scheme}
下面的例子集合展示了对有本地状态的过程使用{\cf eqv?}的情况。对{\cf gen-counter}的每一次调用都必须付汇一个不同的过程,因为每个过程都有它自己内部的计数。{\cf gen-loser}的调用返回的过程被调用的时候行为是一样的。然而,{\cf eqv?}可以不检测这种相等。
\begin{scheme}
(define gen-counter
(lambda ()
(let ((n 0))
(lambda () (set! n (+ n 1)) n))))
(let ((g (gen-counter)))
(eqv? g g)) \ev \unspecified
(eqv? (gen-counter) (gen-counter))
\ev \schfalse
(define gen-loser
(lambda ()
(let ((n 0))
(lambda () (set! n (+ n 1)) 27))))
(let ((g (gen-loser)))
(eqv? g g)) \ev \unspecified
(eqv? (gen-loser) (gen-loser))
\ev \unspecified
(letrec ((f (lambda () (if (eqv? f g) 'both 'f)))
(g (lambda () (if (eqv? f g) 'both 'g))))
(eqv? f g)) \ev \unspecified
(letrec ((f (lambda () (if (eqv? f g) 'f 'both)))
(g (lambda () (if (eqv? f g) 'g 'both))))
(eqv? f g)) \ev \schfalse%
\end{scheme}
实现可以在适当的时候在常量间共享结构。(根据勘误表,此处省略一句话。)因此,作用在常量上的{\cf eqv?}的返回值有时是实现定义的。
\begin{scheme}
(eqv? '(a) '(a)) \ev \unspecified
(eqv? "a" "a") \ev \unspecified
(eqv? '(b) (cdr '(a b))) \ev \unspecified
(let ((x '(a)))
(eqv? x x)) \ev \schtrue%
\end{scheme}
\end{entry}
\begin{entry}{%
\proto{eq?}{ \vari{obj} \varii{obj}}{procedure}}
{\cf eq?}谓词和{\cf eqv?}类似,除了在一些情况其识别差别的能力比{\cf eqv?}更加精细之外。
{\cf eq?}和{\cf eqv?}确保在符号,布尔,空表,点对,过程,非空字符串,字节向量,和向量,以及记录的行为是一样的。{\cf eq?}在数字对象,字符上的行为是实现定义的,但是它总是或者返回\schtrue{}或者返回\schfalse{},且只有当{\cf eqv?}返回\schtrue{}时它才有可能返回\schtrue{}。{\cf eq?}谓词在空表,空向量,空字节向量和空字符串上的行为也可以是不一样的。
\begin{scheme}
(eq? 'a 'a) \ev \schtrue
(eq? '(a) '(a)) \ev \unspecified
(eq? (list 'a) (list 'a)) \ev \schfalse
(eq? "a" "a") \ev \unspecified
(eq? "" "") \ev \unspecified
(eq? '() '()) \ev \schtrue
(eq? 2 2) \ev \unspecified
(eq? \#\backwhack{}A \#\backwhack{}A) \ev \unspecified
(eq? car car) \ev \unspecified (本条已根据勘误表修改)
(let ((n (+ 2 3)))
(eq? n n)) \ev \unspecified
(let ((x '(a)))
(eq? x x)) \ev \schtrue
(let ((x '\#()))
(eq? x x)) \ev \unspecified
(let ((p (lambda (x) x)))
(eq? p p)) \ev \unspecified%
\end{scheme}
\todo{Needs to be explained better above. How can this be made to be
not confusing? A table maybe?}
\end{entry}
\begin{entry}{%
\proto{equal?}{ \vari{obj} \varii{obj}}{procedure}}
{\cf equal?}谓词返回\schtrue{}当且仅当它的参数(可能无限地)到正则树(regular trees)的展开作为有序树是一样的(ordered trees)。% <!-- TODO -->
{\cf equal?}谓词对待点对和向量作为有出边(outgoing edges)的节点,使用{\cf string=?}比较字符串,使用{\cf bytevector=?}比较字节向量(见库的第\extref{lib:bytevectorschapter}{Bytevectors}章),且使用{\cf eqv?}比较其它节点。
\begin{scheme}
(equal? 'a 'a) \ev \schtrue
(equal? '(a) '(a)) \ev \schtrue
(equal? '(a (b) c)
'(a (b) c)) \ev \schtrue
(equal? "abc" "abc") \ev \schtrue
(equal? 2 2) \ev \schtrue
(equal? (make-vector 5 'a)
(make-vector 5 'a)) \ev \schtrue
(equal? '\#vu8(1 2 3 4 5)
(u8-list->bytevector
'(1 2 3 4 5)) \ev \schtrue
(equal? (lambda (x) x)
(lambda (y) y)) \ev \unspecified
(let* ((x (list 'a))
(y (list 'a))
(z (list x y)))
(list (equal? z (list y x))
(equal? z (list x x)))) \lev (\schtrue{} \schtrue{})%
\end{scheme}
\begin{note}
{\cf equal?}必须总是可以终止的,哪怕它的参数存在循环。
\end{note}
\end{entry}
\section{过程谓词(Procedure predicate)}
\begin{entry}{%
\proto{procedure?}{ obj}{procedure}}
返回\schtrue{}如果\var{obj}是一个过程,否则返回\schfalse{}。
\begin{scheme}
(procedure? car) \ev \schtrue
(procedure? 'car) \ev \schfalse
(procedure? (lambda (x) (* x x)))
\ev \schtrue
(procedure? '(lambda (x) (* x x)))
\ev \schfalse%
\end{scheme}
\end{entry}
\section{算术(Arithmetic)}
\label{genericarithmeticsection}
这里描述的过程实现了在第\ref{numbertypeschapter}章描述的数值塔上通用的算术。本节描述的通用过程既接受精确数也接受非精确数对象作为其参数,并根据它们参数的数值子类型执行强制转换和选取适当的操作。
库的第\extref{lib:numberchapter}{Arithmetic}章描述了定义其它数值过程的库。
\subsection{精确性和非精确性的传播(Propagation)}
\label{propagationsection}
下面列出的过程在传递给它们的参数都是精确的时候必须返回数学上正确的精确结果:
\begin{scheme}
+ - *
max min abs
numerator denominator gcd
lcm floor ceiling
truncate round rationalize
real-part imag-part make-rectangular%
\end{scheme}
下面列出的过程当传递给它们的参数都是精确的且没有除数是零的时候必须返回正确的精确结果:
\begin{scheme}
/
div mod div-and-mod
div0 mod0 div0-and-mod0%
\end{scheme}
此外,过程{\cf expt}必须返回正确的精确结果,当传递给它的第一个参数是一个精确的实数对象且第二个参数是一个精确的整数对象。
通用的规则是,一般操作返回正确精确的结果,当所有传递给它们的参数都是精确的且结果是数学上明确定义的,但是当任何一个参数是非精确的时候返回一个非精确结果。这条规则的例外包括{\cf sqrt}, {\cf exp}, {\cf log}, {\cf sin}, {\cf cos}, {\cf tan}, {\cf asin}, {\cf acos}, {\cf atan}, {\cf expt}, {\cf make-polar}, {\cf magnitude}, 和{\cf angle},其甚至可以(但不要求)在传递精确参数的时候返回非精确的结果,如这些过程的规范所示。
上面规则的一个普遍的例外是,一个实现可以返回一个精确结果尽管其参数是非精确的,但这个精确的结果对于所有可能的对这个非精确参数的精确替代,都应该是正确的。一个例子是{\cf (* 1.0 0)},其可以返回{\cf 0}(精确地)或{\cf 0.0}(非精确的)。
\subsection{无穷大和非数的表示性}
\label{infinitiesnanssection}
数值操作的规范被书写就好像无穷大和非数是可以表示的,且指定许多操作,这些操作和数字对象相关,其在方法上和IEEE-754的二进制浮点算术标准相一致。Scheme的一个实现可以也可以不表示无穷大和非数;可是,一个实现必须抛出一个可继续的条件类型是{\cf\&no-infinities}或{\cf\&no-nans}(分别地见库的第\extref{lib:flonumssection}{Flonums}小节)的异常,在任何不能表示一个按规范说明的无穷大或非数的时候。在这种情况下,异常处理程序的继续是一个可以接受无穷大或非数的继续。这个要求也适用于数字对象和外部表示之间的转换,包括读取程序源代码。
\subsection{常用操作的语义(Semantics)}
一些操作是几个算术过程的语义基础。本节描述的这些操作的行为用作以后的参考。
\subsubsection{整数除法(Integer division)}
\label{integerdivision}
Scheme执行整数除法的操作依赖于数学操作$\mathrm{div}$, $\mathrm{mod}$, $\mathrm{div}_0$, 和$\mathrm{mod}_0$,它们定义如下:
$\mathrm{div}$, $\mathrm{mod}$, $\mathrm{div}_0$, 和$\mathrm{mod}_0$每个都接受两个实数$x_1$和$x_2$ 做为操作数,其中$x_2$ 必须是非零。
$\mathrm{div}$返回一个整数,$\mathrm{mod}$返回一个实数。它们的结果规定如下:
%
\begin{eqnarray*}
x_1~\mathrm{div}~x_2 &=& n_d\\
x_1~\mathrm{mod}~x_2 &=& x_m
\end{eqnarray*}
%
其中
%
\begin{displaymath}
\begin{array}{c}
x_1 = n_d \cdot x_2 + x_m\\
0 \leq x_m < |x_2|
\end{array}
\end{displaymath}
%
例子:
\begin{eqnarray*}
123~\mathrm{div}~10 &=& 12\\
123~\mathrm{mod}~10 &=& 3\\
123~\mathrm{div}~\textrm{$-10$} &=& -12\\
123~\mathrm{mod}~\textrm{$-10$} &=& 3\\
-123~\mathrm{div}~10 &=& -13\\
-123~\mathrm{mod}~10 &=& 7\\
-123~\mathrm{div}~\textrm{$-10$} &=& 13\\
-123~\mathrm{mod}~\textrm{$-10$} &=& 7
\end{eqnarray*}
%
$\mathrm{div}_0$和$\mathrm{mod}_0$与$\mathrm{div}$和$\mathrm{mod}$类似,除了$\mathrm{mod}_0$的结果在一个以零为中点的半开的区间中。它们的结果规定如下:
%
\begin{eqnarray*}
x_1~\mathrm{div}_0~x_2 &=& n_d\\
x_1~\mathrm{mod}_0~x_2 &=& x_m
\end{eqnarray*}
%
其中
%
\begin{displaymath}
\begin{array}{c}
x_1 = n_d \cdot x_2 + x_m\\
-|\frac{x_2}{2}| \leq x_m < |\frac{x_2}{2}|
\end{array}
\end{displaymath}
%
例子:
%
\begin{eqnarray*}
123~\mathrm{div}_0~10 &=& 12\\
123~\mathrm{mod}_0~10 &=& 3\\
123~\mathrm{div}_0~\textrm{$-10$} &=& -12\\
123~\mathrm{mod}_0~\textrm{$-10$} &=& 3\\
-123~\mathrm{div}_0~10 &=& -12\\
-123~\mathrm{mod}_0~10 &=& -3\\
-123~\mathrm{div}_0~\textrm{$-10$} &=& 12\\
-123~\mathrm{mod}_0~\textrm{$-10$} &=& -3
\end{eqnarray*}
\subsubsection{超越函数(Transcendental functions)}
\label{transcendentalfunctions}
In general, the transcendental functions $\log$, $\sin^{-1}$
(arcsine), $\cos^{-1}$ (arccosine), and $\tan^{-1}$ are multiply
defined. The value of $\log z$ is defined to be the one whose
imaginary part lies in the range from $-\pi$ (inclusive if $-0.0$ is
distinguished, exclusive otherwise) to $\pi$ (inclusive). $\log 0$ is
undefined.
The value of $\log z$ for non-real $z$ is defined in terms of log on real numbers as
\begin{displaymath}
\log z = \log |z| + (\mathrm{angle}~z)i
\end{displaymath}