Any where to find the doc for lc-each, lc-else and lc-for-c ?

classic Classic list List threaded Threaded
65 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
Trying out the newest snapshot 2016.10.04 (git 7e0935d) and found these new features: lc-each, lc-else and lc-for-c

Can't seem to find docs/examples about them in list comprehension doc.

The lc-else is easy to understand:

list = [ for (a = [ 1 : 8 ]) if (a % 2 == 0) a else a*10 ];
echo(list); // ECHO: [10, 2, 30, 4, 50, 6, 70, 8]
But I am a bit wondering what's benefit of it over this shorter one:

list = [ for (a = [ 1 : 8 ]) (a % 2 == 0)? a : a*10 ];
I can't figure out the other two and will need help.



$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
tp3
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

tp3
On 10/30/2016 11:50 AM, runsun wrote:
> Trying out the newest snapshot 2016.10.04 (git 7e0935d) and found these new
> features: lc-each, lc-else and lc-for-c
>
> Can't seem to find docs/examples about them in  list comprehension
> <https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions>  
> doc.
>
See https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/WIP

ciao,
  Torsten.


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
-- Torsten
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Ronaldo
In reply to this post by runsun
runsun wrote
But I am a bit wondering what's benefit of it over this shorter one:
list = [ for (a = [ 1 : 8 ]) (a % 2 == 0)? a : a*10 ];
There is benefit in some nested tests and filters:
list = [ for (a = [ 1 : 8 ]) if (a % 2 == 0) a else if (a!=1) a*10 ];
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

nophead
Presumably, by using each you could add a different numbers of elements in the else part, which you can't do with a ? : expression.

On 30 October 2016 at 13:45, Ronaldo <[hidden email]> wrote:
runsun wrote
> But I am a bit wondering what's benefit of it over this shorter one:
>> list = [ for (a = [ 1 : 8 ]) (a % 2 == 0)? a : a*10 ];

There is benefit in some nested tests and filters:

> list = [ for (a = [ 1 : 8 ]) if (a % 2 == 0) a else if (a!=1) a*10 ];





--
View this message in context: http://forum.openscad.org/Any-where-to-find-the-doc-for-lc-each-lc-else-and-lc-for-c-tp18823p18827.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
Thx guys for the help. I tried out the examples in the WIP and you guys provided. These are all very powerful additions. The for-else example in the WIP was very confusing to me at first, until I tried the example Ronaldo gave.

I think an easy way of explanation would be that a "cond?a:b" format handles AND RETURN every single item, but "if" or "if-else" allows users to discard some. With this in mind, the example in WIP,
echo([ for (a = [0 : 3]) if (a < 2) ( if (a < 1) ["+", a] ) else ["-", a] ]);
// ECHO: [["+", 0], ["-", 2], ["-", 3]]
can be read as:
>>> when a<2: discard those a>=1, and handle the rest as ["+",a]
>>> when a>=2: ["-",a]

Emphasizing the "discard" part helps me understand it better.

In my opinion, this would be the same as if we allow an "if" existing in the "cond?a:b" format;

a<2? ( if (a < 1) ["+", a] ) : ["-", a]
Or, for Ronado's example:

a %2==0? a: if (a!=1) a*10
I'd like this form better, because it sort of focusing the feature of "if" as a filter that discards something, but not "sometimes it discards, sometimes it picks it back up when else is added".

But, at least it's there when we need it. Thx to those who puts them up. Great additions.
$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Ronaldo
I transcribe here an example of the benefits of the if-else I had used a few months ago to argue its need. The following list comprehension filter in the new sintax:
if ( A ) (  if( B ) x  else if (C) y ) else  z
could be expressed in the old one by:
 if ( B || C )  !A ? z :  B ? x :  y
which is rather cryptic and hard to write. Besides, if we change the first code eliminating the 'else z' part, the standard code will change to:
if ( A )  if(B || C)  B ? x: y
which is far from an obvious change.
runsun wrote
a %2==0? a: if (a!=1) a*10
I'd like this form better, because it sort of focusing the feature of "if" as a filter that discards something, but not "sometimes it discards, sometimes it picks it back up when else is added".
I agree that the list comprehension 'if' is not always a filter in the new syntax. But in your alternative the construct ?: would not always be an expression if it is composed with a filter 'if'. If we extend the usage of conditional expressions as you propose why not in other expressions too?
[ for(a=A) a+(if (a==0) 1) ]
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Tim V. Shaporev
On 10/31/2016 4:03 PM, Ronaldo wrote:
> I transcribe here an example of the benefits of the if-else I had used a few
> months <http://forum.openscad.org/List-comprehension-filters-tc16069.html>
> ago to argue its need. The following list comprehension filter in the new
> sintax:
>
>> if ( A ) (  if( B ) x  else if (C) y ) else  z

