Hacker News new | ask | show | jobs
by mseepgood 4537 days ago
These higher-order functions are a very inefficient way to write loops in Go. When you chain them you will end up with multiple sequential iterations instead of only one. Sort should not allocate and return a new slice, it's better to sort in-place, etc.
2 comments

It’s by design, though I understand the concern. From a design perspective, I like getting a distinct slice out the other end, without having to wonder whether I’ve mutated my original slice. It’s more stateless, so to speak.

Fwiw, slices are inexpensive by design. The elements themselves are not copied. Allocating a new slice is really a small ‘struct’ which serves as a pointer to the underlying array: http://blog.golang.org/go-slices-usage-and-internals

(Gen’ing pointers is supported, which mitigates the potential for allocation.)

It is true that chained operations will be multiple iterations. Whether it will net out to more iterations than otherwise depends on the use.

I’d be interested to see if someone can come up with a pattern where the operations themselves are composed, with a ’.Results()’ method that can intelligently (lazily?) minimize iterations. That’d be impressive.

That's functional programming for you. It's definitely less efficient, but there are other major advantages. For one thing, given the propagation of immutable data, things can be parallelized effortlessly - look at 'pmap' in Clojure for example. Once you're familiar with the style, it's significantly more concise and readable.

That being said, a systems programming language may not be the right place for FP concepts.

>That's functional programming for you.

Uhm, what? No it's not.

Haskell has stream fusion, thereby generating assembler that looks a lot like the optimal imperative version.

This is kind of misleading. Stream fusion isn't baked into Haskell; you need to use a library. [1,2]

    [1] - https://ghc.haskell.org/trac/ghc/ticket/915
    [2] - http://hackage.haskell.org/package/stream-fusion
http://hackage.haskell.org/package/text-0.1/docs/Data-Text-F...

http://hackage.haskell.org/package/vector-0.9.1/docs/Data-Ve...

Except it's bloody everywhere in the libraries you use and you can design your own libraries around it.

A language powerful enough that things like this can be done in libraries instead of in the compiler is a good thing.

But, many of the commonly used libraries already use stream fusion, e.g. vector and text.
Very cool - I was not aware of this feature. Fwiw, I'm actually something of an FP zealot; I failed to make a stronger case in my comment because I'm tired of arguing, and I'm concerned that I'm being obnoxious.
Scala gets around this with "views": store the higher-order functions until the collection actually needs to be used and then apply them all at once, without any intermediate data structure.

http://docs.scala-lang.org/overviews/collections/views.html

> things can be parallelized effortlessly

If you're not using a language with Clojure's nifty datastructures, "effortlessly" probably isn't much better than OpenMP.

D is a systems programming language with FP concepts and they work quite well. Also, it has generics / templates / parametric polymorphism that are more powerful and easier to use than C++.
Right, but it still employs a machine model of computation. This is fundamentally different from FP's language model.

https://existentialtype.wordpress.com/2011/03/16/languages-a...

> That being said, a systems programming language may not be the right place for FP concepts.

It's good enough for Rust.

Note that the Rust compiler doesn't do any stream fusion; rather the functional idioms are designed around iterators, which provide a functional interface that relatively easily and predictably compiles down to code that's as efficient as the corresponding for loop.
I wondered about that - Rust looks like the one systems programming language I would actually enjoy using, but I don't know enough about it to have an informed opinion.