Skip to main content
Version: v2.2.82 (latest)
v2 · Utilities

Monoid Identity & Combination

A monoid is a semigroup with an identity element, providing both a way to combine values and a default/empty value.


Overview

A Monoid extends Semigroup by adding an identity element (also called "empty" or "zero"). This identity element acts as a neutral value for the binary operation.

Key Properties:

  • Associative: (a • b) • c = a • (b • c) (from Semigroup)
  • Left Identity: empty • a = a
  • Right Identity: a • empty = a

The identity element makes monoids perfect for folding/reducing operations, as you always have a safe starting value.


Basic Usage

monoid_basic.go
import M "github.com/IBM/fp-go/monoid"

// Create a string concatenation monoid
stringMonoid := M.MakeMonoid(
  func(a, b string) string { return a + b },  // Concat operation
  "",  // Identity element (empty string)
)

result := stringMonoid.Concat("Hello", " World")
// "Hello World"

empty := stringMonoid.Empty()
// ""

// Identity laws hold
s1 := stringMonoid.Concat(empty, "test")  // "test"
s2 := stringMonoid.Concat("test", empty)  // "test"
// s1 == s2 == "test"

Built-in Monoids

fp-go provides several built-in monoids for common types:

monoid_builtin.go
import (
  N "github.com/IBM/fp-go/number"
  S "github.com/IBM/fp-go/string"
)

// Number addition monoid (identity: 0)
sum := N.MonoidSum.Concat(1, 2)  // 3
zero := N.MonoidSum.Empty()      // 0

// Number multiplication monoid (identity: 1)
product := N.MonoidProduct.Concat(3, 4)  // 12
one := N.MonoidProduct.Empty()           // 1

// String concatenation monoid (identity: "")
text := S.Monoid.Concat("Hello", " World")  // "Hello World"
emptyStr := S.Monoid.Empty()                // ""

// Min/Max monoids
minVal := N.MonoidMin.Concat(5, 3)  // 3
maxVal := N.MonoidMax.Concat(5, 3)  // 5

Folding with Monoids

Monoids are perfect for folding/reducing collections:

monoid_fold.go
import (
  A "github.com/IBM/fp-go/array"
  F "github.com/IBM/fp-go/function"
  N "github.com/IBM/fp-go/number"
)

// Sum array of numbers
numbers := []int{1, 2, 3, 4, 5}
sum := F.Pipe2(
  numbers,
  A.Fold(N.MonoidSum),
)
// 15

// Product of numbers
product := F.Pipe2(
  numbers,
  A.Fold(N.MonoidProduct),
)
// 120

// Empty array uses identity
emptySum := F.Pipe2(
  []int{},
  A.Fold(N.MonoidSum),
)
// 0 (identity element)

Configuration Merging

Use monoids to merge configurations:

monoid_config.go
type Config struct {
  Timeout int
  Retries int
  Debug   bool
}

// Max-merge strategy with defaults
configMonoid := M.MakeMonoid(
  func(a, b Config) Config {
      return Config{
          Timeout: max(a.Timeout, b.Timeout),
          Retries: max(a.Retries, b.Retries),
          Debug:   a.Debug || b.Debug,
      }
  },
  Config{Timeout: 0, Retries: 0, Debug: false},  // Identity
)

// Merge multiple configs
configs := []Config{
  {Timeout: 30, Retries: 3, Debug: false},  // defaults
  {Timeout: 0, Retries: 5, Debug: false},   // env config
  {Timeout: 60, Retries: 0, Debug: true},   // user config
}

final := F.Pipe2(
  configs,
  A.Fold(configMonoid),
)
// Config{Timeout: 60, Retries: 5, Debug: true}

Aggregating Statistics

Combine statistics from multiple sources:

monoid_stats.go
type Stats struct {
  Count int
  Total float64
  Min   float64
  Max   float64
}

statsMonoid := M.MakeMonoid(
  func(a, b Stats) Stats {
      return Stats{
          Count: a.Count + b.Count,
          Total: a.Total + b.Total,
          Min:   min(a.Min, b.Min),
          Max:   max(a.Max, b.Max),
      }
  },
  Stats{
      Count: 0,
      Total: 0.0,
      Min:   math.MaxFloat64,
      Max:   -math.MaxFloat64,
  },
)

// Aggregate stats from multiple sources
allStats := []Stats{
  {Count: 10, Total: 100.0, Min: 5.0, Max: 20.0},
  {Count: 15, Total: 225.0, Min: 3.0, Max: 25.0},
  {Count: 8, Total: 80.0, Min: 7.0, Max: 15.0},
}

combined := F.Pipe2(
  allStats,
  A.Fold(statsMonoid),
)
// Stats{Count: 33, Total: 405.0, Min: 3.0, Max: 25.0}

API Reference

FunctionTypeDescription
MakeMonoid[A](func(A, A) A, A) -> Monoid[A]Creates a monoid from concat and empty
Concat(A, A) -> ACombines two values (from Semigroup)
Empty() -> AReturns the identity element

Built-in Monoids:

MonoidPackageOperationIdentity
MonoidSumnumberAddition0
MonoidProductnumberMultiplication1
MonoidMinnumberMinimumMaxInt
MonoidMaxnumberMaximumMinInt
MonoidstringConcatenation""

Related Concepts

Algebraic Hierarchy:

  • MagmaSemigroupMonoidGroup
  • Monoid adds identity element to Semigroup
  • Group adds inverse operation to Monoid

Common Use Cases:

  • Folding/reducing collections
  • Merging configurations
  • Aggregating statistics
  • Combining results from parallel operations

See Also: