discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

List comprehensions

NH
nop head
Thu, Dec 24, 2015 2:06 PM

Is there a reason why list comprehensions can't have a comma separated list
of elements after the for(..) instead of the just a single element? That
would eliminate the need for flatten in some cases.

Is there a reason why list comprehensions can't have a comma separated list of elements after the for(..) instead of the just a single element? That would eliminate the need for flatten in some cases.
DM
doug moen
Thu, Dec 24, 2015 2:48 PM

This proposed extension is also part of the OpenSCAD2 proposal. So I agree.

Generalised list comprehensions:
https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md

On Thursday, 24 December 2015, nop head nop.head@gmail.com wrote:

Is there a reason why list comprehensions can't have a comma separated
list of elements after the for(..) instead of the just a single element?
That would eliminate the need for flatten in some cases.

This proposed extension is also part of the OpenSCAD2 proposal. So I agree. Generalised list comprehensions: https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md On Thursday, 24 December 2015, nop head <nop.head@gmail.com> wrote: > Is there a reason why list comprehensions can't have a comma separated > list of elements after the for(..) instead of the just a single element? > That would eliminate the need for flatten in some cases. >
P
Parkinbot
Thu, Dec 24, 2015 3:03 PM

If I unterstand your question well, there is a good work-around for this. Use
a second loop variable within your loop and enumerate your vector with it:

echo([for(i=[0:10], j=[0:1])  let (a= [i, i*i]) a[j]]);

-Rudolf

--
View this message in context: http://forum.openscad.org/List-comprehensions-tp15321p15323.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

If I unterstand your question well, there is a good work-around for this. Use a second loop variable within your loop and enumerate your vector with it: echo([for(i=[0:10], j=[0:1]) let (a= [i, i*i]) a[j]]); -Rudolf -- View this message in context: http://forum.openscad.org/List-comprehensions-tp15321p15323.html Sent from the OpenSCAD mailing list archive at Nabble.com.
NH
nop head
Thu, Dec 24, 2015 3:16 PM

Yes that is a good trick but a comma would be much simpler.

On 24 December 2015 at 15:03, Parkinbot rudolf@parkinbot.com wrote:

If I unterstand your question well, there is a good work-around for this.
Use
a second loop variable within your loop and enumerate your vector with it:

echo([for(i=[0:10], j=[0:1])  let (a= [i, i*i]) a[j]]);

-Rudolf

--
View this message in context:
http://forum.openscad.org/List-comprehensions-tp15321p15323.html
Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Yes that is a good trick but a comma would be much simpler. On 24 December 2015 at 15:03, Parkinbot <rudolf@parkinbot.com> wrote: > If I unterstand your question well, there is a good work-around for this. > Use > a second loop variable within your loop and enumerate your vector with it: > > echo([for(i=[0:10], j=[0:1]) let (a= [i, i*i]) a[j]]); > > > -Rudolf > > > > -- > View this message in context: > http://forum.openscad.org/List-comprehensions-tp15321p15323.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
TP
Torsten Paul
Thu, Dec 24, 2015 11:29 PM

On 12/24/2015 04:16 PM, nop head wrote:

Yes that is a good trick but a comma would be much simpler.

I think that's relatively simple to add. I've created a patch
that allows multiple comma separated expressions and seems
to pass all the existing tests.

function f(x) = xxx;
echo([for (a = [1:2:10]) a, a*a, f(a)]);
// ECHO: [1, 1, 1, 3, 9, 27, 5, 25, 125, 7, 49, 343, 9, 81, 729]

It should be fine regarding compatibility as that syntax is
currently just an error.
I guess it still needs some more examples for testing though.

ciao,
Torsten.

On 12/24/2015 04:16 PM, nop head wrote: > Yes that is a good trick but a comma would be much simpler. > I think that's relatively simple to add. I've created a patch that allows multiple comma separated expressions and seems to pass all the existing tests. function f(x) = x*x*x; echo([for (a = [1:2:10]) a, a*a, f(a)]); // ECHO: [1, 1, 1, 3, 9, 27, 5, 25, 125, 7, 49, 343, 9, 81, 729] It should be fine regarding compatibility as that syntax is currently just an error. I guess it still needs some more examples for testing though. ciao, Torsten.
TP
Torsten Paul
Fri, Dec 25, 2015 12:47 AM

