I've been struggling lately with a missing generalization, and I'm not sure how it's going to play out, so I thought I'd ask for advice, or at least think out loud a bit.
Perl has always had functions and listops that take a flat list and do something with each element. Perl has also had various functions that return flat lists, and these naturally feed into the listops. For instance, the map function has always produced a flat list. A split with captures flattens the captures along with the split values. Recently I started redefining C<map> to return multislices such that map { $_, $_ * 10 }, 1..3 seems to return 1,10,2,20,3,30 by default, but in a multidimensional context: @@multislice := map { $_, $_ * 10 }, 1..3 it would have the value [1,10], [2,20], [3,30]. Likewise the values returned by loop iterations or by C<take> have been turned into such multislices. But then these all seem like special casing something more general. When I look at the functions we've defined so far, I see that zip(1,2,3; 4,5,6) produces [1,4],[2,5],[3,6] while each(1,2,3; 4,5,6) produces 1,4,2,5,3,6 and then I have to ask myself, "Why in this case do we have two separate functions that essentially do the same thing?" It's a design smell. Which leads me to think that zip should really return 1,4; 2,5; 3,6 and let the context either flatten or not. Basically, a list return is a Capture, so a higher order function that calls a list operator repeatedly is really returning a Capture of Captures, or a List of Captures, and that's probably what a "multislice" is really. However, currently the only way to get "chunky" behavior is to bind the CoC to a multislice array: @smooth := zip(1,2,3; 4,5,6) @@chunky := zip(1,2,3; 4,5,6) If the default is "smooth", then we need better rvalue syntax for explicitly turning a CoC into LoA, such that you could say chunky zip(1,2,3; 4,5,6) and get the list value [1,4],[2,5],[3,6] And indeed, it's easy to define the function in current notation, something like: sub chunky (*@@chunky) { return @chunky } Basically, this is the inverse of [;], which turns LoA into a CoC. [;] chunky mumble() But "chunky" is clunky, and I'm wondering what syntactic relief we can give ourselves here. I think people would get tired of writing .map({...}).chunky chunky split chunky for 1..100 { $_, $_*10 } I think most other languages would probably just default to returning a structured value and force the user to flatten explicitly. That doesn't seem much like the Perl Way though... Distinguish via unary operators maybe? |(1,2; 3,4) # smooth: 1,2,3,4 =(1,2; 3,4) # chunky: [1,2],[3,4] Doesn't seem to work well with method forms though... (1,2; 3,4)."|" (1,2; 3,4)."=" We could have a special .| form if the default where .=, but .= is taken already so .| can't be the default there. Maybe something else is better than = there. Or maybe we need a naming convention that distinguishes smooth/chunky variants of all the named functions/methods. Then we have the non-commital form: map the smooth form Xmap mapX and the chunky form Ymap mapY for some value of X and Y. But that approach starts to get a bit obnoxious when you want to start adding other similar modifiers, like whether map is allowed to be parallel or must be executed serially. It also doesn't work well with operator forms like ¥ and such. (That almost suggests it should be another metaoperator. Let's all shudder together now...but not rule out the possibility.) Adverbs would be another approach. Those could conceivably work on operators, though a bit oddly insofar as applying to all previous list-associative siblings: for 1,2 ¥ 3,4 ¥ 5,6 :smooth -> $a, $b, $c {...} for 1,2 ¥ 3,4 ¥ 5,6 :chunky -> [$a, $b, $c] {...} And how do you force the return value of the "for" to be smooth or chunky? Course, a "chunky" listop would probably do for that. I should also mention I did (briefly) consider the "null" reduce operator: [] zip(1,2;3,4) to mean "slap [] around each element", but it runs into ambiguity with the existing [] form indicating an empty list. Or maybe a multislice array is a special type, so it's really a type cast: @@(zip(1,2;3,4)) But then people will try to write @@zip and wonder why it doesn't work... The possibilities are endless, and I don't doubt that you can think of a few more... Larry