This is a specification of a reader form (literals) for multi-dimensional arrays. It is an extension of the Common Lisp array reader syntax to handle non-zero lower bounds, optional explicit bounds, and optional uniform element types (compatible with SRFI-4). It can be used in conjunction with SRFI-25 or SRFI-122. These extensions were implemented in Guile (except the handling of rank-0 arrays), and later in Kawa.
Should the rank be optional if the bounds are specified? It is in SRFI-58.
Should format-array
be here?
The output of format-array
starts out
with "╔"
(box drawing double up and right) if there
is space, and otherwise it starts with "#"
. The former is
prettier, but the latter makes it easier to actually parse the output.
It might be nice (as a future or implementation extension) to
be able to use the pretty box representation in a program, or otherwise
execute it, and that is easier if the initial character is "#"
.
It is desirable to have a read and write syntax for multi-dimensional arrays. Basing it on the Common Lisp syntax makes sense, and is what has been done by all known existing implementations. However, Common Lisp arrays do not support non-zero lower bounds, and its handling of specialized (uniform) arrays is very different from known Scheme implementations. Various Scheme extensions have been proposed. SRFI-58 is one proposal, but it does not handle non-zero lower bounds, and it's type-specifier syntax is verbose and stylistically incompatible with the literals proposed for uniform verctors in SRFI-4.
This specification is basically that of Guile. However, Guile requires the single element of rank-0 arrays to be enclosed in parenthesis. While this may slightly enhance readability, it is somewhat inconsistent in that otherwise the nesting of parenthesis (of atom-valued arrays) is equal to the rank. It is also inconsistent with Common Lisp and SRFI-58. So this specification (and the Kawa implementation) diverge from Guile in this respect.
An array literal starts with #
followed by its rank,
followed by a tag that describes the underlying vector (by default a
),
optionally followed by information about its shape,
and finally followed by the cells, organized into dimensions using parentheses.
For example, #2a((11 12 13) (21 22 23))
is a rank-2 array (a matrix)
whose upper index bounds (shape) is #(2 3)
.
It could be pretty-printed (using the non-normative format-array
helper function below):
╔#2a:2:3═╗ ║11│12│13║ ╟──┼──┼──╢ ║21│22│23║ ╚══╧══╧══╝
array-literal
::=
array-literal-header
datum
array-literal-header
::=
#
rank
vectag
array-bound
*
array-bound
::=
[@
lower
]:
length
| @
lower
vectag
::=
a
| uniform-tag
The vectag
specifies the type of the elements of the array.
These are the same tags as SRFI-4. For example #2u32((10 11) (20 21))
is a 2x2 array of 32-bit unsigned integers.
Following the vectag
you can optionally include information
about the shape: For each dimension you can optionally specify
the lower bounds (after the character @
),
followed by the length of the dimension (after the character ":"
).
The shape information is required if a lower bound is non-zero,
or any length is zero.
If any array-bound is specified,
there must be exactly rank of them.
The datum
contains the elements in a nested-list format:
a rank-1 array (i.e. vector) uses a single list,
a rank-2 array uses a list-of-lists, and so on.
The elements are in lexicographic order.
A uniform u32 array of rank 2 with index ranges 2..3 and 3..4:
#2u32@2@3((1 2) (2 3))
Rank 0 arrays:
#0a sym #0f32 237.0
Empty arrays:
#2a:0:2() #2a:2:0(() ()) #3a:2:0:3(() ()) #3a:2:3:0((() () ()) (() () ()))
When an array is printed with the write
function,
the result should be an array-literal.
(This is not possible in a pure library-based implementation,
unless write
is changed.)
However, rank-1 arrays with zero lower bound may be
printed as vectors. They should be printed as vectors
it the implementation treats vector (and possibly uniform vector)
as a subtype of array (i.e. all vectors are arrays), though
an exception may be made for a specified subset of non-simple
vectors
(such as shared vectors).
Printing with display
may format the array in the same way as write
(except using display
for each element),
or in some more readable way, perhaps by
using the format-array
procedure.
Procedure: format-array
value
[element-format
]
Produce a nice “pretty” display for
value
, which is usually an array. It uses Unicode "box drawing" characters.The top line includes an
array-literal-header
. The lower bound are only printed if non-zero. The dimension lengths are printed if there is room, or if one of them is zero.#2a@1:2@1:3((#2a((1 2) (3 4)) 9 #2a((3 4) (5 6))) (#(42 43) #2a((8 7 6)) #2a((90 91) (100 101))))
⇨ ╔#2a@1:2@1:3════╤═════════╗ ║#2a═╗ │ 9│#2a═╗ ║ ║║1│2║ │ │║3│4║ ║ ║╟─┼─╢ │ │╟─┼─╢ ║ ║║3│4║ │ │║5│6║ ║ ║╚═╧═╝ │ │╚═╧═╝ ║ ╟───────┼───────┼─────────╢ ║╔#1a:2╗│#2a:1:3│╔#2a:2:2╗║ ║║42│43║│║8│7│6║│║ 90│ 91║║ ║╚══╧══╝│╚═╧═╧═╝│╟───┼───╢║ ║ │ │║100│101║║ ║ │ │╚═══╧═══╝║ ╚═══════╧═══════╧═════════╝If
element-format
is specified, it is a format string used for format each non-array:(format-array arr "~4,2f")
⇨ ╔#2a@1:2@1:3══╤════════════════╤═══════════════╗ ║╔#2a:2:2══╗ │ 9.00│╔#2a:2:2══╗ ║ ║║1.00│2.00║ │ │║3.00│4.00║ ║ ║╟────┼────╢ │ │╟────┼────╢ ║ ║║3.00│4.00║ │ │║5.00│6.00║ ║ ║╚════╧════╝ │ │╚════╧════╝ ║ ╟─────────────┼────────────────┼───────────────╢ ║╔#1a:2╤═════╗│╔#2a:1:3══╤════╗│╔#2a:2:2══════╗║ ║║42.00│43.00║│║8.00│7.00│6.00║│║ 90.00│ 91.00║║ ║╚═════╧═════╝│╚════╧════╧════╝│╟──────┼──────╢║ ║ │ │║100.00│101.00║║ ║ │ │╚══════╧══════╝║ ╚═════════════╧════════════════╧═══════════════╝If the rank is more than 2, then each “layer” is printed separated by double lines.
#3a(((1 2 3 4) (5 6 7 8)) ((9 10 11 12) (13 14 15 16)) ((17 18 19 20) (21 22 23 24)))
⇨ ╔#3a:3:2:4══╗ ║ 1│ 2│ 3│ 4║ ╟──┼──┼──┼──╢ ║ 5│ 6│ 7│ 8║ ╠══╪══╪══╪══╣ ║ 9│10│11│12║ ╟──┼──┼──┼──╢ ║13│14│15│16║ ╠══╪══╪══╪══╣ ║17│18│19│20║ ╟──┼──┼──┼──╢ ║21│22│23│24║ ╚══╧══╧══╧══╝
This syntax is implemented in Guile (except for the handling of rank-0 arrays), and Kawa.
Kawa provides format-array
(though it is
implemented in Java): The format-array
is a Scheme
wrapper around the print
method of the gnu.kawa.functions.ArrayPrint
class.
Copyright (C) Per Bothner 2018
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.