Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

numbers = map(numbers, func(n int) int { return n * n })

for i, n := range numbers { numbers[i] = n * n }

Sorry, but I do not see a difference in the order of assembly language vs. high-level language.



The difference is small because map is trivial, but the implications of using higher order functions isn't. Even something like trees sees a divergence between the styles (not necessarily in the order of assembly language vs. high-level, but certainly more than you're making out).

Higher order functions are really useful for splitting apart navigation of a data structure and the processing of the data contained within it.

Given that you can use purely higher order functions for control flow, I wouldn't say one is more essential than the other.


Now try it on a more complex type. Then try and compose various operations. Then swap out the container type.


(Unfortunately, formatting is lost)

a) With a more complex type (I don't see how this would affect one more than the other)

Functional would be:

foos = map(foos, func(f Foo) Foo { return Foo{f.A * f.A, f.B * f.B} })

Iterative is:

for i, f := range foos { foos[i] = Foo{f.A * f.A, f.B * f.B} }

b) Composing various operations. Composing filter + map:

Functional would be:

x := filter(map(numbers, func(n int) int { return n * n }), func(n int) bool { return n % 2 == 0 })

Iterative is:

x := make([]int, 0); for _, n := range numbers { sq := n * n; if sq % 2 == 0 { x = append(x, sq) } }

c) Swapping the container type is just a matter of swapping "_, n := range numbers".


> With a more complex type (I don't see how this would affect one more than the other)

It does because the discussion is about generics. The fact that you're writing out types for one and not the other makes your comparisons a bit disingenuous, though I understand if Go isn't very good at functional programming.

b) Composing various operations. Composing filter + map:

As you keep building them up the imperative style will have more code overhead and less efficiency.

> c) Swapping the container type is just a matter of swapping "_, n := range numbers".

This isn't true since the functional one could easily swap out to use an infinite data source whereas the imperative will be constrained to the arrays you're already using.


a) Generics would not make the function signatures shorter. You would have to introduce yet another concept: type inference for the signatures of anonymous functions.

b) No, it will not be less efficient. It's all done within one loop, in-place. You can compose everything inside the body of the loop. A functional language would do the same if it's intelligent.

c) You can easily create an infinite data source in Go with the generator pattern:

numbers := make(chan int); go func() { for i := 0; ; i++ { numbers <- i } }()

for n := range numbers {...}


> Generics would not make the function signatures shorter. You would have to introduce yet another concept: type inference for the signatures of anonymous functions

Yes, I should have said type inference obviously. I can't think of a decent functional language that doesn't have type inference though.

> No, it will not be less efficient. It's all done within one loop, in-place. You can compose everything inside the body of the loop. A functional language would do the same if it's intelligent.

If it's all done in one loop then it isn't composing. It's writing custom code every time you need to do something.

> You can easily create an infinite data source in Go with the generator pattern:

That's nice, you only need to change all of your code to do so. The functional version doesn't have that problem.


================

Please note that if your comment thread starts getting squished against the right side of the page like this, it might be time to move the conversation off of HN.

================


An infinite data source? That sounds like a thunk (which is easy to implement), or perhaps it really is a channel?


The beauty is - it doesn't _matter_.

It could be a linked list that links back to it's own head. It could be a network stream, or a series of events from an input device. The program doesn't have to care.


You should read up on channels and generators then. The source doesn't matter, just the type contract.

It's a different way of approaching things. I'd say that golang was stream-based rather than functional or imperative.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: