Hmmm... David, you seem to have covered all the issues with that rather
lucid screed [attached at bottom]. I have a couple of dragon-nits to pick,
one involving infrastructure and one involving syntax.
First: it seems strange to me to add yet another property ("but
used_to_be_scalar") to the output of the LoL semicolon, when there's a
perfectly good distinction still floating around (the one that is
deliberately blurred between [1] and 1). Using the scalarness of a LoL
element has the potential to make some really esoteric but useful things very
easy to do, since it's a general syntax that could be used for any LoL, not
just for slicing.
But then, there may be good reasons (not obvious to me) to use a property.
Second: Regardless of the LoL infrastructure, we seem to be adopting opposing
viewpoints on whether scalar-ish element in the LoL should be a scalar by
default, with a syntactic hook to denote it as a list-of-1; or whether it
should be a list-of-1 by default, with a syntactic hook to denote it as a
scalar. There are good reasons why either case will surprise a nontrivial
subset of people. Maybe we can sidestep the issue by making use of list
context as you pointed out.
Hmmm... What about replacing '*' entirely, with the yadda-yadda-yadda?
Certainly '0...' ought to enumerate (lazily) everything from 0 to infinity,
so it ought to return everything. But then why not make term-'...' into
an abbreviation for '0...'? That sort of keeps the conceptual crud down
while letting everything get written straightforwardly:
How about this scenario?:
Ground rules: list expressions slice; scalar expressions index;
Basic cases:
[5 ; 0..6] # scalar exps are scalar by default (index)
[(5) ; 0..6] # 5 is now in list context (slice)
[1..1 ; 0..6] # '..' returns a list of 1 element (slice)
[0... ; 0..6] # '0...' is a valid lazy list, if ugly (whole axis)
[... ; 0..6] # '...' acts like '0...' (whole axis)
[* ; 0..6] # OK, have it your way - '*' is a synonym for '0...'.
Cases that return nothing: (either an empty list or undef...)
[ ; 0..6] # An empty list yields nothing
[undef; 0..6] # undefined value yields nothing
[1..0; 0..6] # '..' gives list of no elements; you get nothing
Forcing syntax:
[+(5) ; 0..6] # unary '+' forces scalar context (index always)
[(5) ; 0..6] # List-context parens force list context (slice always)
[5* ; 0..6] # postfix-* forces a slice? (no conflicts?)
Not accepted syntax:
[*5 ; 0..6] # does something strange -- tries to index with a glob.
The only reason to gripe about that (for me) is that surrounding parens change
sense compared to perl5/PDL slicing -- but that seems trivial compared to
hammering out something that's convenient for everyone and still makes some
sort of coherent sense.
Quoth David Green on Wednesday 12 January 2005 05:40 am,
> OK, so at issue is the difference between an element of an array ($p5[1])
> and a slice (that might contain only one element, @p5[1]), only
> generalised to n dimensions. (A problem which didn't exist in P5 because
> there were no higher dimensions!)
>
> And we don't want @B[4; 0..6] to reduce to a 1-D 6-array because then
> dimensions would just be disappearing into some other...dimension.
> (To lose one dimension is a misfortune, to lose two is plane careless....)
> On the other hand, nobody wants to have to write @B[gone(4)] every time
> you need an array element.
>
> Given $a=42 and @a=(42), what if @X[$a] returned a scalar and @[EMAIL
> PROTECTED]
> returned a slice? Similarly, @X[$a; 0..6] would return a 6-array, and
> @[EMAIL PROTECTED]; 0..6] a 1x6-array -- scalar subscripts drop a given
> dimension and
> array subscripts keep it. (I think this is almost what Craig was
> suggesting, only without giving up ! for factorial. =))
>
> The list-of-lists semicolon can still turn the 42 into [42], so that if
> you have a list-of-listy function that doesn't care whether you started
> with scalars or not, it doesn't have to know. But really the LoL
> semicolon would turn 42 into C<[42] but used_to_be_scalar>, so that
> something that *does* care (e.g. subscripting an array) can simply check
> for that property.
>
> Using a scalar to get a scalar feels rather appropriate, and not too
> surprising, I think. Most people would probably expect @X[$a] to return
> a scalar, and use @[EMAIL PROTECTED] to mean a slice (if @a happened to have
> only a
> single element, you're still probably using an array subscript to get
> possibly many elements -- otherwise why would you be using an array @a
> instead of just a plain scalar in the first place?)
>
> Plus if you do want to force an array subscript instead of a scalar, or
> vice versa, you don't need any new keywords to do it: @[EMAIL PROTECTED];
> 0..6] or
> @X[[42]; 0..6] (which is the same as @X[list 42; 0..6], right? Which
> could also be written @X[*42; 0..6], which is kind of nice, because [*42]
> means "give me the 42nd slice" while [*] means "give me an unspecified
> slice, a slice of everything".)
>
>
> Anyway, delving right into the can of wyrms, in P5 there were list,
> scalar, and void contexts (1-D, 0-D, and... uh... -1-D?), but now that we
> have real multidimensional arrays, we could have infinite contexts (ouch).
> Well, there must be some nice way to generalise that, but it raises a
> bunch of questions. (I can imagine "table context" being reasonably
> popular.)
>
> Various functions in P5 left the dimension of their arg untouched (take a
> list, return a list), or dropped it down one (take a list, return a
> scalar). (Taking a scalar and returning a list is less common, but I can
> imagine a 2-D version of 'split' that turns a string into a table....)
>
> So in p6, should 'shift'ing an n-D array return a scalar or an array of
> n-1 dimensions? It depends on whether you see it as a way to criss-cross
> through an array one element at a time, or as a way to take one 'layer'
> off something. Both would be useful.
>
> 'grep' could return a list (1-D) of all matching individual elements, but
> perhaps more usefully it could preserve dimensionality:
> my @board is shape(8;8);
> #match alternating squares:
> @checkerboard=grep { ($_.index[0] + $_.index[1])%2 } @board;
>
> ...to end up with a ragged 2-D array containing only the usable half of
> our checkerboard. (I'm assuming we have something like .index to get the
> x, y co-ords of an element?)
>
> 'reverse' would presumably flip around the indices in all dimensions. Ah,
> the fun of coming up with new multidimensional variations on all the old
> (or new) favourites!
>
>
> - David "a head-scratcher no matter how you slice it" Green