I have never understood the benefits of making syntactic sugar for lists in languages having higher order functions. Python kind-of gets away with it, but I still don't get the benefits compared to using map and filter.
I think a huge benefit is the readability of more complex expressions (e.g. when you start introducing zip, groupBy, folds etc into the mix).
If you want to show some code examples of list comprehensions, I'd be glad to show the equivalent without list-comprehensions in JS (which had a rejected proposal for list-comphensions https://www.reddit.com/r/javascript/comments/5eottt/why_the_..., no regret though), so we can compare the readability
How about finding triples a
[(a,b,c) for a in range(1,30)
for b in range(a+1,30)
if gcd(a,b)==1
for c in range(b+1,30)
if gcd(a,c)==1 and gcd(b,c)==1
for d in [int((a**3+b**3+c**3)**(1.0/3)+0.5)]
if a**3+b**3+c**3==d**3]
I doubt that would look any nicer with higher order functions. Specially if you want to get the same efficiency: notice how here we test that gcd(a,b)==1 as soon as possible. In general efficient comprehensions involve pushing any filtering as early as possible, so with higher order functions you get an alternation of filter with map/flatmap.Here's a (probably lame) attempt at a Python higher order version:
flatmap = lambda f, l: [x for t in l for x in f(t)]
flatmap(lambda a: flatmap(lambda b: flatmap(lambda c: (lambda d: [(a,b,c)] if a**3+b**3+c**3==d**3 else [])(int((a**3+b**3+c**3)**(1.0/3)+0.5)) if gcd(a,c)==1 and gcd(b,c)==1 else [], range(b+1, 30)) if gcd(a,b)==1 else [], range(a+1,30)), range(1,30))
Maybe it would look nicer with some filters thrown in instead of abusing flatmap of empty lists, but it would be longer since you definitely need a flatmap for a and b, and either a flatmap or map for c.I'd love to see a cleaner version with higher order function.
I don't understand your `+0.5`, I've written below the transcription for your description
[...1:30].map(a =>
[...a+1:30].filter(b => gcd(a,b)==1).map(b =>
[...b+1:30].filter(c => gcd(a,c)==1
&& gcd(b,c)==1
&& Number.isInteger((a**3+b**3+c**3)**(1/3))
.map(c => [a, b, c])
)
).flat(2)
Or another equivalent way: [...1:30].flatMap(a =>
[...a+1:30].filter(b => gcd(a,b)==1).flatMap(b =>
[...b+1:30].filter(c => gcd(a,c)==1
&& gcd(b,c)==1
&& Number.isInteger((a**3+b**3+c**3)**(1/3)))
.flatMap(c => [[a, b, c]])
Or another way (generating first all the triples): [...1:30].flatMap(a => [...a+1:30].flatMap(b => [...b+1:30].flatMap(c => [[a, b, c]])))
.filter(([a, b, c]) => gcd(a,b)==1 && gcd(a,c)==1
&& gcd(b,c)==1 && Number.isInteger((a**3+b**3+c**3)**(1/3)))
with https://github.com/tc39/proposal-iterator-helpers, which would allow lazy evaluation, and make more sense than above (1:30).flatMap(a => (a+1:30).flatMap(b => (b+1:30).flatMap(c => [[a, b, c]])))
.filter(([a, b, c]) => gcd(a,b)==1 && gcd(a,c)==1
&& gcd(b,c)==1 && Number.isInteger((a**3+b**3+c**3)**(1/3)))
without the slice-notation, it's really ugly (hence the proposal in the first link) Array.from({length: 30},(_,a)=>a+1)
.flatMap(a=>Array.from({length: 30-a-1},(_,b)=>a+b+1)
.flatMap(b => Array.from({length: 30-b-1},(_,c)=>b+c+1).flatMap(c => [[a, b, c]])))
.filter(([a, b, c]) => gcd(a,b)==1 && gcd(a,c)==1
&& gcd(b,c)==1 && Number.isInteger((a**3+b**3+c**3)**(1/3)))