Julia: Add a "lazy" while guard to comprehension syntax

Created on 12 Jul 2017  路  9Comments  路  Source: JuliaLang/julia

I have found myself wanting to write something like:

X = [f(a) for a in iterator if cond1(a) while cond2(a)]

and have this return elements from the iterator until cond2(a) returns false. This would essentially be the same as:

X = []
for a in iterator
    !cond2(a) && break
    cond1(a) && push!(X, f(a))
end

Using while in this context looks and feels a lot like the functional takewhile function, uses an already existing keyword, and is to my eyes a lot less noisy than the explicit loop above.

There are a few StackOverflow questions that have asked for a similar functionality here https://stackoverflow.com/questions/44097910/killing-a-for-loop-in-julia-array-comprehension and here https://stackoverflow.com/questions/44101965/array-comprehension-with-a-random-output-in-julia/

help wanted speculative

Most helpful comment

I have no real inclination one way or the other, but I thought the sentence "get item from shop if item is in shopping list while wallet is not empty" sounded better than "get item from shop while wallet is not empty if item is in shopping list".

All 9 comments

Could be added as a feature in the 1.x series since it's a syntax error currently.

Shouldn't this rather be written [f(a) for a in iterator while cond2(a) if cond1(a)], to be consistent with the usual ordering?

I have no real inclination one way or the other, but I thought the sentence "get item from shop if item is in shopping list while wallet is not empty" sounded better than "get item from shop while wallet is not empty if item is in shopping list".

But if this is implemented, it would also make sense to extend it to

for a in iterator while cond(a)
    ...
end

and here it's more clear the if should come after the while.

How would you know that the while isn't a while loop in the explicit loop case? But I like the idea of extending it, although it doesn't do much except save a line and two characters from cond(a) && break. 馃槃

Well, the syntax would be defined so that it can't be a while loop unless there's a new line. You're right that that would be quite confusing though.

I'm not entirely opposed to the notation for arbitrary loops, but I do think it would cause head scratching for most people on the first read. Going a bit further, and I'm really not sure if I like this idea myself, but if it translated into a return a instead of break, you could write dropuntil as:

x = for a in iterable while cond(a) end
->
x = for a in iterable
    !cond(a) && return a
end

which has a nice symmetric similarity with the proposed comprehension syntax of takewhile.

Any occurrence of while in a comprehension or loop context will cause head-scratching since it has no precedence in other languages.

A good first step would be to add the appropriate Base.Iterators.takewhile function, which will be needed to implement the comprehension with anyway. The takewhile can be used in more situations because it's more general.

It's worth noting that comprehensions already support more syntax than ordinary for loops in that they can have condition clauses, which for loops cannot. I don't think it makes sense to couple adding features to comprehensions with adding them to for loops since these things are already easy to express with for loops by using break and continue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

felixrehren picture felixrehren  路  3Comments

arshpreetsingh picture arshpreetsingh  路  3Comments

ararslan picture ararslan  路  3Comments

sbromberger picture sbromberger  路  3Comments

Keno picture Keno  路  3Comments