top | item 27299634

(no title)

andolanra | 4 years ago

I think people have a habit of taking relatively surface-level features of functional programming and focusing on them to the exclusion of the real benefits of functional programming. The use of something like compose3 in the "functional" example here is a perfect example. Sure, function composition is a "functional" thing, but I don't see why you wouldn't instead write something like (handwaving wildly on the specifics, since I know barely any Go and certainly am not up to speed on the generics proposal):

    func getTopUsers(posts []Post) []UserLevelPoints {
            return posts.GroupBy(func (v Post) string { return v.Level })
                        .Values()
                        .Map(getTopUser)
    }
This pipeline style is significantly easier to read (especially without having to put all those extraneous type parameters in your call to compose3!) and doesn't actually lose any of the core advantages of the functional style: purity, testability in isolation, equational reasoning, and so forth. Sure, the Haskell equivalent might use composition… but composition reads more or less naturally in Haskell, and I don't think it does at all here in Go. If your specific approach to "functional programming" makes your code theoretically easier to reason about but practically harder to both read and write, then is it really helping you much?

discuss

order

platinumrad|4 years ago

Yeah if you're writing "Compose3" you've already lost. The extra type annotations only make it worse.

    x := foo()
    y := bar(x)
    z := baz(y)
Wow.

pharmakom|4 years ago

Ok, now what if foo, bar and bar are async? Nullable? Result types?

mappu|4 years ago

Piling on here - My impression of your snippet here is that GroupBy() and Values() both construct (potentially very large) temporary arrays on the stack.

Maybe Haskell and F# can elide this kind of thing, but it's not something the Go compiler is going to do.

Yoric|4 years ago

Rust and OCaml (the latter if you use the right libraries) can definitely avoid it. Why couldn't Go?

Serow225|4 years ago

FWIW C# would as well (LINQ)

mjburgess|4 years ago

Exactly my thought: why is this clearer?

I'm often think FP-first (data science) -- here though, I was surprised by how I went back over the imperative alternative.

Avoiding `append()` isnt worth it in a language where this level of annotation is required to do FP. It's less clear.