Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to destructure for loop parameters into array of fixed size?

I am trying to put the parameters in a for loop into array of FIXED size. This is what I have been doing (I want to use a array @m of 3 elements):

for (1..19).rotor(3, :partial) -> @m { say @m; } # works, but I cannot specify size of @m

However, all of the following give me errors:

for (1..19).rotor(3, :partial) -> @m[0,1,2] { say @m; }
===SORRY!=== Error while compiling:
Variable '@m' is not declared
------> ).rotor(3, :partial) -> @m[0,1,2] { say ⏏@m; }

for (1..19).rotor(3 => -2) -> @m[0..2] { say @m; }
===SORRY!=== Error while compiling:
Variable '@m' is not declared
------> 1..19).rotor(3 => -2) -> @m[0..2] { say ⏏@m; }

for (1..19).rotor(3 => -2) -> @m[3] { say $_; say @m; }
===SORRY!=== Error while compiling:
Variable '@m' is not declared
------> ).rotor(3 => -2) -> @m[3] { say $_; say ⏏@m; }

So, how should I specify that the array @m must have only 3 elements?

like image 675
lisprogtor Avatar asked Mar 03 '23 14:03

lisprogtor


2 Answers

The title of the question mentions destructuring, but that is about taking something apart. For example, we could extract the three elements using it:

for (1..19).rotor(3, :partial) -> [$a, $b, $c] {
}

However, this doesn't seem to actually be a destructuring problem, since the request isn't to break the passed aggregate into its parts, but transform it into a different type of aggregate.

Looking a little further at the question:

I am trying to put the parameters in a for loop into array of FIXED size.

The thing is, rotor doesn't produce (mutable) Arrays at all. Instead, when writing:

for (1..19).rotor(3, :partial) -> @m {
}

Then @m is a List. A List is immutable (and thus implicitly its size is fixed at creation), so if the intent is that there can be no accidental change of size, that's already a cert. Unfortunately, the ultimate goal wasn't stated.

If really wanting to turn the passed immutable List into a shaped Array, there's nothing for it other than to assign it into a new fixed size Array:

for (1..19).rotor(3, :partial) -> @l {
    my @arr[3] = @l;
}

Of course, this is going to blow up if the :partial leads to leftover elements; one could do:

for (1..19).rotor(3, :partial) -> @l {
    my @arr[@l.elems] = @l;
}

To avoid that. However, if the goal as really to ensure that things blow up if there ever are leftover elems, then either a where:

for (1..19).rotor(3, :partial) -> @m where .elems == 3 {
}

Or, a bit less clearly, a throw-away destructure:

for (1..19).rotor(3, :partial) -> @m [$,$,$] {
}

Would do it.

like image 180
Jonathan Worthington Avatar answered Apr 30 '23 10:04

Jonathan Worthington


So the -> @m[3] is what you want but that's assigning a Signature your anonymous block that's expecting a shaped array and you're passing in a List.

So what I ended up doing may coercing my list into a shaped Array.

for (1..19).rotor(3, :partial).map( { Array.new(:shape(3),$_ ) } ) -> @m[3] { say @m; }

And then it works fine. There's probably a better way to do it though.

like image 37
Scimon Proctor Avatar answered Apr 30 '23 08:04

Scimon Proctor