Also, to step a bit into the direction of
https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md

echo([for (a = [1:5]) if (a % 2 == 0) "even", a, [aa] else "odd", a, [aa*a]]);
// ECHO: ["odd", 1, [1], "even", 2, [4], "odd", 3, [27], "even", 4, [16], "odd", 5, [125]]

ciao,
Torsten.

Also, to step a bit into the direction of https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md echo([for (a = [1:5]) if (a % 2 == 0) "even", a, [a*a] else "odd", a, [a*a*a]]); // ECHO: ["odd", 1, [1], "even", 2, [4], "odd", 3, [27], "even", 4, [16], "odd", 5, [125]] ciao, Torsten.
TP
Torsten Paul
Tue, Jan 5, 2016 1:10 AM

On 12/24/2015 03:48 PM, doug moen wrote:

This proposed extension is also part of the OpenSCAD2 proposal.
So I agree.

Generalised list comprehensions:
https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md

On Thursday, 24 December 2015, nop head nop.head@gmail.com wrote:

Is there a reason why list comprehensions can't have a comma separated
list of elements after the for(..) instead of the just a single
element? That would eliminate the need for flatten in some cases.

Actually it's not the same. I just realized that after discussion with
Marius. The initial question was about having the list comprehension
expression as vector (without the []), like:

echo([ for (a = [2 : 4]) a, a*a ]);

which would result in:

ECHO: [ 2, 4, 3, 9, 4, 16 ]

The generalized solution (as is my understanding now) does not allow that,
it would result in "a*a" producing a warning that "a" is not defined at
this point as this part does not belong to the for() expression.

I think the solution following the suggested feature set would look like:

echo([ for (a = [2 : 4]) each [ a, a*a ] ]);
// ECHO: [2, 4, 3, 9, 4, 16]

which is a bit more verbose for this specific case, but having multiple
generators in one expression also allows for things like:

echo([ -1, for (a = [0:1:3]) a, for (b = [3:-1:0]) b, -1 ]);
// ECHO: [-1, 0, 1, 2, 3, 3, 2, 1, 0, -1]

I don't think we can have both, because the parser would have a hard
time to decide what the "," means.

The if/else is also implemented:

echo([ for (a = [0:2]) if (a == 1) "A" else "B" ]);
// ECHO: ["B", "A", "B"]

// nested list comprehension expressions with if/else
echo([ for (a = [0:3]) if ((a % 2) == 0) for (b = ["a", "b"]) b else each ["x", "y"] ]);
// ECHO: ["a", "b", "x", "y", "a", "b", "x", "y"]

AFAICS this should implement all the features of the "Using Generators in
List Literals" section with the exception of the "*" operator. What's the
rationale to have that shortcut?

ciao,
Torsten.

On 12/24/2015 03:48 PM, doug moen wrote: > This proposed extension is also part of the OpenSCAD2 proposal. > So I agree. > > Generalised list comprehensions: > https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md > > On Thursday, 24 December 2015, nop head <nop.head@gmail.com> wrote: > > Is there a reason why list comprehensions can't have a comma separated > > list of elements after the for(..) instead of the just a single > > element? That would eliminate the need for flatten in some cases. > Actually it's not the same. I just realized that after discussion with Marius. The initial question was about having the list comprehension expression as vector (without the []), like: echo([ for (a = [2 : 4]) a, a*a ]); which would result in: ECHO: [ 2, 4, 3, 9, 4, 16 ] The generalized solution (as is my understanding now) does not allow that, it would result in "a*a" producing a warning that "a" is not defined at this point as this part does not belong to the for() expression. I think the solution following the suggested feature set would look like: echo([ for (a = [2 : 4]) each [ a, a*a ] ]); // ECHO: [2, 4, 3, 9, 4, 16] which is a bit more verbose for this specific case, but having multiple generators in one expression also allows for things like: echo([ -1, for (a = [0:1:3]) a, for (b = [3:-1:0]) b, -1 ]); // ECHO: [-1, 0, 1, 2, 3, 3, 2, 1, 0, -1] I don't think we can have both, because the parser would have a hard time to decide what the "," means. The if/else is also implemented: echo([ for (a = [0:2]) if (a == 1) "A" else "B" ]); // ECHO: ["B", "A", "B"] // nested list comprehension expressions with if/else echo([ for (a = [0:3]) if ((a % 2) == 0) for (b = ["a", "b"]) b else each ["x", "y"] ]); // ECHO: ["a", "b", "x", "y", "a", "b", "x", "y"] AFAICS this should implement all the features of the "Using Generators in List Literals" section with the exception of the "*" operator. What's the rationale to have that shortcut? ciao, Torsten.
R
runsun
Tue, Jan 5, 2016 1:35 AM

