1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-25 22:21:49 +02:00
Files
fp-go/v2/monoid/doc.go
Carsten Leue 3385c705dc Implement v2 using type aliases (#141)
* fix: initial checkin of v2

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: slowly migrate IO

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: migrate MonadTraverseArray and TraverseArray

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: migrate traversal

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: complete migration of IO

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: migrate ioeither

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: refactorY

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: next step in migration

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: adjust IO generation code

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: get rid of more IO methods

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: get rid of more IO

* fix: convert iooption

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: convert reader

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: convert a bit of reader

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: new build script

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: cleanup

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: reformat

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: simplify

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: some cleanup

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: adjust Pair to Haskell semantic

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: documentation and testcases

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: some performance optimizations

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: remove coverage

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: better doc

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

---------

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00

359 lines
8.6 KiB
Go

// Copyright (c) 2023 - 2025 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package monoid provides the Monoid algebraic structure.
# Overview
A Monoid is a Semigroup with an identity element (called Empty). It extends
the Magma → Semigroup hierarchy by adding a neutral element that doesn't
change other elements when combined with them.
The Monoid interface:
type Monoid[A any] interface {
Semigroup[A] // Provides Concat(x, y A) A
Empty() A // Identity element
}
Monoid laws:
- Associativity (from Semigroup): Concat(Concat(x, y), z) = Concat(x, Concat(y, z))
- Left identity: Concat(Empty(), x) = x
- Right identity: Concat(x, Empty()) = x
# Algebraic Hierarchy
Magma (binary operation)
Semigroup (associative)
Monoid (identity element)
# Basic Usage
Creating monoids for common types:
// Integer addition monoid (identity: 0)
addMonoid := monoid.MakeMonoid(
func(a, b int) int { return a + b },
0,
)
result := addMonoid.Concat(5, 3) // 8
empty := addMonoid.Empty() // 0
// Verify identity laws
assert.Equal(t, 5, addMonoid.Concat(addMonoid.Empty(), 5)) // Left identity
assert.Equal(t, 5, addMonoid.Concat(5, addMonoid.Empty())) // Right identity
// Integer multiplication monoid (identity: 1)
mulMonoid := monoid.MakeMonoid(
func(a, b int) int { return a * b },
1,
)
result := mulMonoid.Concat(5, 3) // 15
empty := mulMonoid.Empty() // 1
// String concatenation monoid (identity: "")
stringMonoid := monoid.MakeMonoid(
func(a, b string) string { return a + b },
"",
)
result := stringMonoid.Concat("Hello", " World") // "Hello World"
empty := stringMonoid.Empty() // ""
# Array Operations
ConcatAll - Combines all elements using the monoid's empty as starting value:
addMonoid := monoid.MakeMonoid(
func(a, b int) int { return a + b },
0,
)
numbers := []int{1, 2, 3, 4, 5}
sum := monoid.ConcatAll(addMonoid)(numbers)
// sum is 15 (0 + 1 + 2 + 3 + 4 + 5)
// Empty slice returns the identity
empty := monoid.ConcatAll(addMonoid)([]int{})
// empty is 0
Fold - Alias for ConcatAll:
mulMonoid := monoid.MakeMonoid(
func(a, b int) int { return a * b },
1,
)
numbers := []int{2, 3, 4}
product := monoid.Fold(mulMonoid)(numbers)
// product is 24 (1 * 2 * 3 * 4)
GenericConcatAll - Works with custom slice types:
type IntSlice []int
addMonoid := monoid.MakeMonoid(
func(a, b int) int { return a + b },
0,
)
numbers := IntSlice{1, 2, 3}
sum := monoid.GenericConcatAll[IntSlice](addMonoid)(numbers)
// sum is 6
# Transforming Monoids
Reverse - Swaps the order of arguments:
subMonoid := monoid.MakeMonoid(
func(a, b int) int { return a - b },
0,
)
reversedMonoid := monoid.Reverse(subMonoid)
result1 := subMonoid.Concat(10, 3) // 10 - 3 = 7
result2 := reversedMonoid.Concat(10, 3) // 3 - 10 = -7
ToSemigroup - Converts a Monoid to a Semigroup:
m := monoid.MakeMonoid(
func(a, b int) int { return a + b },
0,
)
sg := monoid.ToSemigroup(m)
result := sg.Concat(5, 3) // 8
# Function Monoid
FunctionMonoid - Creates a monoid for functions when the codomain has a monoid:
// Monoid for functions that return integers
intAddMonoid := monoid.MakeMonoid(
func(a, b int) int { return a + b },
0,
)
funcMonoid := monoid.FunctionMonoid[string, int](intAddMonoid)
f1 := func(s string) int { return len(s) }
f2 := func(s string) int { return len(s) * 2 }
// Combine functions: result(x) = f1(x) + f2(x)
combined := funcMonoid.Concat(f1, f2)
result := combined("hello") // len("hello") + len("hello")*2 = 5 + 10 = 15
// Empty function always returns the monoid's empty
emptyFunc := funcMonoid.Empty()
result := emptyFunc("anything") // 0
# Applicative Monoid
ApplicativeMonoid - Lifts a monoid into an applicative functor:
// This is used internally for combining applicative effects
// Example with Option-like types:
type Option[A any] struct {
value *A
}
func Some[A any](a A) Option[A] {
return Option[A]{value: &a}
}
func None[A any]() Option[A] {
return Option[A]{value: nil}
}
// Define applicative operations for Option
// Then use ApplicativeMonoid to combine Option values
# Alternative Monoid
AltMonoid - Creates a monoid from an Alt type class:
// For types with alternative/fallback semantics
// Used with Option, Either, etc. to provide fallback behavior
AlternativeMonoid - Combines applicative and alternative:
// Advanced usage for types that are both Applicative and Alternative
// Provides rich composition of effects with fallback
# Practical Examples
Boolean AND monoid:
andMonoid := monoid.MakeMonoid(
func(a, b bool) bool { return a && b },
true, // Identity: true AND x = x
)
values := []bool{true, true, true}
result := monoid.ConcatAll(andMonoid)(values) // true
values2 := []bool{true, false, true}
result2 := monoid.ConcatAll(andMonoid)(values2) // false
Boolean OR monoid:
orMonoid := monoid.MakeMonoid(
func(a, b bool) bool { return a || b },
false, // Identity: false OR x = x
)
values := []bool{false, false, false}
result := monoid.ConcatAll(orMonoid)(values) // false
values2 := []bool{false, true, false}
result2 := monoid.ConcatAll(orMonoid)(values2) // true
Max monoid (with bounded integers):
maxMonoid := monoid.MakeMonoid(
func(a, b int) int {
if a > b {
return a
}
return b
},
math.MinInt, // Identity: smallest possible int
)
numbers := []int{3, 7, 2, 9, 1}
maximum := monoid.ConcatAll(maxMonoid)(numbers) // 9
Min monoid (with bounded integers):
minMonoid := monoid.MakeMonoid(
func(a, b int) int {
if a < b {
return a
}
return b
},
math.MaxInt, // Identity: largest possible int
)
numbers := []int{3, 7, 2, 9, 1}
minimum := monoid.ConcatAll(minMonoid)(numbers) // 1
List concatenation monoid:
listMonoid := monoid.MakeMonoid(
func(a, b []int) []int {
result := make([]int, len(a)+len(b))
copy(result, a)
copy(result[len(a):], b)
return result
},
[]int{}, // Identity: empty slice
)
lists := [][]int{{1, 2}, {3, 4}, {5}}
flattened := monoid.ConcatAll(listMonoid)(lists)
// flattened is []int{1, 2, 3, 4, 5}
# Monoid Laws
All monoid instances must satisfy these laws:
1. Associativity (from Semigroup):
Concat(Concat(x, y), z) = Concat(x, Concat(y, z))
2. Left Identity:
Concat(Empty(), x) = x
3. Right Identity:
Concat(x, Empty()) = x
Example verification:
m := monoid.MakeMonoid(
func(a, b int) int { return a + b },
0,
)
// Associativity
assert.Equal(t,
m.Concat(m.Concat(1, 2), 3),
m.Concat(1, m.Concat(2, 3)),
) // Both equal 6
// Left identity
assert.Equal(t, 5, m.Concat(m.Empty(), 5))
// Right identity
assert.Equal(t, 5, m.Concat(5, m.Empty()))
# Common Monoids
Additive monoid (integers):
- Concat: addition
- Empty: 0
Multiplicative monoid (integers):
- Concat: multiplication
- Empty: 1
String monoid:
- Concat: concatenation
- Empty: ""
List monoid:
- Concat: list concatenation
- Empty: []
Boolean AND monoid:
- Concat: logical AND
- Empty: true
Boolean OR monoid:
- Concat: logical OR
- Empty: false
# Functions
Core operations:
- MakeMonoid[A any](func(A, A) A, A) - Create a monoid
- Reverse[A any](Monoid[A]) - Swap argument order
- ToSemigroup[A any](Monoid[A]) - Convert to semigroup
Array operations:
- ConcatAll[A any](Monoid[A]) - Combine all elements
- Fold[A any](Monoid[A]) - Alias for ConcatAll
- GenericConcatAll[GA ~[]A, A any](Monoid[A]) - Generic version
Higher-order:
- FunctionMonoid[A, B any](Monoid[B]) - Monoid for functions
- ApplicativeMonoid[A, HKTA, HKTFA any](...) - Lift into applicative
- AltMonoid[HKTA any, LAZYHKTA ~func() HKTA](...) - From Alt type class
- AlternativeMonoid[A, HKTA, HKTFA any, LAZYHKTA ~func() HKTA](...) - Applicative + Alternative
# Related Packages
- semigroup: Parent structure (associative binary operation)
- magma: Grandparent structure (binary operation)
*/
package monoid