I'm working though a Rust course right now, and while my code works fine (once it compiles), I always see the reference implementations of the code, and it's like 2 lines of filter/map/collect, and voila. Meanwhile, my 8 line frankenfunction looks like the Charlie Brown Christmas tree.
Using a loop is not a sin, but it is often counterproductively over-prescriptive. A loop says, 'do these things in this order in a single thread'. If the loop body is an effect-free function, then the order doesn't matter, why not use a map to let the compiler or run-time decide how many cores/containers/botnets to throw at the problem? Similarly, if the loop combines the results of its iterations in a unital and associative way, why not use a fold/reduce in order to get as much parallelism as possible for free? Sure, your compiler could try to do some fancy static analysis to try to figure out whether the loop you've written is equivalent to a more efficient program, and if so, replace it for you, but that's a lot of work for the compiler writer and inherently limited: we're a long way away from compilers being able to guess properties of programs and synthesize proofs for them. Sometimes avoiding loops is both conceptually clearer and practically more efficient.
> why not use a fold/reduce in order to get as much parallelism as possible for free?
I always wondered how this would then be configured in a convenient way. I mean, there are situations where you can not just let the compiler parallelize to the max (e.g. web services).
99% of the time a loop works just fine, because there are no measurable gains to be had from parallelism. For the 1% where performance matters, it's usually a bit more involved that simply using a map or fold, and hopefully already packaged as an off-the-shelf library. To have measurable gains from parallelism one has to be very intentional in balancing communication vs computation. Think carefully designed libraries like cuDNN.
I'm working though a Rust course right now, and while my code works fine (once it compiles), I always see the reference implementations of the code, and it's like 2 lines of filter/map/collect, and voila. Meanwhile, my 8 line frankenfunction looks like the Charlie Brown Christmas tree.