I believe such syntax should be forbidden because it is not obvious what
is else part of if (C).

Do you mean
A ? (B ? x : (C ? y : undef)) : z

> could be expressed in the old one by:
>>  if ( B || C )  !A ? z :  B ? x :  y

Oh, no, it's something different.

I am quite doubtful if this is really benefit.

Just my $0.02
Tim

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
In reply to this post by Ronaldo
Ronaldo wrote
The following list comprehension filter in the new sintax:
if ( A ) (  if( B ) x  else if (C) y ) else  z
could be expressed in the old one by:
 if ( B || C )  !A ? z :  B ? x :  y
which is rather cryptic and hard to write.

Besides, if we change the first code eliminating the 'else z' part, the standard code will change to:
if ( A )  if(B || C)  B ? x: y
which is far from an obvious change.
I think you made it too complicated. It should be expressed as follows instead :
A? (B?x:if(C)y) : z
which, in my opinion, is a lot easier to both read and write than the 3 forms you presented.

Note that I highlight the if(C)y part to emphasize that "an if w/o else is a filter", and "an if with an else is the same as cond?A:B".

runsun wrote
a %2==0? a: if (a!=1) a*10
why not in other expressions too?
[ for(a=A) a+(if (a==0) 1) ]
Because it can be easily achieved with current stable release:
[ for(a=A) a==0? a+1:a ]
$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
This post was updated on .
In reply to this post by Tim V. Shaporev
Tim, I had the similar confusion, took me a lot of "brain twists" to understand it. Now that after I keep talking to myself for hours:

"an if w/o else is a filter", and "an if with an else is the same as cond?A:B".

I am able to decode it and I think once you keep reminding yourself this principle, it'd be easier for you, too.

So the example:

>> if ( A ) (  if( B ) x  else if (C) y ) else  z

has 3 if's: the first and 2nd ones, if(A) and if(B), are followed by an "else", so are the same as A?~:~ and B?~:~, respectively

The 3rd one, if(C), has no "else", so it is a filter. So it can be translated to the "imagined workable code":

A? ( B?x: if(C)y) : z

Once this principle is embedded in mind, it becomes not that confusing.

In the mean time, however, I believe this construct will continue to frustrate future (or even current) users.

$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Ronaldo
In reply to this post by runsun
runsun wrote
I think you made it too complicated. It should be expressed as follows instead :
A? (B?x:if(C)y) : z
which, in my opinion, is a lot easier to both read and write than the 3 forms you presented.
We are discussing two different matters: the benefits of the if-else filter in list comprehension and your alternative sintax of it. The first point of my last message was about the benefits. So, your recoding above mix the two things and did not help.

The second issue (your alternative to if-else filter) has it own drawbacks. With my trivial example:
[ for(a=A) a+(if (a==0) 1) ]
I meant:
[ for(a=A) if (a==0) a+1 ]
which is a filter, and not your code:
[ for(a=A) a==0? a+1:a ]
which is not. The if in the first expression imposes a filter as in your alternative sintax. That is, if a filter if is allowed as a filter in conditional expression why wouldn't it be allowed in any expression (keeping its effect of filtering) ?
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
Ronaldo wrote
We are discussing two different matters: the benefits of the if-else filter in list comprehension and your alternative sintax of it.
I'd strongly suggest not to categorize "if-else" construct as a "filter". A filter means pick something and discard the rest based on a condition. With the "if-else", nothing can be discarded (just like cond?a:b), so it shouldn't be considered a filter. Treating it a filter only add more confusion 'cos it's the role "if" (w/o else) plays.  

The first point of my last message was about the benefits. So, your recoding above mix the two things and did not help.
Sorry I don't get this part.

The second issue (your alternative to if-else filter) has it own drawbacks. With my trivial example:
[ for(a=A) a+(if (a==0) 1) ]
I meant:
[ for(a=A) if (a==0) a+1 ]
which is a filter
Re-arranging "if(a==0) a+1" to "a+(if (a==0)1)" and suggesting they are the same doesn't make any sense at all. If "a" is subject to the conditional pick/drop, why would it be placed BEFORE if ? I couldn't ever imagine an "if" can simultaneously decide the fate of the code before it (a) and after it (1). That is a mess-up of scopes and only makes it more confusing.

If you ask "why not 'if' shows up here / there if it is allowed in cond?if(...):if(...)", then with the same logic, since "if" shows up in
[ for (...) if(...) ]
why not it is allowed in in
[ for(...) cond?if(...):if(...) ]
 
?
To me that's simply a choice of language design.
$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
After getting more familiar with this, I have this thought:

[ for(...) if(A) xxx else yyy ]  // allowed
[ for(...) if(A) (if(B) xxx ) else yyy ]  // allowed
[ for(...) if(A) xxx else (if(B)yyy ) ]  // allowed

