forked from filonenko-mikhail/cltl2-doc
-
Notifications
You must be signed in to change notification settings - Fork 1
/
array.tex
1909 lines (1645 loc) · 93.8 KB
/
array.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
%Part{Array, Root = "CLM.MSS"}
%%%Chapter of Common Lisp Manual. Copyright 1984, 1988, 1989 Guy L. Steele Jr.
\clearpage\def\pagestatus{FINAL PROOF}
\ifx \rulang\Undef
\chapter{Arrays}
An array is an object with components arranged according
to a rectilinear coordinate system.
In principle, an
array in Common Lisp may have any number of dimensions, including zero.
(A zero-dimensional array has exactly one element.)
In practice, an implementation may limit the number of dimensions
supported, but
every Common Lisp implementation must support arrays of up to
seven dimensions.
Each dimension is a non-negative integer; if any dimension of an array is zero,
the array has no elements.
An array may be a \emph{general array}, meaning each element may be any Lisp
object, or it may be a \emph{specialized array}, meaning that each element
must be of a given restricted type.
\section{Array Creation}
Do not be daunted by the many options of the function \cdf{make-array}.
All that is required to construct an array is a list of
the dimensions; most of the options are for relatively esoteric
applications.
\begin{defun}[Function]
make-array dimensions &key :element-type :initial-element :initial-contents :adjustable :fill-pointer :displaced-to :displaced-index-offset
This is the primitive function for making arrays. The \emph{dimensions} argument
should be a list of non-negative integers
that are to be the dimensions of the array; the
length of the list will be the dimensionality of the array.
Each dimension must be smaller than \cdf{array-dimension-limit},
and the product of all the dimensions must be smaller than
\cdf{array-total-size-limit}.
Note that if \emph{dimensions} is {\nil}, then a zero-dimensional array is created.
For convenience when making a one-dimensional array, the single dimension
may be provided as an integer rather than as a list of one integer.
An implementation of Common Lisp may impose a limit on the rank of an array,
but this limit may not be smaller than 7. Therefore, any Common Lisp
program may assume the use of arrays of rank 7 or less.
The implementation-dependent limit on array rank is reflected in
\cdf{array-rank-limit}.
The keyword arguments for \cdf{make-array} are as follows:
\begin{flushdesc}
\item[\cd{:element-type}]
This argument
should be the name of the type of the elements of the array;
an array is constructed
of the most specialized type that can nevertheless accommodate
elements of the given type.
The type {\true} specifies a general array, one whose elements may
be any Lisp object; this is the default type.
\begin{new}
X3J13 voted in January 1989
\issue{ARRAY-TYPE-ELEMENT-TYPE-SEMANTICS}
to change \cdf{typep} and \cdf{subtypep}
so that the specialized \cdf{array} type specifier
means the same thing for discrimination purposes
as for declaration purposes: it encompasses those arrays
that can result by specifying \emph{element-type} as the element type
to the function \cdf{make-array}. Therefore we may say
that if \emph{type} is the \cd{:element-type} argument, then
the result will be an array of type \cd{(array \emph{type})};
put another way, for any type \emph{A},
\begin{lisp}
(typep (make-array ... :element-type '\emph{A} ...) \\*
~~~~~~~'(array \emph{A\/})))
\end{lisp}
is always true.
See \cdf{upgraded-array-element-type}.
\end{new}
\item[\cd{:initial-element}]
This argument
may be used to initialize each element of the array. The value
must be of the type specified by the \cd{:element-type} argument. If the
\cd{:initial-element} option is omitted, the initial values of the array
elements are undefined (unless the \cd{:initial-contents} or
\cd{:displaced-to} option is used).
The \cd{:initial-element} option may not be used with the
\cd{:initial-contents} or \cd{:displaced-to} option.
\item[\cd{:initial-contents}]
This argument may be used to initialize the
contents of the array. The value is a nested structure of sequences. If
the array is zero-dimensional, then the value specifies the single
element. Otherwise, the value must be a sequence whose length is equal
to the first dimension; each element must be a nested structure for an
array whose dimensions are the remaining dimensions, and so on.
For example:
\begin{lisp}
(make-array '(4 2 3) \\*
~~~~~~~~~~~~:initial-contents \\
~~~~~~~~~~~~'(((a b c) (1 2 3)) \\
~~~~~~~~~~~~~~((d e f) (3 1 2)) \\
~~~~~~~~~~~~~~((g h i) (2 3 1)) \\
~~~~~~~~~~~~~~((j k l) (0 0 0))))
\end{lisp}
The numbers of levels in the structure must equal the rank of the array.
Each leaf of the nested structure
must be of the type specified by the \cd{:type} option. If the
\cd{:initial-contents} option is omitted, the initial values of the array
elements are undefined (unless the \cd{:initial-element} or
\cd{:displaced-to} option is used).
The \cd{:initial-contents} option may not be used with the
\cd{:initial-element} or \cd{:displaced-to} option.
\item[\cd{:adjustable}]
This argument, if specified and not {\false}, indicates that it
must be possible to alter the array's size dynamically after it is
created. This argument defaults to {\nil}.
\begin{newer}
X3J13 voted in June 1989
\issue{ADJUST-ARRAY-NOT-ADJUSTABLE}
to clarify that if this argument is non-{\false}
then the predicate \cdf{adjustable-array-p} will necessarily be true when applied
to the resulting array; but if this argument is \cdf{nil} (or omitted) then the
resulting array may or may not be adjustable, depending on the implementation,
and therefore \cdf{adjustable-array-p} may be correspondingly true or false of
the resulting array. Common Lisp provides no portable way to create a
non-adjustable array, that is, an array for which \cdf{adjustable-array-p} is
guaranteed to be false.
\end{newer}
\item[\cd{:fill-pointer}]
This argument
specifies that the array should have a fill pointer.
If this option is specified and not {\false}, the array must be one-dimensional.
The value is used to initialize the fill pointer for the array.
If the value {\true} is specified, the length of the array is used;
otherwise the value must be an integer between 0 (inclusive)
and the length of the array (inclusive).
This argument defaults to {\nil}.
\item[\cd{:displaced-to}]
This argument, if specified and
not {\false}, specifies that the array will be a \emph{displaced} array.
The argument must then be an array;
\cdf{make-array} will create
an \emph{indirect} or \emph{shared} array that shares its contents with
the specified array. In this case the \cd{:displaced-index-offset}
option may be useful.
It is an error if the array given as the \cd{:displaced-to} argument
does not have the same \cd{:element-type} as the array being created.
The \cd{:displaced-to} option may not be used with the
\cd{:initial-element}
or \cd{:initial-contents} option.
This argument defaults to {\nil}.
\item[\cd{:displaced-index-offset}]
This argument may be used only in conjunction
with the \cd{:displaced-to} option.
It must be a non-negative integer (it defaults to zero); it is made to be the
index-offset of the created shared array.
When an array A is given as
the \cd{:displaced-to} argument to \cdf{make-array} when creating array B,
then array B is said to be \emph{displaced} to array A. Now the
total number of elements in an array, called the \emph{total size} of the array,
is calculated as the product of all the dimensions
(see \cdf{array-total-size}).
It is required that the total size of A be no smaller than the sum
of the total size of B plus the offset \emph{n} specified by
the \cd{:displaced-index-offset}
argument. The effect of displacing is that array B does not have any
elements of its own but instead maps accesses to itself into
accesses to array A. The mapping treats both arrays as if they
were one-dimensional by taking the elements in row-major order,
and then maps an access to element \emph{k} of array B to an access to element
\emph{k}+\emph{n} of array A.
\end{flushdesc}
If \cdf{make-array} is called with each of the \cd{:adjustable}, \cd{:fill-pointer},
and \cd{:displaced-to}
arguments either unspecified or {\nil}, then the
resulting array is guaranteed to be a \emph{simple} array
(see section~\ref{ARRAY-TYPE-SECTION}).
\begin{newer}
X3J13 voted in June 1989
\issue{ADJUST-ARRAY-NOT-ADJUSTABLE}
to clarify that if one or more of the \cd{:adjustable}, \cd{:fill-pointer},
and \cd{:displaced-to} arguments is true, then whether the resulting
array is simple is unspecified.
\end{newer}
Here are some examples of the use of \cdf{make-array}:
\begin{lisp}
;;; Create a one-dimensional array of five elements. \\*
(make-array 5) \\
\\
;;; Create a two-dimensional array, 3 by 4, with four-bit elements. \\*
(make-array '(3 4) \cd{:element-type} '(mod 16)) \\
\\
;;; Create an array of single-floats.\\*
(make-array 5 \cd{:element-type} 'single-float)) \\
\\
;;; Making a shared array. \\*
(setq a (make-array '(4 3))) \\
(setq b (make-array 8 :displaced-to a \\*
~~~~~~~~~~~~~~~~~~~~~~:displaced-index-offset 2)) \\
;;; Now it is the case that: \\*
~~~~~~~~(aref b 0) \EQ\ (aref a 0 2) \\*
~~~~~~~~(aref b 1) \EQ\ (aref a 1 0) \\*
~~~~~~~~(aref b 2) \EQ\ (aref a 1 1) \\*
~~~~~~~~(aref b 3) \EQ\ (aref a 1 2) \\*
~~~~~~~~(aref b 4) \EQ\ (aref a 2 0) \\*
~~~~~~~~(aref b 5) \EQ\ (aref a 2 1) \\*
~~~~~~~~(aref b 6) \EQ\ (aref a 2 2) \\*
~~~~~~~~(aref b 7) \EQ\ (aref a 3 0)
\end{lisp}
The last example depends on the fact that arrays are, in effect,
stored in row-major order for purposes of sharing. Put another way,
the indices for the elements of an array are ordered
lexicographically.
\end{defun}
\begin{defun}[Constant]
array-rank-limit
The value of \cdf{array-rank-limit} is a positive integer that is
the upper exclusive bound on the rank of an array.
This bound depends on the implementation
but will not be smaller than 8; therefore every Common Lisp implementation
supports arrays whose rank is between 0 and 7 (inclusive).
(Implementors are encouraged to make this limit as large as practicable
without sacrificing performance.)
\end{defun}
\begin{defun}[Constant]
array-dimension-limit
The value of \cdf{array-dimension-limit} is a positive integer that is
the upper exclusive bound on each individual dimension of an array.
This bound depends on the implementation
but will not be smaller than 1024.
(Implementors are encouraged to make this limit as large as practicable
without sacrificing performance.)
\begin{new}
X3J13 voted in January 1989
\issue{FIXNUM-NON-PORTABLE}
to specify that the value
of \cd{array-dimension-limit} must be of type \cdf{fixnum}.
This in turn implies that all valid array indices will be fixnums.
\end{new}
\end{defun}
\begin{defun}[Constant]
array-total-size-limit
The value of \cdf{array-total-size-limit} is a positive integer that is
the upper exclusive bound on the total number of elements in an array.
This bound depends on the implementation
but will not be smaller than 1024.
(Implementors are encouraged to make this limit as large as practicable
without sacrificing performance.)
The actual limit on array size imposed by the implementation may vary
according to the \cd{:element-type} of the array; in this case the value of
\cdf{array-total-size-limit} will be the smallest of these individual
limits.
\end{defun}
\begin{defun}[Function]
vector &rest objects
The function \cdf{vector} is a convenient means for creating
a simple general vector with specified initial contents.
It is analogous to the function \cdf{list}.
\begin{lisp}
(vector $\emph{a}_1$ $\emph{a}_2$ ... $\emph{a}_{n}$) \\
~~~\EQ\ (make-array (list $\emph{n}$) :element-type t \\
~~~~~~~~~~~~~:initial-contents (list $\emph{a}_1$ $\emph{a}_2$ ... $\emph{a}_{n}$))
\end{lisp}
\end{defun}
\section{Array Access}
The function \cdf{aref} is normally
used for accessing an element of an array.
Other access functions, such as \cdf{svref}, \cdf{char}, and \cdf{bit},
may be more efficient in specialized circumstances.
\begin{defun}[Function]
aref array &rest subscripts
This accesses and returns the element of \emph{array} specified
by the \emph{subscripts}. The number of subscripts must
equal the rank of the array, and each subscript must be
a non-negative integer less than the corresponding array dimension.
\cdf{aref} is unusual among the functions that operate on arrays
in that it completely ignores fill pointers. \cdf{aref} can access
without error any array element, whether active or not. The generic
sequence function \cdf{elt}, however, observes the fill pointer;
accessing an element beyond the fill pointer with \cdf{elt} is an error.
Note that this remark, predating the design of the Common Lisp Object System,
uses the term ``generic'' in a generic sense and not necessarily
in the technical sense used by CLOS
(see chapter~\ref{DTYPES}).
\cdf{setf} may be used with \cdf{aref} to destructively replace
an array element with a new value.
Under some circumstances it is desirable to write code that
will extract an element from an array \cdf{a} given a list \cdf{z} of the indices,
in such a way that the code works regardless of the rank of the
array. This is easy using \cdf{apply}:
\begin{lisp}
(apply \#'aref a z)
\end{lisp}
(The length of the list must of course equal the rank of
the array.) This construction may be used with \cdf{setf} to alter
the element so selected to some new value \cdf{w}:
\begin{lisp}
(setf (apply \#'aref a z) w)
\end{lisp}
\end{defun}
\begin{defun}[Function]
svref simple-vector index
The first argument must be a simple general vector,
that is, an object of type \cdf{simple-vector}.
The element of the \emph{simple-vector} specified by the integer \emph{index}
is returned.
The \emph{index} must be non-negative and less than
the length of the vector.
\cdf{setf} may be used with \cdf{svref} to destructively replace
a simple-vector element with a new value.
\cdf{svref} is identical to \cdf{aref} except that it requires its first
argument to be a simple vector. In some implementations of Common Lisp,
\cdf{svref} may be faster than \cdf{aref} in situations where it is applicable.
See also \cdf{schar} and \cdf{sbit}.
\end{defun}
\section{Array Information}
The following functions extract from an array
interesting information other than the elements.
\begin{defun}[Function]
array-element-type array
\cdf{array-element-type} returns a type specifier for the set of objects
that can be stored in the \emph{array}. This set may be larger than the
set requested when the array was created; for example,
the result of
\begin{lisp}
(array-element-type (make-array 5 :element-type '(mod 5)))
\end{lisp}
could be \cd{(mod 5)}, \cd{(mod 8)}, \cdf{fixnum}, \cdf{t}, or any other
type of which \cd{(mod 5)} is a subtype. See \cdf{subtypep}.
\end{defun}
\begin{defun}[Function]
array-rank array
This returns the number of dimensions (axes) of \emph{array}.
This will be a non-negative integer.
See \cdf{array-rank-limit}.
\end{defun}
\begin{defun}[Function]
array-dimension array axis-number
The length of dimension number \emph{axis-number} of the \emph{array} is returned.
\emph{array} may be any kind of array, and \emph{axis-number} should
be a non-negative integer less than the rank of \emph{array}.
If the \emph{array} is a vector with a fill pointer,
\cdf{array-dimension} returns the total size of the vector,
including inactive elements,
not the size indicated by the fill pointer.
(The function \cdf{length} will return the size indicated
by the fill pointer.)
\end{defun}
\begin{defun}[Function]
array-dimensions array
\cdf{array-dimensions} returns a list whose elements are the dimensions
of \emph{array}.
\end{defun}
\begin{defun}[Function]
array-total-size array
\cdf{array-total-size} returns the total number of elements in the \emph{array},
calculated as the product of all the dimensions.
\begin{lisp}
(array-total-size \emph{x}) \\
~~~\EQ\ (apply \#'* (array-dimensions \emph{x})) \\
~~~\EQ\ (reduce \#'* (array-dimensions \emph{x}))
\end{lisp}
Note that the total size of a zero-dimensional array is \cd{1}.
The total size of a one-dimensional array is calculated without regard
for any fill pointer.
\end{defun}
\begin{defun}[Function]
array-in-bounds-p array &rest subscripts
This predicate checks whether the \emph{subscripts} are all
legal subscripts for \emph{array}. The predicate is true if they
are all legal; otherwise it is false. The \emph{subscripts} must be integers.
The number of \emph{subscripts} supplied must equal the rank of the array.
Like \cdf{aref}, \cdf{array-in-bounds-p} ignores fill pointers.
\end{defun}
\begin{defun}[Function]
array-row-major-index array &rest subscripts
This function takes an array and valid subscripts for the array
and returns a single non-negative integer less than the total size
of the array that identifies the
accessed element in the row-major ordering of the elements.
The number of \emph{subscripts} supplied must equal the rank of the array.
Each subscript must be a non-negative integer less than the
corresponding array dimension.
Like \cdf{aref}, \cdf{array-row-major-index} ignores fill pointers.
A possible definition of \cdf{array-row-major-index}, with no error checking,
would be
\begin{lisp}
(defun array-row-major-index (a \cd{\&rest} subscripts) \\
~~(apply \#'+ (maplist \#'(lambda (x y) \\
~~~~~~~~~~~~~~~~~~~~~~~~~~(* (car x) (apply \#'* (cdr y)))) \\
~~~~~~~~~~~~~~~~~~~~~~subscripts \\
~~~~~~~~~~~~~~~~~~~~~~(array-dimensions a))))
\end{lisp}
For a one-dimensional array, the result of \cdf{array-row-major-index}
always equals the supplied subscript.
\end{defun}
\begin{defun}[Function]
row-major-aref array index
This allows any array element to be accessed as if the containing array
were one-dimensional. The \emph{index} must be a non-negative integer
less than the total size of the \emph{array}. It indexes into the array as
if its elements were arranged one-dimensionally in row-major order.
It may be understood in terms of \cdf{aref} as follows:
\begin{lisp}
(row-major-aref \emph{array} \emph{index}) \EQ \\*
~~(aref (make-array (array-total-size array)) \\*
~~~~~~~~~~~~~~~~~~~~:displaced-to array \\*
~~~~~~~~~~~~~~~~~~~~:element-type (array-element-type array)) \\*
~~~~~~~~index)
\end{lisp}
In other words, one may treat an array as one-dimensional by creating
a new one-dimensional array that is displaced to the old one and then
accessing the new array.
Alternatively, \cdf{aref} may be understood in terms of \cdf{row-major-aref}:
\begin{lisp}
(aref \emph{array} $\emph{i}_0$ $\emph{i}_1$ ... $\emph{i}_{n-1}$) \EQ \\*
~~(row-major-aref array \\*
~~~~~~~~~~~~~~~~~~(array-row-major-index array $\emph{i}_0$ $\emph{i}_1$ ... $\emph{i}_{n-1}$)
\end{lisp}
That is, a multidimensional array access is equivalent to a row-major access
using an equivalent row-major index.
Like \cdf{aref}, \cdf{row-major-aref} completely ignores fill pointers.
A call to \cdf{row-major-setf} is suitable for use as a \emph{place} for
\cdf{setf}.
This operation makes it easier to write code that efficiently processes
arrays of any rank. Suppose, for example, that one wishes to set every
element of an array \cdf{tennis-scores} to zero. One might write
\begin{lisp}
(fill (make-array (array-total-size tennis-scores) \\*
~~~~~~~~~~~~~~~~~~:element-type (array-element-type tennis-scores) \\*
~~~~~~~~~~~~~~~~~~:displaced-to tennis-scores) \\*
~~~~~~0)
\end{lisp}
Unfortunately, this incurs the overhead of creating a displaced array,
and \cdf{fill} cannot be applied to multidimensional arrays.
Another approach would be to handle each possible rank separately:
\begin{lisp}
(ecase (array-rank tennis-scores) \\*
~~(0 (setf (aref tennis-scores) 0)) \\
~~(1 (dotimes (i0 (array-dimension tennis-scores 0)) \\*
~~~~~~~(setf (aref tennis-scores i0) 0))) \\
~~(2 (dotimes (i0 (array-dimension tennis-scores 0)) \\*
~~~~~~~(dotimes (i1 (array-dimension tennis-scores 1)) \\*
~~~~~~~~~(setf (aref tennis-scores i0 i1) 0)))) \\*
~~... \\
~~(7 (dotimes (i0 (array-dimension tennis-scores 0)) \\*
~~~~~~~(dotimes (i1 (array-dimension tennis-scores 1)) \\
~~~~~~~~~(dotimes (i2 (array-dimension tennis-scores 1)) \\
~~~~~~~~~~~(dotimes (i3 (array-dimension tennis-scores 1)) \\
~~~~~~~~~~~~~(dotimes (i4 (array-dimension tennis-scores 1)) \\
~~~~~~~~~~~~~~~(dotimes (i5 (array-dimension tennis-scores 1)) \\
~~~~~~~~~~~~~~~~~(dotimes (i6 (array-dimension tennis-scores 1)) \\*
~~~~~~~~~~~~~~~~~~~(setf (aref tennis-scores i0 i1 i2 i3 i4 i5 i6) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~0))))))))) \\*
~~)
\end{lisp}
It is easy to get tired of writing such code. Furthermore, this approach
is undesirable because some implementations of Common Lisp
will in fact correctly support arrays of rank greater than 7 (though no
implementation is required to do so). A recursively nested loop does the job,
but it is still pretty hairy:
\begin{lisp}
(labels \\*
~~((grok-any-rank (\&rest indices) \\*
~~~~~(let ((d (- (array-rank tennis-scores) (length indices))) \\*
~~~~~~~(if (= d 0) \\*
~~~~~~~~~~~(setf (apply \#'row-major-aref indices) 0) \\*
~~~~~~~~~~~(dotimes (i (array-dimension tennis-scores (- d 1))) \\*
~~~~~~~~~~~~~(apply \#'grok-any-rank i indices)))))) \\*
~~(grok-any-rank))
\end{lisp}
Whether this code is particularly efficient depends on many implementation
parameters, such as how \cd{\&rest} arguments are handled and how
cleverly calls to \cdf{apply} are compiled.
How much easier it is to use \cdf{row-major-aref}!
\begin{lisp}
(dotimes (i (array-total-size tennis-scores)) \\*
~~(setf (row-major-aref tennis-scores i) 0))
\end{lisp}
Surely this code is sweeter than the honeycomb.
\end{defun}
\begin{defun}[Function]
adjustable-array-p array
This predicate is true if the argument (which must be an array)
is adjustable, and otherwise is false.
\begin{newer}
X3J13 voted in June 1989
\issue{ADJUST-ARRAY-NOT-ADJUSTABLE}
to clarify that \cdf{adjustable-array-p} is true of an array
if and only if \cdf{adjust-array}, when applied to that array,
will return the same array, that is, an array \cdf{eq} to the original array.
If the \cd{:adjustable} argument
to \cdf{make-array} is non-\cdf{nil} when an array is created,
then \cdf{adjustable-array-p} must be true of that array.
If an array is created with the \cd{:adjustable} argument \cdf{nil}
(or omitted), then \cdf{adjustable-array-p} may be true or false of that
array, depending on the implementation.
X3J13 further voted to \emph{define}
the terminology ``adjustable array'' to mean precisely ``an array of
which \cdf{adjustable-array-p} is true.''
See \cdf{make-array} and \cdf{adjust-array}.
\end{newer}
\end{defun}
\begin{defun}[Function]
array-displacement array
This returns two values. The first value is the array displaced to and the
second is the displacement. If array is not a displaced array then
array-displacement returns the values nil and 0.
\end{defun}
\section{Functions on Arrays of Bits}
The functions described in this section operate only
on arrays of bits, that is, specialized arrays whose elements
are all \cd{0} or \cd{1}.
\begin{defun}[Function]
bit bit-array &rest subscripts \\
sbit simple-bit-array &rest subscripts
\cdf{bit} is exactly like \cdf{aref} but requires an array of bits,
that is, one of type \cd{(array bit)}.
The result will always be \cd{0} or \cd{1}.
\cdf{sbit} is like \cdf{bit} but additionally requires that the first
argument be a \emph{simple} array (see section~\ref{ARRAY-TYPE-SECTION}).
Note that \cdf{bit} and \cdf{sbit}, unlike \cdf{char} and \cdf{schar},
allow the first argument to be an array of any rank.
\cdf{setf} may be used with \cdf{bit} or \cdf{sbit} to destructively replace
a bit-array element with a new value.
\cdf{bit} and \cdf{sbit} are identical to \cdf{aref} except for the
more specific type requirements on the first argument.
In some implementations of Common Lisp,
\cdf{bit} may be faster than \cdf{aref} in situations where it is applicable,
and \cdf{sbit} may similarly be faster than \cdf{bit}.
\end{defun}
\begin{defun}[Function]
bit-and bit-array1 bit-array2 &optional result-bit-array \\
bit-ior bit-array1 bit-array2 &optional result-bit-array \\
bit-xor bit-array1 bit-array2 &optional result-bit-array \\
bit-eqv bit-array1 bit-array2 &optional result-bit-array \\
bit-nand bit-array1 bit-array2 &optional result-bit-array \\
bit-nor bit-array1 bit-array2 &optional result-bit-array \\
bit-andc1 bit-array1 bit-array2 &optional result-bit-array \\
bit-andc2 bit-array1 bit-array2 &optional result-bit-array \\
bit-orc1 bit-array1 bit-array2 &optional result-bit-array \\
bit-orc2 bit-array1 bit-array2 &optional result-bit-array
These functions perform bit-wise logical operations on bit-arrays.
All of the arguments to any of these functions must be bit-arrays
of the same rank and dimensions.
The result is a bit-array of matching rank and dimensions,
such that any given bit of the result
is produced by operating on corresponding bits from each of the arguments.
If the third argument is {\false} or omitted, a new array is created
to contain the result. If the third argument is a bit-array,
the result is destructively placed into that array. If the third
argument is {\true}, then the first argument is also used as the third
argument; that is, the result is placed back in the first array.
The following table indicates what the result bit is for each operation
as a function of the two corresponding argument bits.
\begin{flushleft}
\cf
\begin{tabular*}{\textwidth}{@{}l@{\extracolsep{\fill}}lllll@{}}
~~~\emph{argument1}~~&0&0&1&1 \\
~~~\emph{argument2}~~&0&1&0&1&\emph{Operation name} \\
\hlinesp
bit-and&0&0&0&1&\textrm{and} \\
bit-ior&0&1&1&1&\textrm{inclusive or} \\
bit-xor&0&1&1&0&\textrm{exclusive or} \\
bit-eqv&1&0&0&1&\textrm{equivalence (exclusive nor)} \\
bit-nand&1&1&1&0&\textrm{not-and} \\
bit-nor&1&0&0&0&\textrm{not-or} \\
bit-andc1&0&1&0&0&\textrm{and complement of \emph{argument1} with \emph{argument2}} \\
bit-andc2&0&0&1&0&\textrm{and \emph{argument1} with complement of \emph{argument2}} \\
bit-orc1&1&1&0&1&\textrm{or complement of \emph{argument1} with \emph{argument2}} \\
bit-orc2&1&0&1&1&\textrm{or \emph{argument1} with complement of \emph{argument2}} \\
\hline
\end{tabular*}
\end{flushleft}
For example:
\begin{lisp}
(bit-and \#*1100 \#*1010) \EV\ \#*1000 \\
(bit-xor \#*1100 \#*1010) \EV\ \#*0110 \\
(bit-andc1 \#*1100 \#*1010) \EV\ \#*0100
\end{lisp}
See \cdf{logand} and related functions.
\end{defun}
\begin{defun}[Function]
bit-not bit-array &optional result-bit-array
The first argument must be an array of bits. A bit-array
of matching rank and dimensions is returned that contains
a copy of the argument
with all the bits inverted.
See \cdf{lognot}.
If the second argument is {\false} or omitted, a new array is created
to contain the result. If the second argument is a bit-array,
the result is destructively placed into that array. If the second
argument is {\true}, then the first argument is also used as the second
argument; that is, the result is placed back in the first array.
\end{defun}
\section{Fill Pointers}
\label{FILL-POINTER}
Several functions for manipulating a \emph{fill pointer} are provided
in Common Lisp
to make it easy to incrementally fill in the contents of a vector
and, more generally, to allow efficient varying of the length of a vector.
For example, a string with a fill pointer has most of the characteristics
of a PL/I varying string.
The fill pointer is a non-negative integer no larger than the total
number of elements in the vector (as returned by \cdf{array-dimension});
it is the number of ``active'' or ``filled-in'' elements in the vector.
The fill pointer constitutes the ``active length'' of the vector;
all vector elements whose index is less than the fill pointer are
active, and the others are inactive.
Nearly all functions that operate on the contents of a vector
will operate only on the active elements. An important exception
is \cdf{aref}, which can be used to access any vector element
whether in the active region of the vector or not. It is important
to note that vector elements not in the active region are still considered
part of the vector.
\beforenoterule
\begin{implementation}
An implication of this rule is that
vector elements outside the active region may not be garbage-collected.
\end{implementation}
\afternoterule
Only vectors (one-dimensional arrays) may have fill pointers;
multidimensional arrays may not. (Note, however, that one can create
a multidimensional array that is \emph{displaced} to a vector that has
a fill pointer.)
\begin{defun}[Function]
array-has-fill-pointer-p array
The argument must be an array. \cdf{array-has-fill-pointer-p} returns
{\true} if the array has a fill pointer, and otherwise returns {\false}.
Note that
\cdf{array-has-fill-pointer-p}
always returns {\false} if
the \emph{array} is not one-dimensional.
\end{defun}
\begin{defun}[Function]
fill-pointer vector
The fill pointer of \emph{vector} is returned. It is an error if
the \emph{vector} does not have a fill pointer.
\cdf{setf} may be used with \cdf{fill-pointer} to change the fill pointer
of a vector. The fill pointer of a vector must always be an integer
between zero and the size of the vector (inclusive).
\end{defun}
\begin{defun}[Function]
vector-push new-element vector
\emph{vector} must be a one-dimensional array that has a fill pointer,
and \emph{new-element} may be any object. \cdf{vector-push} attempts to store
\emph{new-element} in the element of the vector designated by the fill
pointer, and to increase the fill pointer by 1. If the fill pointer does
not designate an element of the vector (specifically, when it gets too
big), it is unaffected and
\cdf{vector-push} returns {\false}. Otherwise, the store and increment take
place and \cdf{vector-push} returns the \emph{former} value of the fill pointer
(1 less than the one it leaves in the vector); thus the value of
\cdf{vector-push} is the index of the new element pushed.
It is instructive to compare \cdf{vector-push}, which is a function,
with \cdf{push}, which is a macro that requires a \emph{place} suitable
for \cdf{setf}. A vector with a fill pointer effectively contains
the place to be modified in its \cdf{fill-pointer} slot.
\end{defun}
\begin{defun}[Function]
vector-push-extend new-element vector &optional extension
\cdf{vector-push-extend} is just like \cdf{vector-push} except
that if the fill pointer gets too large, the vector is extended (using
\cdf{adjust-array}) so that it can contain more elements.
If, however, the vector is not adjustable, then \cdf{vector-push-extend}
signals an error.
\begin{newer}
X3J13 voted in June 1989
\issue{ADJUST-ARRAY-NOT-ADJUSTABLE}
to clarify that \cdf{vector-push-extend} regards an array as
not adjustable if and only if \cdf{adjustable-array-p} is false
of that array.
\end{newer}
The optional argument \emph{extension}, which must be a positive
integer, is the minimum number of elements to be added to the vector if it
must be extended; it defaults to a ``reasonable'' implementation-dependent
value.
\end{defun}
\begin{defun}[Function]
vector-pop vector
\emph{vector} must be a one-dimensional array that has a fill pointer.
If the fill pointer is zero, \cdf{vector-pop} signals an error.
Otherwise the fill pointer is decreased by 1, and the vector element
designated by the new value of the fill pointer is returned.
\end{defun}
\section{Changing the Dimensions of an Array}
This function may be used to resize or reshape an array.
Its options are similar to those of \cdf{make-array}.
\begin{defun}[Function]
adjust-array array new-dimensions &key :element-type :initial-element :initial-contents :fill-pointer :displaced-to :displaced-index-offset
\cdf{adjust-array} takes an array and a number of other arguments
as for \cdf{make-array}. The number of dimensions
specified by \emph{new-dimensions} must equal the rank of \emph{array}.
\cdf{adjust-array} returns an array of the same type and rank as \emph{array},
with the specified \emph{new-dimensions}. In effect, the \emph{array} argument
itself is modified to conform to the new specifications, but this may
be achieved either by modifying the \emph{array} or by creating a new
array and modifying the \emph{array} argument to be \emph{displaced} to the
new array.
In the simplest case, one specifies only the \emph{new-dimensions}
and possibly an \cd{:initial-element} argument.
Those elements of \emph{array} that
are still in bounds appear in the new array. The elements of
the new array that are not in the bounds of \emph{array} are initialized
to the \cd{:initial-element}; if this argument is not provided,
then the initial contents of any new elements are undefined.
If \cd{:element-type} is specified, then \emph{array} must be such that it could have
been originally created with that type; otherwise an error is signaled.
Specifying \cd{:element-type} to \cdf{adjust-array} serves only to require such an
error check.
If \cd{:initial-contents} or \cd{:displaced-to}
is specified, then it is treated as for
\cdf{make-array}. In this case none of the original contents of
\emph{array} appears in the new array.
If \cd{:fill-pointer} is specified, the fill pointer of the \emph{array}
is reset as specified. An error is signaled if \emph{array} had no
fill pointer already.
\begin{new}
X3J13 voted in June 1988
\issue{ADJUST-ARRAY-FILL-POINTER}
to clarify the treatment of the \cd{:fill-pointer}
argument as follows.
If the \cd{:fill-pointer} argument is not supplied, then the fill pointer
of the \emph{array} is left alone. It is an error
to try to adjust the \emph{array} to a total size that is smaller
than its fill pointer.
If the \cd{:fill-pointer} argument is supplied, then its value
must be either an integer, \true, or \false. If it is an integer,
then it is the new value for the fill pointer;
it must be non-negative and no greater than the new size to which the
\emph{array} is being adjusted.
If it is \true, then the fill pointer is set equal to the new size
for the \emph{array}. If it is \false, then the fill pointer is
left alone; it is as if the argument had not been supplied.
Again, it is an error
to try to adjust the \emph{array} to a total size that is smaller
than its fill pointer.
An error is signaled if a non-{\false} \cd{:fill-pointer} value
is supplied and the \emph{array} to be adjusted does not already
have a fill pointer.
This extended treatment of the \cd{:fill-pointer}
argument to \cdf{adjust-array} is consistent with the previously
existing treatment of the \cd{:fill-pointer} argument to \cdf{make-array}.
\end{new}
\cdf{adjust-array} may, depending on the implementation and the arguments,
simply alter the given array or create and return a new one.
In the latter case the given array will be altered so as to be displaced
to the new array and have the given new dimensions.
\begin{newer}
X3J13 voted in January 1989
\issue{ADJUST-ARRAY-NOT-ADJUSTABLE}
to allow \cdf{adjust-array} to be applied to any array.
If \cdf{adjust-array} is applied to an array that was
originally created with \cd{:adjustable} true,
the array returned is \cdf{eq} to its first argument. It is not specified
whether \cdf{adjust-array} returns an array \cdf{eq} to its first argument for any
other arrays. If the array returned by \cdf{adjust-array} is not \cdf{eq} to its
first argument, the original array is unchanged and does not share
storage with the new array.
Under this new definition, it is wise to treat \cdf{adjust-array}
in the same manner as \cdf{delete} and \cdf{nconc}: one should carefully
retain the returned value, for example by writing
\begin{lisp}
(setq my-array (adjust-array my-array ...))
\end{lisp}
rather than relying solely on a side effect.
\end{newer}
If \cdf{adjust-array} is applied to an \emph{array} that is displaced
to another array \emph{x}, then afterwards neither \emph{array} nor the returned
result is displaced to \emph{x} unless such displacement is explicitly
re-specified in the call to \cdf{adjust-array}.
For example, suppose that the 4-by-4 array \cdf{m} looks like this:
\begin{lisp}
\#2A(~(~alpha~~~~~beta~~~~~~gamma~~~~~delta~) \\
~~~~~(~epsilon~~~zeta~~~~~~eta~~~~~~~theta~) \\
~~~~~(~iota~~~~~~kappa~~~~~lambda~~~~mu~~~~) \\
~~~~~(~nu~~~~~~~~xi~~~~~~~~omicron~~~pi~~~~)~)
\end{lisp}
Then the result of
\begin{lisp}
(adjust-array m '(3 5) :initial-element 'baz)
\end{lisp}
is a 3-by-5 array with contents
\begin{lisp}
\#2A(~(~alpha~~~~~beta~~~~~~gamma~~~~~delta~~~~~baz~) \\
~~~~~(~epsilon~~~zeta~~~~~~eta~~~~~~~theta~~~~~baz~) \\
~~~~~(~iota~~~~~~kappa~~~~~lambda~~~~mu~~~~~~~~baz~)~)
\end{lisp}
Note that if array \cdf{a} is created displaced to array \cdf{b} and subsequently
array \cdf{b} is given to \cdf{adjust-array}, array \cdf{a} will still be
displaced to array \cdf{b}; the effects of this displacement and
the rule of row-major storage order must be taken into account.
\begin{newer}
X3J13 voted in June 1988 \issue{ADJUST-ARRAY-DISPLACEMENT}
to clarify the interaction of \cdf{adjust-array} with array displacement.
Suppose that an array \emph{A} is to be adjusted. There are four cases
according to whether or not \emph{A} was displaced before adjustment
and whether or not the result is displaced after adjustment.
\begin{itemize}
\item
Suppose \emph{A} is not displaced either before or after.
The dimensions of \emph{A} are altered, and
the contents are rearranged as appropriate. Additional elements of \emph{A}
are taken from the \cd{:initial-element} argument.
However, the use of the \cd{:initial-contents} argument causes all old
contents to be discarded.
\item
Suppose \emph{A} is not displaced before, but is displaced to array \emph{C} after.
None of the original contents of \emph{A} appears in \emph{A} afterwards; \emph{A}
now contains (some of) the contents of \emph{C}, without any rearrangement of
\emph{C}.
\item
Suppose \emph{A} is displaced to {array \emph{B}} before the call,
and is displaced to array \emph{C} after the call.
(Note that \emph{B} and \emph{C} may be the same array.)
The contents of \emph{B} do not appear in
\emph{A} afterwards (unless such contents also happen to be in \emph{C},
as when \emph{B} and \emph{C} are the same, for example). If
\cd{:displaced-index-offset} is not specified in the call to
\cdf{adjust-array}, it defaults
to zero; the old offset (into \emph{B}) is not retained.
\item
Suppose \emph{A} is displaced to array \emph{B} before the call,
but is not displaced afterwards. In this case \emph{A} gets
a new ``data region'' and (some of) the
contents of \emph{B} are copied into it as appropriate to
maintain the existing old contents. Additional elements of \emph{A}
are taken from the \cd{:initial-element} argument.
However, the use of the \cd{:initial-contents} argument causes all old
contents to be discarded.
\end{itemize}
If array \emph{X} is displaced to array \emph{Y}, and array \emph{Y} is displaced
to array \emph{Z}, and array \emph{Y} is altered by \cdf{adjust-array}, array
\emph{X} must now refer to the adjusted contents of \emph{Y}. This means that an
implementation may not collapse the chain to make \emph{X} refer to \emph{Z}
directly and forget that the chain of reference passes through array \emph{Y}.
(Caching techniques are of course permitted, as long as they preserve the
semantics specified here.)
If \emph{X} is displaced to \emph{Y}, it is an error to adjust \emph{Y} in such a
way that it no longer has enough elements to satisfy \emph{X}. This error may be
signaled at the time of the adjustment, but this is not required.
Note that omitting the \cd{:displaced-to} argument to \cdf{adjust-array} is
equivalent to specifying \cd{:displaced-to~nil}; in either case, the array is
not displaced after the call regardless of whether it was displaced before
the call.
\end{newer}
\end{defun}
%RUSSIAN
\else
\chapter{Массивы}
Массив является объектом с элементами, расположенными в соответствие с
прямолинейной координатной системой. В целом, это можно назвать построчным
хранением объектов многомерных таблиц.
В теории, массив в Common Lisp'е может иметь любое количество измерений, включая
ноль.
(Нульмерный массив измерений имеет только один элемент. FIXME)
На практике, реализация может ограничивать количество измерений,
но должна как минимум поддерживать семь.
Каждое измерение является неотрицательным целым. Если любое из измерений равно
нулю, то массив не имеет элементов.
Массив может быть \emph{общим}. Это означает, что элемент может быть
любым Lisp объектом. Массив также может быть \emph{специализированным}. Это
означает, что элемент ограничен некоторым типом.
\section{Создание массива}
Не волнуйтесь о большом количестве опций для функции \cdf{make-array}.
Все что действительно необходимо, это список размерностей. Остальные же опции
служат для относительно эзотерических программ.
\begin{defun}[Функция]
make-array dimensions &key :element-type :initial-element :initial-contents :adjustable :fill-pointer :displaced-to :displaced-index-offset