Earlier quoted context omitted.
Semantically, loops impose order, maps do not. A map can be auto-parallelised. A loop cannot. It seems to me that for a language aimed at exploiting concurrent features, easy wins for parallelisation would be a feature.
There's really nothing about a typical map operation that makes it any more parallelize-able than a for-loop, in the presence of closures.
Rust and Go
91–100 of 311 posts
Re: Rust and Go
#92Earlier quoted context omitted.
To met it's pretty clear that the language C++ programmers were waiting for is called C++ 14.
As a C++ programmer, I'm waiting for C++ZZ where ZZ is the version that has a sane module system. Something like Cargo isn't even on the radar for C++ developers for a lot of reasons, but many of them can be traced back to textual inclusion.
Re: Rust and Go
#93Earlier quoted context omitted.
I'm thinking of the crowd that insists "map" is never more useful or readable than s straight for-loop. So not only don't they want it in go (which could be understandable in some situations), they genuinely seem to think it has no place in an imperative language. That blows my mind.
I've written in both paradigms and I mostly agree with the Go team. That it blows your mind blows mine, and I suppose it's good that we have these choices so we don't have to agree. Could you show me a code snippet of maps and filters used that you believe is more readable than for loops? Maybe I'll get a laugh out of that. :)
# utility, normally wouldn't be here
map2 = (f, xs, ys) ->
map (apply f, _), (zip xs, ys)
startsWith = (prefix, str) ->
map2 (==), prefix, str |> and-list
endsWith = (suffix, str) ->
revStr = unchars
"" is a "pipe" or "reverse application order operator", "_" is partial application. "map", "zip" and "apply" functions are standard and have expected semantics, "chars" transforms a string into an array of chars and "unchars" does the opposite (and they all come from prelude-ls library).This code is both shorter and easier to read (to me, at least) than equivalent for loops and it also composes better. The details of iteration are irrelevant here and so are abstracted, which means they can be trivially changed.
Of course, for "map" to be this useful it needs to be supported by many functionally oriented language constructs. It's also not the best example for anything, it's just a piece of code I wrote in a style I like, in a language I use.
Re: Rust and Go
#94Earlier quoted context omitted.
I've written in both paradigms and I mostly agree with the Go team. That it blows your mind blows mine, and I suppose it's good that we have these choices so we don't have to agree. Could you show me a code snippet of maps and filters used that you believe is more readable than for loops? Maybe I'll get a laugh out of that. :)
let descending_squares = range(0u, 5u).rev().map(|x| x * x).collect(); versus: let mut descending_squares = Vec::new(); let mut i = 4u; loop { descending_squares.push(i * i); if i == 0 { break } i -= 1 } (Note that if you try to use a for loop here you will infinite loop due to unsigned underflow.)
Re: Rust and Go
#95Earlier quoted context omitted.
let descending_squares = range(0u, 5u).rev().map(|x| x * x).collect(); versus: let mut descending_squares = Vec::new(); let mut i = 4u; loop { descending_squares.push(i * i); if i == 0 { break } i -= 1 } (Note that if you try to use a for loop here you will infinite loop due to unsigned underflow.)
You need a collect on that first example, you end with a Vec in the second, but an Iterator in the first.
Re: Rust and Go
#96Earlier quoted context omitted.
I've written in both paradigms and I mostly agree with the Go team. That it blows your mind blows mine, and I suppose it's good that we have these choices so we don't have to agree. Could you show me a code snippet of maps and filters used that you believe is more readable than for loops? Maybe I'll get a laugh out of that. :)
let descending_squares = range(0u, 5u).rev().map(|x| x * x).collect(); versus: let mut descending_squares = Vec::new(); let mut i = 4u; loop { descending_squares.push(i * i); if i == 0 { break } i -= 1 } (Note that if you try to use a for loop here you will infinite loop due to unsigned underflow.)
For loops are almost always going to explicitly show their allocations whereas the functional version has allocations that are not nearly as obvious.
Re: Rust and Go
#97Earlier quoted context omitted.
I've written in both paradigms and I mostly agree with the Go team. That it blows your mind blows mine, and I suppose it's good that we have these choices so we don't have to agree. Could you show me a code snippet of maps and filters used that you believe is more readable than for loops? Maybe I'll get a laugh out of that. :)
A for loop is a general tool. It can be used for anything. Because of that, it conveys little or no information. As a reader I have to read the loop in detail to see that what it does is perform a mapping, and not something slightly different (the last item could be skipped, etc etc). The expressiveness of higher order functions comes not from terseness (only) but by expressing intent more clearly. E.g this expresses…
I think on a higher level with complex code, you definitely want better abstractions to convey intent, rather than say just having one large function that does everything.
I think in many cases map/filter does in fact help with readability of intent, especially if you're not declaring the function body inline, and the functions are commonly available ones like parseInt. But generally this isn't the case, which diminishes the readability such that it's comparable to a for-loop anyways.
I spend most of my time trying to figure out exactly that -- the higher level abstractions that aren't easily conveyed by "map" or "filter", that having map/filter generic functions isn't high on priority. I just want a simple language that I can spew out thoughts onto uncompilable code... tweak the code often as I see fit, and work on fixing type errors later and once I'm done with that it will probably run fine with few bugs. The nice thing about for-loops is that it exposes more control points e.g. breaking out early, using the index, inserting log lines -- that the flexibility helps me mutate the code quickly.
So maybe it's more about coding style, rather than readability. Do you like to spec out your code completely before writing things down, or do you prefer to define the spec as you write and edit the code because it helps you get things done faster?
Re: Rust and Go
#98If you are considering Go, or just want a good laugh, just read discussions where higher order functions are discussed. Or for that matter, generics. Here is a gem: https://groups.google.com/forum/#!topic/golang-nuts/RKymTuSC... There's a chance you'll laugh at the people dismissing higher order functions as nonsense, in which case Go might not be for you. This is a good test of whether you want to try it out or not.
Let me save the reader of this comment a long and unproductive session of reading tea leaves out of mailing list posts: * Golang doesn't have generics. This comes up so often on the mailing list that it's in the FAQ: http://golang.org/doc/faq#generics * Golang has a similar attitude to idiomatic functional programming tools as Python; it doesn't have map() and it's not easy to write a general-purpose map. (I'll take…
>>> map(lambda x: x*5, range(5))
[0, 5, 10, 15, 20]Re: Rust and Go
#99Earlier quoted context omitted.
Well this is how I'd write it in Go: descending_squares := []uint{} for x:=4; 0
Use unsigned integers for your index and values. That's what makes it hard to use a for loop. (Sure, you could cast a signed integer loop index to unsigned inside the loop to avoid the underflow problem in this specific case, but I'd argue that the functional style is so much clearer than code that has to work around unsigned underflow gotchas.)
Re: Rust and Go
#100Earlier quoted context omitted.
let descending_squares = range(0u, 5u).rev().map(|x| x * x).collect(); versus: let mut descending_squares = Vec::new(); let mut i = 4u; loop { descending_squares.push(i * i); if i == 0 { break } i -= 1 } (Note that if you try to use a for loop here you will infinite loop due to unsigned underflow.)
Aside from your specific point (which I liked), isn't there a kind of tension here in a systems language? For loops are almost always going to explicitly show their allocations whereas the functional version has allocations that are not nearly as obvious.