Reference · Utilities
Eq (Equality)
Type-safe equality checking. Define custom equality semantics for any type using the Eq type class.
Core API
| Function | Signature | Description |
|---|---|---|
FromEquals | func FromEquals[A any](func(A, A) bool) Eq[A] | Create Eq from function |
Contramap | func Contramap[A, B any](func(B) A) func(Eq[A]) Eq[B] | Derive Eq by mapping |
Usage Examples
Basic Usage
basic.go
import E "github.com/IBM/fp-go/v2/eq"
// Create equality from function
type User struct {
ID int
Name string
}
userEq := E.FromEquals(func(a, b User) bool {
return a.ID == b.ID
})
user1 := User{ID: 1, Name: "Alice"}
user2 := User{ID: 1, Name: "Alice Updated"}
userEq.Equals(user1, user2) // true - same ID
Built-in Eq Instances
builtin.go
import (
N "github.com/IBM/fp-go/v2/number"
S "github.com/IBM/fp-go/v2/string"
)
// Number equality
N.Eq.Equals(1, 1) // true
N.Eq.Equals(1, 2) // false
// String equality
S.Eq.Equals("hello", "hello") // true
S.Eq.Equals("hello", "world") // false
Contramap - Derive Equality
contramap.go
type User struct {
ID int
Name string
}
// Equality based on ID
userEq := E.Contramap(
func(u User) int { return u.ID },
)(N.Eq)
userEq.Equals(
User{ID: 1, Name: "Alice"},
User{ID: 1, Name: "Alice Updated"},
) // true - same ID
userEq.Equals(
User{ID: 1, Name: "Alice"},
User{ID: 2, Name: "Bob"},
) // false - different IDs
Case-Insensitive Equality
case_insensitive.go
// Case-insensitive string equality
caseInsensitiveEq := E.FromEquals(func(a, b string) bool {
return strings.ToLower(a) == strings.ToLower(b)
})
caseInsensitiveEq.Equals("Hello", "HELLO") // true
caseInsensitiveEq.Equals("Hello", "World") // false
Struct Field Equality
field.go
type Product struct {
SKU string
Name string
Price float64
}
// Compare by SKU only
productEq := E.Contramap(
func(p Product) string { return p.SKU },
)(S.Eq)
p1 := Product{SKU: "A123", Name: "Laptop", Price: 999}
p2 := Product{SKU: "A123", Name: "Laptop Pro", Price: 1299}
productEq.Equals(p1, p2) // true - same SKU
Approximate Float Equality
float.go
// Approximate equality for floats
const epsilon = 0.0001
floatEq := E.FromEquals(func(a, b float64) bool {
return math.Abs(a-b) < epsilon
})
floatEq.Equals(3.14159, 3.14160) // true - within epsilon
floatEq.Equals(3.14159, 3.15000) // false - outside epsilon
Array Equality
array.go
import A "github.com/IBM/fp-go/v2/array"
// Equality for arrays
arrayEq := A.Eq(N.Eq)
arr1 := []int{1, 2, 3}
arr2 := []int{1, 2, 3}
arr3 := []int{1, 2, 4}
arrayEq.Equals(arr1, arr2) // true
arrayEq.Equals(arr1, arr3) // false
Common Patterns
Testing Helper
testing.go
func AssertEqual[A any](
t *testing.T,
eq E.Eq[A],
expected, actual A,
) {
if !eq.Equals(expected, actual) {
t.Errorf("Not equal:
Expected: %v
Actual: %v",
expected, actual)
}
}
// Usage in tests
func TestSomething(t *testing.T) {
expected := User{ID: 1, Name: "Alice"}
actual := fetchUser(1)
AssertEqual(t, userEq, expected, actual)
}
Semantic Equality
semantic.go
type Status string
const (
Active Status = "active"
Inactive Status = "inactive"
Enabled Status = "enabled"
Disabled Status = "disabled"
)
// Treat active/enabled and inactive/disabled as equal
statusEq := E.FromEquals(func(a, b Status) bool {
normalize := func(s Status) string {
if s == Active || s == Enabled {
return "active"
}
return "inactive"
}
return normalize(a) == normalize(b)
})
statusEq.Equals(Active, Enabled) // true
statusEq.Equals(Inactive, Disabled) // true
statusEq.Equals(Active, Inactive) // false
Composite Equality
composite.go
type Address struct {
Street string
City string
Zip string
}
// Equality based on city and zip only
addressEq := E.FromEquals(func(a, b Address) bool {
return a.City == b.City && a.Zip == b.Zip
})
addr1 := Address{Street: "123 Main St", City: "NYC", Zip: "10001"}
addr2 := Address{Street: "456 Oak Ave", City: "NYC", Zip: "10001"}
addressEq.Equals(addr1, addr2) // true - same city and zip
Contramap: Use Contramap to derive equality from existing Eq instances. It's more composable than writing custom equality functions.
Use Cases: Custom Eq instances are useful for:
- Domain-specific equality (e.g., case-insensitive strings)
- Approximate numeric equality
- Comparing by specific fields
- Testing and assertions