Any thought of accessing the item(s) generated (still in the buffer), in the
middle of looping, before the loop is completed ?

Something like:

[ for(i=[1:4])
if(i==1) 1
else ((@-1)+i)*i
]

=> [ 1
,  (1+2)*2        // = 6
,  (6+3)*3        // = 27
,  (27+4)*4      // = 124
]

=> [ 1,6,27,124 ]


$  Runsun Pan, PhD

$ libs:

doctest ,

faces ( git ),

offline doc ( git ),

runscad.py( 1 , 2 , git ),

synwrite( 1 , 2 );

$ tips:

hash( 1 , 2 ),

sweep ,

var( 1 , 2 ),

lerp ,

animGif ,

precision( 1 , 2 ),

xl-control

--
View this message in context: http://forum.openscad.org/List-comprehensions-tp15321p15491.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Any thought of accessing the item(s) generated (still in the buffer), in the middle of looping, before the loop is completed ? Something like: [ for(i=[1:4]) if(i==1) 1 else ((@-1)+i)*i ] => [ 1 , (1+2)*2 // = 6 , (6+3)*3 // = 27 , (27+4)*4 // = 124 ] => [ 1,6,27,124 ] ----- $ Runsun Pan, PhD $ libs: doctest , faces ( git ), offline doc ( git ), runscad.py( 1 , 2 , git ), synwrite( 1 , 2 ); $ tips: hash( 1 , 2 ), sweep , var( 1 , 2 ), lerp , animGif , precision( 1 , 2 ), xl-control -- View this message in context: http://forum.openscad.org/List-comprehensions-tp15321p15491.html Sent from the OpenSCAD mailing list archive at Nabble.com.
DM
doug moen
Tue, Jan 5, 2016 1:42 AM

The reason for the * operator in OpenSCAD2 is that I unified the
"statement" and "expression" syntax to the maximum extent possible. The
prefix * operator already exists in OpenSCAD at the statement level, and I
made it available in expression syntax for consistency.

That's not a compelling reason for you to add it right now, it only really
makes sense later, assuming we decide to use the backward compatibility
scheme that I outline in the design doc. If we were to use a less rigid
backward compatibility system, one which allows some of the core syntax to
change, then we might decide to rename the prefix * operator to something
more mnemonic, like 'ignore'.

function f(x) = x;
module g(x) cube(x);

[ f(1), for (a = [2:4]) f(a), for (b = [4:-1:2]) f(b), f(1), ]
{ g(1); for (a = [2:4]) g(a); for (b = [4:-1:2]) g(b); g(1); }

Notice how the 2 lines above are structurally the same, and in OpenSCAD2
the 'for' operator has the same semantics in both cases. The first is a
list expression, the second is a "statement" (in OpenSCAD) or an "object
expression" (in OpenSCAD2). Note that the trailing , in the list expression
is optional in OpenSCAD, and I hope to make the trailing ; optional in the
object expression in OpenSCAD2.

Yes, the 'each' operator is verbose. I tried using an operator character,
&, in a previous draft, but it didn't get a very positive response from
Marius, because it doesn't look like anything familiar.

