Advanced Functional Programming in Go

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 Level

\n\n

Go (Golang) is not a purely functional language, but its powerful type system, support for closures, and first-class functions allow functional paradigms to be applied effectively. At an advanced level, functional programming in Go helps write more predictable, testable, and concurrency-safe code. In this article, we will explore key concepts: pure functions, composition, closures, currying, monadic patterns, and error handling without exceptions.

\n\n

1. Pure Functions and Immutability

\n\n

A pure function is a function that:

\n
    \n
  • Always returns the same result for the same arguments (determinism).
  • \n
  • Has no side effects (does not modify external state, does not write to files/network).
  • \n
\n\n

In Go, immutability is achieved by passing copies of data and using constants. Example of a pure function:

\n\n
package main\n\nimport "fmt"\n\n// Pure function: does not modify the original slice, returns a new one\nfunc DoubleSlice(s []int) []int {\n    result := make([]int, len(s))\n    for i, v := range s {\n        result[i] = v * 2\n    }\n    return result\n}\n\nfunc main() {\n    original := []int{1, 2, 3}\n    doubled := DoubleSlice(original)\n    fmt.Println(original) // [1 2 3] — unchanged\n    fmt.Println(doubled)  // [2 4 6]\n}
\n\n

Using pure functions simplifies refactoring and testing, as there is no hidden state to account for.

\n\n

2. Higher-Order Functions and Closures

\n\n

In Go, functions are first-class objects: they can be passed as arguments, returned from other functions, and stored in variables. A closure is a function that captures variables from its outer scope.

\n\n

Example of a higher-order function — Filter:

\n\n
package main\n\nimport "fmt"\n\n// Filter returns a new slice containing elements that satisfy the predicate\nfunc Filter[T any](s []T, predicate func(T) bool) []T {\n    var result []T\n    for _, v := range s {\n        if predicate(v) {\n            result = append(result, v)\n        }\n    }\n    return result\n}\n\nfunc main() {\n    numbers := []int{1, 2, 3, 4, 5, 6}\n    even := Filter(numbers, func(n int) bool { return n%2 == 0 })\n    fmt.Println(even) // [2 4 6]\n}
\n\n

Closures are often used to create function factories or to encapsulate state:

\n\n
package main\n\nimport "fmt"\n\n// Counter creates a closure that stores internal state\nfunc Counter() func() int {\n    count := 0\n    return func() int {\n        count++\n        return count\n    }\n}\n\nfunc main() {\n    c1 := Counter()\n    fmt.Println(c1()) // 1\n    fmt.Println(c1()) // 2\n\n    c2 := Counter()\n    fmt.Println(c2()) // 1 — independent state\n}
\n\n

3. Function Composition and Partial Application (Currying)

\n\n

Composition is combining multiple functions into one new function. In Go, composition is implemented through intermediate functions. Partial application (currying) allows fixing some arguments and returning a function that expects the remaining ones.

\n\n

Example of composition:

\n\n
package main\n\nimport "fmt"\n\n// Compose combines two functions: f(g(x))\nfunc Compose[A, B, C any](f func(B) C, g func(A) B) func(A) C {\n    return func(x A) C {\n        return f(g(x))\n    }\n}\n\nfunc addOne(x int) int { return x + 1 }\nfunc double(x int) int { return x * 2 }\n\nfunc main() {\n    addThenDouble := Compose(double, addOne)\n    fmt.Println(addThenDouble(3)) // (3+1)*2 = 8\n}
\n\n

Currying example with a sum function:

\n\n
package main\n\nimport "fmt"\n\n// Add — curried version of addition\nfunc Add(a int) func(int) int {\n    return func(b int) int {\n        return a + b\n    }\n}\n\nfunc main() {\n    addFive := Add(5)\n    fmt.                

Blogs

Book Recommendations