This page is part of the web mail archives of SRFI 58 from before July 7th, 2015. The new archives for SRFI 58 contain all messages, not just those from before July 7th, 2015.
Brief summary: More praise, a few minor suggestions, and one major issue. Bradd wrote: >> Would you mind terribly making the A optional in the second syntax? >> >> array-prefix :: rank `A' [ dimensions ] [ `:' type-specifier ] >> | [`A'] dimensions [ `:' type-specifier ] >> >> I realize that it complicates parsing a bit .... Aubrey Jaffer wrote: > It took several hours to code, but it seems to work. Great! I thought of two more items for the syntax examples. 1. They should include examples of how to write arrays with empty dimensions. (I hope I got all these right.) #A0*2() #A2*0(() ()). #A2*0*3(() ()). #A2*3*0((() () ()) (() () ())). 2. It should be an error to write any array with inconsistent or ambiguous rank or dimension specifiers. #3A() array shape is ambiguous #2A((1 2) (1)) column widths are inconsistent #3A1*1((1)) rank is inconsistent with dimension specifier >> ... but it also unifies the dimension syntax with the #n(...) vector >> syntax of Common Lisp and PLT Scheme. > Can you describe the PLT compatibility? PLT Scheme implements the Common Lisp #n(...) syntax with two extensions. In Common Lisp, #n(v.1 v.2 ... v.k) creates a vector of size N, with the final value, v.k, repeated (N - K) times. It's an error if (K > N) or if (K = 0 and N > 0). Examples: #5(1 2) ==> #(1 2 2 2 2) #2(1 2) ==> #(1 2) #0() ==> #() #1(1 2) ==> error: too many values #5() ==> error: no values for non-empty array PLT Scheme adds two extensions: If (K = 0), the vector is filled with 0, and if (K > N) the reader raises a specific exception. If "it is an error" means the same thing in Common Lisp as it does in Scheme, these are pure extensions of the CL feature. With the "A" optional, the array literal syntax is consistent with CL/PLT: #3(1 2 3) == #A3(1 2 3) == #1A3(1 2 3) == #1A(1 2 3). >> Don't forget to give semantics and examples for the shaped-array >> syntax. I don't particularly care whether you define the repeat-fill >> rule; feel free to leave it for a later SRFI if you don't want to >> write it up. > Do whole rows, planes, etc also repeat? I would expect it. First, repeat the last object in each column as many times as necessary to fill it. Then repeat the last column in each row, the last row in each super-row, and so on, until the array is complete. For example, consider this 4*4 matrix: | 1 2 3 3 | | 2 2 3 3 | | 3 3 3 3 | | 3 3 3 3 | You could write this as: #4*4((1 2 3) (2 2 3) (3)) The reader would first complete each column: #4*4((1 2 3 3) (2 2 3 3) (3 3 3 3)) Then each row: #4*4((1 2 3 3) (2 2 3 3) (3 3 3 3) (3 3 3 3)) Obviously, this works best (typing-wise) for arrays that only vary near the origin. While it would be nice to have a more general shorthand -- especially something that could handle identity matrices -- that's a better subject for a later SRFI. (Here's an idea in case somebody does want to implement an extension like that. In the list decomposition, an exact integer M indicates that the following row should be repeated M times, and an ellipsis indicates that the preceding row or column should be repeated as many times as necessary to complete the dimension. For example, #100x100(2(1 ...) (1 1 0 ... 1 1) ... 2(1 ...)) describes a 100x100 matrix with a border of two 1s surround a zero center. I don't recommend it for this SRFI; it's too big of an enhancement. I don't even mind if you also punt on the basic CL/PLT tail-filling feature. Only do this if you're sure it's a good idea and you really want to implement it.) >> Anybody feel strongly about "*" vs "x" for the bound separator? > I don't like x because it looks like mistyped hex numbers (#x33) OK, that's good enough for me. >> That covers all of the basic types. Only binaryx [x86] is missing .... > I think you will find that vectorized instructions don't pack > non-power-of-2 bit widths. Breaking operands over cache-line > boundaries is a huge hassle for hardware. > > So the 80-bit and 96-bit are likely stored into 128 bits. We might as > well call them 128b. Ah, OK. That's good enough for now, since I know of no implementations with both x86 and quad flonums. I suppose it could happen in the future, if Intel keeps binaryx and adds binary128, but that's probably 5 to 10 years off, if it happens at all. If it ever becomes a problem, it wouldn't be hard to add flox96b specifiers. > This text I added describes how sizes are chosen: > > Implementations are required to accept all of the type denotations. > Uniform types of matching sizes which the platform supports will be > used; the others will be represented as the next larger format of > the same type implemented. If there is no larger format of the same > type and there is a bignum format for that element type, then the > array format defaults to vector; otherwise the largest uniform > format of that type is used. I'll try an example to make sure I understand the intent correctly. Suppose that I'm targeting all the machines in an HP data center (a mix of x86, Itanium, and PA-RISC). flor128b => x86 extended (binaryx) on x86 and Itanium flor16b => IEEE single (binary32) on all three systems fixz64b => bignum on x86, or signed32 if there are no bignums I have one major issues with the rule as written above: It's not clear what to do if the system lacks a flonum format altogehter. For example, if you have no decimal flonums at all, you should probably use rational bignums instead (because binary flonums are unacceptable for the major decnum applications). However, if rational bignums are allowed as a "flonum" format, then the rule above would prefer them over binaryx. The essential problem here is that flonum, decnum, and fixnum typically have different requirements. In general, precision and range are non- negotiable for fixnums and decnums: Users only specify the large types when the data requires it. However, speed is usually more important than precision for binary flonums. It might be best to specify each major element type separately. Here are my recommendations for defaults when there's format large enough. Each offers a list of acceptable possibilities, roughly in order from most to least desirable. An implementation should document its behavior (and should allow users to reconfigure that behavior). Binary flonum (floTWb) a. largest available binary flonum b. arbitrary-precision floating-point number (a "floating-point bignum") c. rational bignum d. none (signal an error) Decimal flonum (floTWd) a. arbitrary-precision floating-point number b. rational bignum c. binary flonum with at least 2W precision d. none (signal an error) e. largest available decimal flonum Fixnum (fixTWb) a. flonum with at least W bits precision in the significand b. bignum c. none (signal an error) >> No fixq arrays for rational numbers? C'mon, you know you want to! > Although the syntax could easily specify arbitrary precisions, the > prototype functions would need to take extra arguments. Should the > precision be specified as total bits and fractional bits; or integral > bits and fractional bits? Oh, I figured they'd work like complex numbers, e.g., a fixq32b would have a 32-bit numerator and a 32-bit denominator. (That is how complex numbers work, right?) > It is the Swiss-army-knife of array syntax. I hope the R6RS editors > are okay with that. Well, I like it. There are a couple issues to work out, but I'm very happy with the spec overall. -- Bradd W. Szonye http://www.szonye.com/bradd