They are basically the same as  :

[ for(...) A? xxx : yyy ]  // allowed
[ for(...) A? (if(B)xxx) : yyy ]  // NOT allowed
[ for(...) A? xxx : (if(B) yyy) ]  // NOT allowed

Since ALL "if-else" (w/o the filter (if(B) yyy)) are the same as "cond?~:~" (both are either-or conditional forks), the only purpose of introducing "else" seems to allow a filter (if(B) yyy) be valid.

That is, in order for a filter (if(B) yyy) to be legitimate, instead of making it legitimate in the already-existing construct "cond?~:~", we create a new one "if-else" that changes the role of "if", making it a source of confusion.

So a legitimate question is: why not just allow the filter (if(B) yyy) in a "cond?~:~" ?
$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Ronaldo
runsun wrote
So a legitimate question is: why not just allow the filter (if(B) yyy) in a "cond?~:~" ?
You have answered the question in your preceding message:
runsun wrote
Re-arranging "if(a==0) a+1" to "a+(if (a==0)1)" and suggesting they are the
same doesn't make any sense at all. If "a" is subject to the conditional
pick/drop, why would it be placed BEFORE if ? I couldn't ever imagine an
"if" can simultaneously decide the fate of the code before it (a) and after
it (1). That is a mess-up of scopes and only makes it more confusing.
That is exactly what is happening when you write something like:
[for (a=A) a % 2 == 0 ? a: if (a!=1) a*10 ]
the filter if is deciding "the fate of the conditional before it". In fact, the conditional expression above would not act as an expression but as a filter. And that is confusing!

I agree that is inappropriate to call the construct if-else a filter and that it is just a conditional that accepts filtering. But it is not equivalent to ?: because it is not an expression either.
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
Ronaldo wrote
runsun wrote
So a legitimate question is: why not just allow the filter (if(B) yyy) in a "cond?~:~" ?
You have answered the question in your preceding message:
My message was to explain that your trivial example is illogical. How could anyone invent an illogical usage of an idea in order to argue against that idea ?

That is exactly what is happening when you write something like:
[for (a=A) a % 2 == 0 ? a: if (a!=1) a*10 ]
the filter if is deciding "the fate of the conditional before it".
No! it is to decide the fate of the variable AFTER it ... when the condition "a%2==0" is met, the previous variable of if's, a, is then decided without invoking the if-filter. So it's not decided by the "if-filter". The 'if' filter comes into play only when "a%2==0" is not met. Under that condition, the 'if' filter is to decide the variable/code AFTER it, just like anywhere 'if' is used in this and other languages.
 
In fact, the conditional expression above would not act as an expression but as a filter. And that is confusing!
No, the condition expression (the ?:) is not a filter. The "if (a!=1) a*10" is, working only when condition "a % 2 == 0" is not met.

Re-write it to the currently accepted form:

[ for (a=A) if(a % 2 == 0 ) a else if (a!=1) a*10 ]

Now you have two if's, the 2nd one is a filter but the 1st is not. That's where the confusion comes.

I agree that is inappropriate to call the construct if-else a filter and that it is just a conditional that accepts filtering. But it is not equivalent to ?: because it is not an expression either.
Yes, "if-else" is a conditional that accepts filtering is the best way to describe it. Better if added: "if" w/o "else" serves as a filter.

But, other than the filtering, show me an example that can only be expressed by "if-else" but not "?:".

I don't think you could, because they serve the exact same role (other than the filtering).
$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Ronaldo
This will be my third message trying to clarify my point about your proposed syntax. And, I promise, it will be the last one.

The operator ?: is a ternary operator. As such, it requires 3 operand, no more no less. In the expression you prefer:
 a % 2 == 0 ? a: if (a!=1) a*10
when a=3 the operator ?: receives the following operands: true, 3 and <nothing>. That is, it receives just 2 operands as the filter if returns nothing at all. And you expect the operator ?: returns nothing at all in this case. That is a twisted (and confusing) behavior of it.

The if-else construct on the other hand has the very special property that it returns nothing if the followed branch (either true or false) receives nothing. And that is the reason why it cannot be used (like filter if) as a operand of any other operator except itself and the filter if.

If we allow the operator ?: receives less that 3 operands why not allow the sum operator + receives less that two?
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Parkinbot
Ronaldo, as you write it, ?: is a ternary operator. So it has to return a result, as it is the outer expression. You seem to argue that this result may also be nothing, which afaik currently is only an implicit feature (or call it a hack) of "if".  