On 4 January 2016 at 20:10, Torsten Paul Torsten.Paul@gmx.de wrote:

On 12/24/2015 03:48 PM, doug moen wrote:

This proposed extension is also part of the OpenSCAD2 proposal.
So I agree.

Generalised list comprehensions:
https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md

On Thursday, 24 December 2015, nop head nop.head@gmail.com wrote:

Is there a reason why list comprehensions can't have a comma separated
list of elements after the for(..) instead of the just a single
element? That would eliminate the need for flatten in some cases.

Actually it's not the same. I just realized that after discussion with
Marius. The initial question was about having the list comprehension
expression as vector (without the []), like:

echo([ for (a = [2 : 4]) a, a*a ]);

which would result in:

ECHO: [ 2, 4, 3, 9, 4, 16 ]

The generalized solution (as is my understanding now) does not allow that,
it would result in "a*a" producing a warning that "a" is not defined at
this point as this part does not belong to the for() expression.

I think the solution following the suggested feature set would look like:

echo([ for (a = [2 : 4]) each [ a, a*a ] ]);
// ECHO: [2, 4, 3, 9, 4, 16]

which is a bit more verbose for this specific case, but having multiple
generators in one expression also allows for things like:

echo([ -1, for (a = [0:1:3]) a, for (b = [3:-1:0]) b, -1 ]);
// ECHO: [-1, 0, 1, 2, 3, 3, 2, 1, 0, -1]

I don't think we can have both, because the parser would have a hard
time to decide what the "," means.

The if/else is also implemented:

echo([ for (a = [0:2]) if (a == 1) "A" else "B" ]);
// ECHO: ["B", "A", "B"]

// nested list comprehension expressions with if/else
echo([ for (a = [0:3]) if ((a % 2) == 0) for (b = ["a", "b"]) b else each
["x", "y"] ]);
// ECHO: ["a", "b", "x", "y", "a", "b", "x", "y"]

AFAICS this should implement all the features of the "Using Generators in
List Literals" section with the exception of the "*" operator. What's the
rationale to have that shortcut?

ciao,
Torsten.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

The reason for the * operator in OpenSCAD2 is that I unified the "statement" and "expression" syntax to the maximum extent possible. The prefix * operator already exists in OpenSCAD at the statement level, and I made it available in expression syntax for consistency. That's not a compelling reason for you to add it right now, it only really makes sense later, assuming we decide to use the backward compatibility scheme that I outline in the design doc. If we were to use a less rigid backward compatibility system, one which allows some of the core syntax to change, then we might decide to rename the prefix * operator to something more mnemonic, like 'ignore'. function f(x) = x; module g(x) cube(x); [ f(1), for (a = [2:4]) f(a), for (b = [4:-1:2]) f(b), f(1), ] { g(1); for (a = [2:4]) g(a); for (b = [4:-1:2]) g(b); g(1); } Notice how the 2 lines above are structurally the same, and in OpenSCAD2 the 'for' operator has the same semantics in both cases. The first is a list expression, the second is a "statement" (in OpenSCAD) or an "object expression" (in OpenSCAD2). Note that the trailing , in the list expression is optional in OpenSCAD, and I hope to make the trailing ; optional in the object expression in OpenSCAD2. Yes, the 'each' operator is verbose. I tried using an operator character, &, in a previous draft, but it didn't get a very positive response from Marius, because it doesn't look like anything familiar. On 4 January 2016 at 20:10, Torsten Paul <Torsten.Paul@gmx.de> wrote: > On 12/24/2015 03:48 PM, doug moen wrote: > > This proposed extension is also part of the OpenSCAD2 proposal. > > So I agree. > > > > Generalised list comprehensions: > > https://github.com/doug-moen/openscad2/blob/master/rfc/Generators.md > > > > On Thursday, 24 December 2015, nop head <nop.head@gmail.com> wrote: > > > Is there a reason why list comprehensions can't have a comma separated > > > list of elements after the for(..) instead of the just a single > > > element? That would eliminate the need for flatten in some cases. > > > Actually it's not the same. I just realized that after discussion with > Marius. The initial question was about having the list comprehension > expression as vector (without the []), like: > > echo([ for (a = [2 : 4]) a, a*a ]); > > which would result in: > > ECHO: [ 2, 4, 3, 9, 4, 16 ] > > The generalized solution (as is my understanding now) does not allow that, > it would result in "a*a" producing a warning that "a" is not defined at > this point as this part does not belong to the for() expression. > > I think the solution following the suggested feature set would look like: > > echo([ for (a = [2 : 4]) each [ a, a*a ] ]); > // ECHO: [2, 4, 3, 9, 4, 16] > > which is a bit more verbose for this specific case, but having multiple > generators in one expression also allows for things like: > > echo([ -1, for (a = [0:1:3]) a, for (b = [3:-1:0]) b, -1 ]); > // ECHO: [-1, 0, 1, 2, 3, 3, 2, 1, 0, -1] > > I don't think we can have both, because the parser would have a hard > time to decide what the "," means. > > The if/else is also implemented: > > echo([ for (a = [0:2]) if (a == 1) "A" else "B" ]); > // ECHO: ["B", "A", "B"] > > // nested list comprehension expressions with if/else > echo([ for (a = [0:3]) if ((a % 2) == 0) for (b = ["a", "b"]) b else each > ["x", "y"] ]); > // ECHO: ["a", "b", "x", "y", "a", "b", "x", "y"] > > AFAICS this should implement all the features of the "Using Generators in > List Literals" section with the exception of the "*" operator. What's the > rationale to have that shortcut? > > ciao, > Torsten. > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > >
TP
Torsten Paul
Tue, Jan 5, 2016 1:59 AM

