Functional Programming in Go: Advanced Techniques and Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Functional Programming in Go: Advanced Techniques and Examples



Go (Golang) was not originally designed as a purely functional language, but its powerful features such as closures, first-class functions, and goroutines allow you to successfully apply the functional programming (FP) paradigm at an advanced level. This article is intended for developers already familiar with the basics of Go who want to delve deeper into functional techniques for writing more predictable, testable, and concurrent code. We will look at currying, function composition, working with monad-like structures, and integrating FP with goroutines.



1. Currying and Partial Application of Functions



Currying is the transformation of a function that takes multiple arguments into a sequence of functions, each taking a single argument. In Go, which has no built-in support for currying, we implement it through closures.



Example: currying for a configurable logger



package main

import "fmt"

// Curried function: prefix -> message -> outputfunc createLogger(prefix string) func(string) { return func(message string) { fmt.Printf("[%s] %s", prefix, message) }}

func main() { infoLogger := createLogger("INFO") errorLogger := createLogger("ERROR")

infoLogger("System started") errorLogger("Connection error") // Output: // [INFO] System started // [ERROR] Connection error}


Partial application is a special case of currying where we fix some of the arguments. In Go, this is especially useful for creating specialized versions of functions.



// Partial application: fix the coefficientfunc multiply(a, b int) int {    return a * b}

func partialMultiply(a int) func(int) int { return func(b int) int { return multiply(a, b) }}

func main() { double := partialMultiply(2) triple := partialMultiply(3)

fmt.Println(double(5)) // 10 fmt.Println(triple(5)) // 15}


2. Function Composition and Pipelines



Composition is combining simple functions into more complex ones. In Go, we can build chains of transformations by passing the result of one function as input to another. This works especially powerfully in combination with interfaces and generics (Go 1.18+).



Example: composition for string processing



package main

import ( "fmt" "strings" "unicode")

type StringTransform func(string) string

// Compose creates a composition of two functionsfunc Compose(f, g StringTransform) StringTransform { return func(s string) string { return f(g(s)) }}

// Pipeline combines multiple functionsfunc Pipeline(transforms ...StringTransform) StringTransform { return func(s string) string { for _, t := range transforms { s = t(s) } return s }}

func removeSpaces(s string) string { return strings.ReplaceAll(s, " ", "")}

func toUpper(s string) string { return strings.ToUpper(s)}

func removeDigits(s string) string { var result strings.Builder for _, r := range s { if !unicode.IsDigit(r) { result.WriteRune(r) } } return result.String()}

func main() { // Composition of two functions cleanAndUpper := Compose(removeSpaces, toUpper) result1 := cleanAndUpper("go 1.18 rocks") fmt.Println(result1) // "GO1.18ROCKS"

// Pipeline of three functions pipeline := Pipeline(removeSpaces, removeDigits, toUpper) result2 := pipeline("go 1.18 rocks") fmt.Println(result2) // "GOROCKS"}


This approach allows you to build complex transformations from simple, testable blocks. Each pipeline function can be tested separately.



3. Monad-like Structures: Work

Blogs

Book Recommendations