Ronaldo wrote
a % 2 == 0 ? a: if (a!=1) a*10
I guess, you can always express a filter like this in the right order:
if (a!=1) (a % 2 == 0)? a : a*10
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Ronaldo
Parkinbot wrote
Ronaldo, as you write it, ?: is a ternary operator. So it has to return a result, as it is the outer expression. You seem to argue that this result may also be nothing, which afaik currently is only an implicit feature (or call it a hack) of "if".  
I couldn't say it better.
Parkinbot wrote
I guess, you can always express a filter like this in the right order:
if (a!=1) (a % 2 == 0)? a : a*10
Surely, we always can but after hard work and at the expenses of clarity in less obvious cases. The snapshot version syntax solves this and we certainly can replace all ?: by if-else without fear.
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

runsun
In reply to this post by Parkinbot
Parkinbot wrote
Ronaldo wrote
a % 2 == 0 ? a: if (a!=1) a*10
I guess, you can always express a filter like this in the right order:
if (a!=1) (a % 2 == 0)? a : a*10
This is exactly the same as "if-else" case. The example in the WIP:
echo( [ for (a = [ 1 : 8 ]) if (a % 2 == 0) a else if (a!=1) a*10 ] );
    could be written in the right order, as you wish, as :
   
echo( [ for (a = [ 1 : 8 ]) if (a!=1) if (a % 2 == 0) a else  a*10 ] );
and they return the same thing, which once again implies that "?:" behaves exactly like "if-else", which is what I've been arguing all along.

Parkinbot wrote
Ronaldo, as you write it, ?: is a ternary operator. So it has to return a result, as it is the outer expression. You seem to argue that this result may also be nothing, which afaik currently is only an implicit feature (or call it a hack) of "if".  
I believe that this belief of what "if-else" is is the source of conflict that causes conversations between Ronaldo and I went parallel.

Afaik, "if-else" by itself has to return something for every single item it handles, therefor is a "catch-all" construct and shouldn't be considered a filter. Ronaldo, on the other hand, thinks "if-else" is a filter, that it "has the very special property that it returns nothing if the followed branch (either true or false) receives nothing," therefor it can be used with "if(w/o else)" filter, but "?:" cannot.

Ronaldo forgot one thing: the "special property" he mentioned is a result of our design, NOT the reason for our design. One cannot design a behavior, then turn around to argue that having that behavior is the reason we need to design that behavior, or even go further to argue that we cannot add that same behavior to others because they don't have it.

"if-else" by itself is never a filter. Even in OpenSCAD when we allow "if(w/o else)" to be in "if-else" branch, it's the "if(w/o else)" that executes the filtering, not the "if-else". The ability of  "if-else" to accept "if(w/o else)" and turn its branch into a filter is NOT a nature of "if-else", but an add-on feature we intentionally put it in.

In terms of language feature, having a filter in a conditional expression is a novel and welcomed idea. But mixing "if-else" and "if(w/o else)" means that users have to deal with that an "if" in OpenSCAD list comprehension is sometimes a filter, sometimes not. That's where the confusion is.
$ Runsun Pan, PhD
$ libs: scadx, doctest, faces(git), offline doc(git), runscad.py(2,git), editor of choice: CudaText ( OpenSCAD lexer); $ Tips; $ Snippets
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

Parkinbot
In reply to this post by Ronaldo
Surely, we always can but after hard work and at the expenses of clarity in less obvious cases. The snapshot version syntax solves this and we certainly can replace all ?: by if-else without fear.
I must admit that the idea of having if/else, if within an expression having this semantics is a bit awkward. Personally I wouldn't introduce it, but implement the filter by introducing a new symbol like null that explicates what happens:
 a==v? a : null
in lc-context null could resolve to nothing and in expression context to 0 (or maybe undef).
In the second step I'd define a binary operator op1?op2 that defaults to the ternary operator op1?op2:null. This new binary operator can then be used anywhere.
Reply | Threaded
Open this post in threaded view
|

Re: Any where to find the doc for lc-each, lc-else and lc-for-c ?

nophead
As I said earlier: in conjunction with each if / else can add different numbers of elements to a list, which ? : can't as it is a single expression.

E.g.
if(a %2) a else each a, a * a

On 1 November 2016 at 19:17, Parkinbot <[hidden email]> wrote:

> Surely, we always can but after hard work and at the expenses of clarity
> in less obvious cases. The snapshot version syntax solves this and we
> certainly can replace all ?: by if-else without fear.

I must admit that the idea of having *if/else*, *if* within an expression
having this semantics is a bit awkward. Personally I wouldn't introduce it,
but implement the filter by introducing a new symbol like *null* that
explicates what happens:

>  a==v? a : null

in lc-context *null* could resolve to nothing and in expression context to 0
(or maybe *undef*).
In the second step I'd define a binary operator *op1?op2* that defaults to
the ternary operator *op1?op2:null*. This new binary operator can then be
used anywhere.



--
View this message in context: http://forum.openscad.org/Any-where-to-find-the-doc-for-lc-each-lc-else-and-lc-for-c-tp18823p18857.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
1234