On 01/05/2016 02:35 AM, runsun wrote:

Any thought of accessing the item(s) generated (still in the buffer), in the
middle of looping, before the loop is completed ?

Hmm, the first two thoughts were

  • Isn't that what recursive functions can do much easier
  • I have no idea how to implement that with the current expression logic

Still, it might be possible. Do you have a specific use-case where that
would help. It's more compact than the matching recursive function,
but also looks a bit scary :).

Something like:

[ for(i=[1:4])
if(i==1) 1
else ((@-1)+i)*i
]

=> [ 1
,  (1+2)*2        // = 6
,  (6+3)*3        // = 27
,  (27+4)*4      // = 124
]

=> [ 1,6,27,124 ]

// the tail-recursive version is a bit more verbose
function f(i, x, r = []) = i <= x ? f(i + 1, x, concat(r, i == 1 ? 1 : (r[len(r)-1] + i) * i)) : r;

// could be written using "each" too :)
function f(i, x, r = []) = i <= x ? f(i + 1, x, [ each r, i == 1 ? 1 : (r[len(r)-1] + i) * i ]) : r;

echo(f(1, 4));
// ECHO: [1, 6, 27, 124]

ciao,
Torsten.

On 01/05/2016 02:35 AM, runsun wrote: > Any thought of accessing the item(s) generated (still in the buffer), in the > middle of looping, before the loop is completed ? > Hmm, the first two thoughts were - Isn't that what recursive functions can do much easier - I have no idea how to implement that with the current expression logic Still, it might be possible. Do you have a specific use-case where that would help. It's more compact than the matching recursive function, but also looks a bit scary :). > Something like: > > [ for(i=[1:4]) > if(i==1) 1 > else ((@-1)+i)*i > ] > > => [ 1 > , (1+2)*2 // = 6 > , (6+3)*3 // = 27 > , (27+4)*4 // = 124 > ] > > => [ 1,6,27,124 ] > // the tail-recursive version is a bit more verbose function f(i, x, r = []) = i <= x ? f(i + 1, x, concat(r, i == 1 ? 1 : (r[len(r)-1] + i) * i)) : r; // could be written using "each" too :) function f(i, x, r = []) = i <= x ? f(i + 1, x, [ each r, i == 1 ? 1 : (r[len(r)-1] + i) * i ]) : r; echo(f(1, 4)); // ECHO: [1, 6, 27, 124] ciao, Torsten.