DEV Community

Cover image for 7 Easy functional programming techniques in Go

7 Easy functional programming techniques in Go

Deepu K Sasidharan on August 14, 2019

Originally published at deepu.tech. There is a lot of hype around functional programming(FP) and a lot of cool kids are doing it but it is not a s...
Collapse
 
derek profile image
derek • Edited

I think the situation will dictate the technique.

I definitely think there's a lot of merit to functional programming, and even in usage with go; but perhaps sparingly. Sparingly... meaning maybe it won't be the first thing I reach for when coding go 🤷🏽‍♂️. Due to its type system it's definitely a little bit harder to get more milage out of functional programming like python, javascript, haskell, elm, etc. But you're right perhaps we'll see an evolution of Go and its community and how we write go in the coming years (v2).

I usually regurgitate Uncle Bill's motto "optimize for correctness"

Here's a suggestion to reduce allocations for your mapForEach:

func mapForEach(arr []string, fn func(it string) int) []int {
    out := make([]int, len(arr))
    for i, it := range arr {
        out[i] = len(it)
    }
    return out
}

bench

Collapse
 
deepu105 profile image
Deepu K Sasidharan

Thanks. Nice catch. I wasn't focusing on performance as it was just sample code.

Collapse
 
derek profile image
derek

Gotcha!

I forgot to open my reply with: First off... Thank you for sharing your findings and knowledge!

Collapse
 
bootcode profile image
Robin Palotai

While I like FP, these practices go directly against Go style. If someone applies this FP style, reviewers will be very unhappy.

In Go, a for loop is a for loop, they would say. They would even be bity for pulling a for loop out into a method sometimes (let alone recursion).

Based on my own experience as a novice writer of occasional Go code.

Collapse
 
deepu105 profile image
Deepu K Sasidharan

I don't think any of this actually goes against Go style. What makes you think this is against Go style, Go supports recursion and hence you can always choose between looping and recursion based on the use case. Lazy eval is the only thing that looks hacky IMO, that's why I mentioned to use it only if the methods are heavy.

Collapse
 
bootcode profile image
Robin Palotai • Edited

You are right, I can't state it with a solid resource.

My impression about the language was that one of its intent is to keep code in front of the developer's face. Abstractions that introduce indirection are not as welcome as in, say, Java.

I would say the immutable data usage surely can't hurt. Other functional constructs deviate more from the KISS agenda of Go.

I don't say don't do it. As a mental exercise it is interesting. If your team is with you, sure. On a public project however, don't get surprised if selling the style would be hard.

Looking forward to your experience!

Edit: See twitter.com/bootcode/status/116161... for a balanced feedback.

Thread Thread
 
deepu105 profile image
Deepu K Sasidharan

FP can be useful as long as you don't overdo it. I personally like functional composition/HoF/closures and so on. Avoiding data mutation and using pure functions can only add value most of the times. Stuff like recursion, Lazy eval is definitely on a need basis and can be ugly if overused. But if you are coming to Go from a functional background you can always do things(almost) the way you are used to.

It's all about personal preferences anyway. IMO we should use good concepts from every paradigm(FP, OOP and imperative)

Collapse
 
the2bears profile image
William Swaney

I don't think that's really "currying", just a higher order function that takes one argument ("x") returning a different function that closes around the value of "x".

Collapse
 
deepu105 profile image
Deepu K Sasidharan

As far as I know, that is exactly what currying is en.m.wikipedia.org/wiki/Currying?w.... Care to explain why you think its not

Collapse
 
the2bears profile image
William Swaney • Edited

The code certainly performs the task of currying in a limited subset of my impression of the meaning. I agree, that in this case you have a function (add) that takes two arguments and you supply the first, returning a function that only requires the second argument.

When I think of currying, though, I think more of how Haskell supports it, where it's automatic and baked right into the language. You might have:

my-fun :: Integer ->  Integer -> Integer -> Integer

This is a function that takes 3 Integers, returning an Integer. In this case, (my-fun 10) is a function taking 2 integers, returning one. This can be done as you showed, with a series of higher order functions, but it has to be explicitly done.

A more interesting problem is how to deal with functions that have multi-arity? It can be done, again, with lots of explicit creation of what turns out to be a lot of boiler plate.

Anyway, sorry if my original post was curt. Your "add" example shows some of what I consider currying, but I don't think Go, Scala, Clojure, etc. can do it all (at least easily) so I think it's better describing this as using higher order functions.

Thread Thread
 
deepu105 profile image
Deepu K Sasidharan

Currying is a concept and is definitely not based on how Haskel does it AFAIK. You can do currying even in Java using lambda and stuff. The idea is to make the concept possible and not in the syntax IMO