pair

package
v2.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2025 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package pair provides a strongly-typed data structure for holding two values with functional operations.

Overview

A Pair is a data structure that holds exactly two values of potentially different types. Unlike tuples which are position-based, Pair provides semantic operations for working with "head" and "tail" (or "first" and "second") values, along with rich functional programming capabilities including Functor, Applicative, and Monad operations.

The Pair type:

type Pair[A, B any] struct {
    h, t any  // head and tail (internal)
}

Basic Usage

Creating pairs:

// Create a pair from two values
p := pair.MakePair("hello", 42)  // Pair[string, int]

// Create a pair with the same value in both positions
p := pair.Of(5)  // Pair[int, int]{5, 5}

// Convert from tuple
t := tuple.MakeTuple2("world", 100)
p := pair.FromTuple(t)  // Pair[string, int]

Accessing values:

p := pair.MakePair("hello", 42)

head := pair.Head(p)    // "hello"
tail := pair.Tail(p)    // 42

// Alternative names
first := pair.First(p)  // "hello" (same as Head)
second := pair.Second(p) // 42 (same as Tail)

Transforming Pairs

Map operations transform one or both values:

p := pair.MakePair(5, "hello")

// Map the tail (second) value
p2 := pair.MonadMapTail(p, func(s string) int {
    return len(s)
})  // Pair[int, int]{5, 5}

// Map the head (first) value
p3 := pair.MonadMapHead(p, func(n int) string {
    return fmt.Sprintf("%d", n)
})  // Pair[string, string]{"5", "hello"}

// Map both values
p4 := pair.MonadBiMap(p,
    func(n int) string { return fmt.Sprintf("%d", n) },
    func(s string) int { return len(s) },
)  // Pair[string, int]{"5", 5}

Curried versions for composition:

import F "github.com/IBM/fp-go/v2/function"

// Create a mapper function
doubleHead := pair.MapHead[string](func(n int) int {
    return n * 2
})

p := pair.MakePair(5, "hello")
result := doubleHead(p)  // Pair[int, string]{10, "hello"}

// Compose multiple transformations
transform := F.Flow2(
    pair.MapHead[string](N.Mul(2)),
    pair.MapTail[int](func(s string) int { return len(s) }),
)
result := transform(p)  // Pair[int, int]{10, 5}

Swapping

Swap exchanges the head and tail values:

p := pair.MakePair("hello", 42)
swapped := pair.Swap(p)  // Pair[int, string]{42, "hello"}

Monadic Operations

Pair supports monadic operations on both head and tail, requiring a Semigroup for combining values:

import (
    SG "github.com/IBM/fp-go/v2/semigroup"
    N "github.com/IBM/fp-go/v2/number"
)

// Chain on the tail (requires semigroup for head)
intSum := N.SemigroupSum[int]()

p := pair.MakePair(5, "hello")
result := pair.MonadChainTail(intSum, p, func(s string) pair.Pair[int, int] {
    return pair.MakePair(len(s), len(s) * 2)
})  // Pair[int, int]{10, 10} (5 + 5 from semigroup, 10 from function)

// Chain on the head (requires semigroup for tail)
strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b })

p2 := pair.MakePair(5, "hello")
result2 := pair.MonadChainHead(strConcat, p2, func(n int) pair.Pair[string, string] {
    return pair.MakePair(fmt.Sprintf("%d", n), "!")
})  // Pair[string, string]{"5", "hello!"}

Curried versions:

intSum := N.SemigroupSum[int]()
chain := pair.ChainTail(intSum, func(s string) pair.Pair[int, int] {
    return pair.MakePair(len(s), len(s) * 2)
})

p := pair.MakePair(5, "hello")
result := chain(p)  // Pair[int, int]{10, 10}

Applicative Operations

Apply functions wrapped in pairs to values in pairs:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()

// Function in a pair
pf := pair.MakePair(10, func(s string) int { return len(s) })

// Value in a pair
pv := pair.MakePair(5, "hello")

// Apply (on tail)
result := pair.MonadApTail(intSum, pf, pv)
// Pair[int, int]{15, 5} (10+5 from semigroup, len("hello") from function)

// Apply (on head)
strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b })
pf2 := pair.MakePair(func(n int) string { return fmt.Sprintf("%d", n) }, "!")
pv2 := pair.MakePair(42, "hello")

result2 := pair.MonadApHead(strConcat, pf2, pv2)
// Pair[string, string]{"42", "!hello"}

Function Conversion

Convert between regular functions and pair-taking functions:

// Regular function
add := func(a, b int) int { return a + b }

// Convert to pair-taking function
pairedAdd := pair.Paired(add)
result := pairedAdd(pair.MakePair(3, 4))  // 7

// Convert back
unpairedAdd := pair.Unpaired(pairedAdd)
result = unpairedAdd(3, 4)  // 7

Merge curried functions:

// Curried function
add := func(b int) func(a int) int {
    return func(a int) int { return a + b }
}

// Apply to pair
merge := pair.Merge(add)
result := merge(pair.MakePair(3, 4))  // 7 (applies 4 then 3)

Equality

Compare pairs for equality:

import (
    EQ "github.com/IBM/fp-go/v2/eq"
)

// Create equality for pairs
pairEq := pair.Eq(
    EQ.FromStrictEquals[string](),
    EQ.FromStrictEquals[int](),
)

p1 := pair.MakePair("hello", 42)
p2 := pair.MakePair("hello", 42)
p3 := pair.MakePair("world", 42)

pairEq.Equals(p1, p2)  // true
pairEq.Equals(p1, p3)  // false

For comparable types:

pairEq := pair.FromStrictEquals[string, int]()

p1 := pair.MakePair("hello", 42)
p2 := pair.MakePair("hello", 42)

pairEq.Equals(p1, p2)  // true

Tuple Conversion

Convert between Pair and Tuple2:

import "github.com/IBM/fp-go/v2/tuple"

// Pair to Tuple
p := pair.MakePair("hello", 42)
t := pair.ToTuple(p)  // Tuple2[string, int]

// Tuple to Pair
t := tuple.MakeTuple2("world", 100)
p := pair.FromTuple(t)  // Pair[string, int]

Type Class Instances

Pair provides type class instances for functional programming:

Functor - Map over values:

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

// Functor for tail
functor := pair.FunctorTail[int, string, int]()
mapper := functor.Map(func(s string) int { return len(s) })

p := pair.MakePair(5, "hello")
result := mapper(p)  // Pair[int, int]{5, 5}

Pointed - Wrap values:

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

// Pointed for tail (requires monoid for head)
intSum := M.MonoidSum[int]()
pointed := pair.PointedTail[string](intSum)

p := pointed.Of("hello")  // Pair[int, string]{0, "hello"}

Applicative - Apply wrapped functions:

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

intSum := M.MonoidSum[int]()
applicative := pair.ApplicativeTail[string, int, int](intSum)

// Create a pair with a function
pf := applicative.Of(func(s string) int { return len(s) })

// Apply to a value
pv := pair.MakePair(5, "hello")
result := applicative.Ap(pv)(pf)  // Pair[int, int]{5, 5}

Monad - Chain operations:

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

intSum := M.MonoidSum[int]()
monad := pair.MonadTail[string, int, int](intSum)

p := monad.Of("hello")
result := monad.Chain(func(s string) pair.Pair[int, int] {
    return pair.MakePair(len(s), len(s) * 2)
})(p)  // Pair[int, int]{5, 10}

Practical Examples

Example 1: Accumulating Results with Context

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

// Process items while accumulating a count
intSum := N.SemigroupSum[int]()

processItem := func(item string) pair.Pair[int, string] {
    return pair.MakePair(1, strings.ToUpper(item))
}

items := []string{"hello", "world", "foo"}
initial := pair.MakePair(0, "")

result := F.Pipe2(
    items,
    A.Map(processItem),
    A.Reduce(func(acc, curr pair.Pair[int, string]) pair.Pair[int, string] {
        return pair.MonadBiMap(
            pair.MakePair(
                pair.First(acc) + pair.First(curr),
                pair.Second(acc) + " " + pair.Second(curr),
            ),
            F.Identity[int],
            strings.TrimSpace,
        )
    }, initial),
)
// Result: Pair[int, string]{3, "HELLO WORLD FOO"}

Example 2: Tracking Computation Steps

type Log []string

logConcat := SG.MakeSemigroup(func(a, b Log) Log {
    return append(a, b...)
})

compute := func(n int) pair.Pair[Log, int] {
    return pair.MakePair(
        Log{fmt.Sprintf("computed %d", n)},
        n * 2,
    )
}

p := pair.MakePair(Log{"start"}, 5)
result := pair.MonadChainTail(logConcat, p, compute)
// Pair[Log, int]{
//     []string{"start", "computed 5"},
//     10
// }

Example 3: Writer Monad Pattern

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

// Use pair as a writer monad
stringMonoid := M.MakeMonoid(
    func(a, b string) string { return a + b },
    "",
)

monad := pair.MonadTail[string, string, int](stringMonoid)

// Log and compute
logAndDouble := func(n int) pair.Pair[string, int] {
    return pair.MakePair(
        fmt.Sprintf("doubled %d; ", n),
        n * 2,
    )
}

logAndAdd := func(n int) pair.Pair[string, int] {
    return pair.MakePair(
        fmt.Sprintf("added 10; ", n),
        n + 10,
    )
}

result := F.Pipe2(
    monad.Of(5),
    monad.Chain(logAndDouble),
    monad.Chain(logAndAdd),
)
// Pair[string, int]{"doubled 5; added 10; ", 20}

Function Reference

Creation:

  • MakePair[A, B any](A, B) Pair[A, B] - Create a pair from two values
  • Of[A any](A) Pair[A, A] - Create a pair with same value in both positions
  • FromTuple[A, B any](Tuple2[A, B]) Pair[A, B] - Convert tuple to pair
  • ToTuple[A, B any](Pair[A, B]) Tuple2[A, B] - Convert pair to tuple

Access:

  • Head[A, B any](Pair[A, B]) A - Get the head (first) value
  • Tail[A, B any](Pair[A, B]) B - Get the tail (second) value
  • First[A, B any](Pair[A, B]) A - Get the first value (alias for Head)
  • Second[A, B any](Pair[A, B]) B - Get the second value (alias for Tail)

Transformations:

  • MonadMapHead[B, A, A1 any](Pair[A, B], func(A) A1) Pair[A1, B] - Map head value
  • MonadMapTail[A, B, B1 any](Pair[A, B], func(B) B1) Pair[A, B1] - Map tail value
  • MonadMap[B, A, A1 any](Pair[A, B], func(A) A1) Pair[A1, B] - Map head value (alias)
  • MonadBiMap[A, B, A1, B1 any](Pair[A, B], func(A) A1, func(B) B1) Pair[A1, B1] - Map both values
  • MapHead[B, A, A1 any](func(A) A1) func(Pair[A, B]) Pair[A1, B] - Curried map head
  • MapTail[A, B, B1 any](func(B) B1) func(Pair[A, B]) Pair[A, B1] - Curried map tail
  • Map[A, B, B1 any](func(B) B1) func(Pair[A, B]) Pair[A, B1] - Curried map tail (alias)
  • BiMap[A, B, A1, B1 any](func(A) A1, func(B) B1) func(Pair[A, B]) Pair[A1, B1] - Curried bimap
  • Swap[A, B any](Pair[A, B]) Pair[B, A] - Swap head and tail

Monadic Operations:

  • MonadChainHead[B, A, A1 any](Semigroup[B], Pair[A, B], func(A) Pair[A1, B]) Pair[A1, B]
  • MonadChainTail[A, B, B1 any](Semigroup[A], Pair[A, B], func(B) Pair[A, B1]) Pair[A, B1]
  • MonadChain[A, B, B1 any](Semigroup[A], Pair[A, B], func(B) Pair[A, B1]) Pair[A, B1]
  • ChainHead[B, A, A1 any](Semigroup[B], func(A) Pair[A1, B]) func(Pair[A, B]) Pair[A1, B]
  • ChainTail[A, B, B1 any](Semigroup[A], func(B) Pair[A, B1]) func(Pair[A, B]) Pair[A, B1]
  • Chain[A, B, B1 any](Semigroup[A], func(B) Pair[A, B1]) func(Pair[A, B]) Pair[A, B1]

Applicative Operations:

  • MonadApHead[B, A, A1 any](Semigroup[B], Pair[func(A) A1, B], Pair[A, B]) Pair[A1, B]
  • MonadApTail[A, B, B1 any](Semigroup[A], Pair[A, func(B) B1], Pair[A, B]) Pair[A, B1]
  • MonadAp[A, B, B1 any](Semigroup[A], Pair[A, func(B) B1], Pair[A, B]) Pair[A, B1]
  • ApHead[B, A, A1 any](Semigroup[B], Pair[A, B]) func(Pair[func(A) A1, B]) Pair[A1, B]
  • ApTail[A, B, B1 any](Semigroup[A], Pair[A, B]) func(Pair[A, func(B) B1]) Pair[A, B1]
  • Ap[A, B, B1 any](Semigroup[A], Pair[A, B]) func(Pair[A, func(B) B1]) Pair[A, B1]

Function Conversion:

  • Paired[F ~func(T1, T2) R, T1, T2, R any](F) func(Pair[T1, T2]) R
  • Unpaired[F ~func(Pair[T1, T2]) R, T1, T2, R any](F) func(T1, T2) R
  • Merge[F ~func(B) func(A) R, A, B, R any](F) func(Pair[A, B]) R

Equality:

  • Eq[A, B any](Eq[A], Eq[B]) Eq[Pair[A, B]] - Create equality for pairs
  • FromStrictEquals[A, B comparable]() Eq[Pair[A, B]] - Equality for comparable types

Type Classes:

  • MonadHead[A, B, A1 any](Monoid[B]) Monad[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]]
  • MonadTail[B, A, B1 any](Monoid[A]) Monad[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]
  • Monad[B, A, B1 any](Monoid[A]) Monad[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]
  • PointedHead[A, B any](Monoid[B]) Pointed[A, Pair[A, B]]
  • PointedTail[B, A any](Monoid[A]) Pointed[B, Pair[A, B]]
  • Pointed[B, A any](Monoid[A]) Pointed[B, Pair[A, B]]
  • FunctorHead[A, B, A1 any]() Functor[A, A1, Pair[A, B], Pair[A1, B]]
  • FunctorTail[B, A, B1 any]() Functor[B, B1, Pair[A, B], Pair[A, B1]]
  • Functor[B, A, B1 any]() Functor[B, B1, Pair[A, B], Pair[A, B1]]
  • ApplicativeHead[A, B, A1 any](Monoid[B]) Applicative[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]]
  • ApplicativeTail[B, A, B1 any](Monoid[A]) Applicative[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]
  • Applicative[B, A, B1 any](Monoid[A]) Applicative[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]
  • github.com/IBM/fp-go/v2/tuple - Position-based heterogeneous tuples
  • github.com/IBM/fp-go/v2/semigroup - Associative binary operations
  • github.com/IBM/fp-go/v2/monoid - Semigroups with identity
  • github.com/IBM/fp-go/v2/eq - Equality type class
  • github.com/IBM/fp-go/v2/function - Function composition utilities

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApHead

func ApHead[B, A, A1 any](sg Semigroup[B], fa Pair[A, B]) func(Pair[func(A) A1, B]) Pair[A1, B]

ApHead returns a function that applies a function in a pair to a value in a pair, operating on head values. This is the curried version of MonadApHead.

Example:

import SG "github.com/IBM/fp-go/v2/semigroup"

strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b })
pv := pair.MakePair(42, "hello")
ap := pair.ApHead(strConcat, pv)
pf := pair.MakePair(func(n int) string { return fmt.Sprintf("%d", n) }, "!")
result := ap(pf)  // Pair[string, string]{"42", "!hello"}

func Applicative

func Applicative[B, A, B1 any](m monoid.Monoid[A]) applicative.Applicative[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]

Applicative implements the applicative operations for Pair operating on the tail value (alias for ApplicativeTail). This is the default applicative instance for Pair.

Example:

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

intSum := M.MonoidSum[int]()
applicative := pair.Applicative[string, int, int](intSum)
pf := applicative.Of(func(s string) int { return len(s) })
pv := pair.MakePair(5, "hello")
result := applicative.Ap(pv)(pf)  // Pair[int, int]{5, 5}

func ApplicativeHead

func ApplicativeHead[A, B, A1 any](m monoid.Monoid[B]) applicative.Applicative[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]]

ApplicativeHead implements the applicative operations for Pair operating on the head value. Requires a monoid for the tail type to provide an identity element for the Of operation and a semigroup for combining tail values in the Ap operation.

Example:

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

stringMonoid := M.MakeMonoid(
    func(a, b string) string { return a + b },
    "",
)
applicative := pair.ApplicativeHead[int, string, string](stringMonoid)
pf := applicative.Of(func(n int) string { return fmt.Sprintf("%d", n) })
pv := pair.MakePair(42, "!")
result := applicative.Ap(pv)(pf)  // Pair[string, string]{"42", "!"}

func ApplicativeTail

func ApplicativeTail[B, A, B1 any](m monoid.Monoid[A]) applicative.Applicative[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]

ApplicativeTail implements the applicative operations for Pair operating on the tail value. Requires a monoid for the head type to provide an identity element for the Of operation and a semigroup for combining head values in the Ap operation.

Example:

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

intSum := M.MonoidSum[int]()
applicative := pair.ApplicativeTail[string, int, int](intSum)
pf := applicative.Of(func(s string) int { return len(s) })
pv := pair.MakePair(5, "hello")
result := applicative.Ap(pv)(pf)  // Pair[int, int]{5, 5}

func BiMap

func BiMap[A, B, A1, B1 any](f func(A) A1, g func(B) B1) func(Pair[A, B]) Pair[A1, B1]

BiMap returns a function that maps over both values of a pair. This is the curried version of MonadBiMap.

Example:

mapper := pair.BiMap(
    func(n int) string { return fmt.Sprintf("%d", n) },
    func(s string) int { return len(s) },
)
p := pair.MakePair(5, "hello")
p2 := mapper(p)  // Pair[string, int]{"5", 5}
Example
package main

import (
	"fmt"

	N "github.com/IBM/fp-go/v2/number"
	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	result := pair.BiMap(
		func(s string) string { return s + "!" },
		N.Mul(2),
	)(p)
	fmt.Println(result)
}
Output:

Pair[string, int](hello!, 84)

func ChainHead

func ChainHead[B, A, A1 any](sg Semigroup[B], f func(A) Pair[A1, B]) func(Pair[A, B]) Pair[A1, B]

ChainHead returns a function that chains over the head value. This is the curried version of MonadChainHead.

Example:

import SG "github.com/IBM/fp-go/v2/semigroup"

strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b })
chain := pair.ChainHead(strConcat, func(n int) pair.Pair[string, string] {
    return pair.MakePair(fmt.Sprintf("%d", n), "!")
})
p := pair.MakePair(5, "hello")
p2 := chain(p)  // Pair[string, string]{"5", "hello!"}

func Eq

func Eq[A, B any](a eq.Eq[A], b eq.Eq[B]) eq.Eq[Pair[A, B]]

Eq constructs an equality predicate for Pair from equality predicates for both components. Two pairs are considered equal if both their head values are equal and their tail values are equal.

Example:

import EQ "github.com/IBM/fp-go/v2/eq"

pairEq := pair.Eq(
    EQ.FromStrictEquals[string](),
    EQ.FromStrictEquals[int](),
)
p1 := pair.MakePair("hello", 42)
p2 := pair.MakePair("hello", 42)
p3 := pair.MakePair("world", 42)
pairEq.Equals(p1, p2)  // true
pairEq.Equals(p1, p3)  // false

func First

func First[A, B any](fa Pair[A, B]) A

First returns the first value of the pair (alias for Head).

Example:

p := pair.MakePair("hello", 42)
f := pair.First(p)  // "hello"
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	f := pair.First(p)
	fmt.Println(f)
}
Output:

hello

func FromStrictEquals

func FromStrictEquals[A, B comparable]() eq.Eq[Pair[A, B]]

FromStrictEquals constructs an eq.Eq for Pair using the built-in equality operator (==) for both components. This is only available when both type parameters are comparable.

Example:

pairEq := pair.FromStrictEquals[string, int]()
p1 := pair.MakePair("hello", 42)
p2 := pair.MakePair("hello", 42)
pairEq.Equals(p1, p2)  // true

func Functor

func Functor[B, A, B1 any]() functor.Functor[B, B1, Pair[A, B], Pair[A, B1]]

Functor implements the functor operations for Pair operating on the tail value (alias for FunctorTail). This is the default functor instance for Pair.

Example:

functor := pair.Functor[string, int, int]()
mapper := functor.Map(func(s string) int { return len(s) })
p := pair.MakePair(5, "hello")
p2 := mapper(p)  // Pair[int, int]{5, 5}

func FunctorHead

func FunctorHead[A, B, A1 any]() functor.Functor[A, A1, Pair[A, B], Pair[A1, B]]

FunctorHead implements the functor operations for Pair operating on the head value.

Example:

functor := pair.FunctorHead[int, string, string]()
mapper := functor.Map(func(n int) string { return fmt.Sprintf("%d", n) })
p := pair.MakePair(42, "hello")
p2 := mapper(p)  // Pair[string, string]{"42", "hello"}

func FunctorTail

func FunctorTail[B, A, B1 any]() functor.Functor[B, B1, Pair[A, B], Pair[A, B1]]

FunctorTail implements the functor operations for Pair operating on the tail value.

Example:

functor := pair.FunctorTail[string, int, int]()
mapper := functor.Map(func(s string) int { return len(s) })
p := pair.MakePair(5, "hello")
p2 := mapper(p)  // Pair[int, int]{5, 5}
func Head[A, B any](fa Pair[A, B]) A

Head returns the head (first) value of the pair.

Example:

p := pair.MakePair("hello", 42)
h := pair.Head(p)  // "hello"
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	h := pair.Head(p)
	fmt.Println(h)
}
Output:

hello

func MapHead

func MapHead[B, A, A1 any](f func(A) A1) func(Pair[A, B]) Pair[A1, B]

MapHead returns a function that maps over the head value of a pair. This is the curried version of MonadMapHead.

Example:

mapper := pair.MapHead[string](func(n int) string {
    return fmt.Sprintf("%d", n)
})
p := pair.MakePair(5, "hello")
p2 := mapper(p)  // Pair[string, string]{"5", "hello"}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	upper := pair.MapHead[int](func(s string) string { return s + "!" })(p)
	fmt.Println(upper)
}
Output:

Pair[string, int](hello!, 42)

func Merge

func Merge[F ~func(B) func(A) R, A, B, R any](f F) func(Pair[A, B]) R

Merge applies a curried function to a pair by applying the tail value first, then the head value.

Example:

add := func(b int) func(a int) int {
    return func(a int) int { return a + b }
}
merge := pair.Merge(add)
result := merge(pair.MakePair(3, 4))  // 7 (applies 4 then 3)

func Monad

func Monad[B, A, B1 any](m monoid.Monoid[A]) monad.Monad[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]

Monad implements the monadic operations for Pair operating on the tail value (alias for MonadTail). This is the default monad instance for Pair.

Example:

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

intSum := M.MonoidSum[int]()
monad := pair.Monad[string, int, int](intSum)
p := monad.Of("hello")  // Pair[int, string]{0, "hello"}

func MonadHead

func MonadHead[A, B, A1 any](m monoid.Monoid[B]) monad.Monad[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]]

MonadHead implements the monadic operations for Pair operating on the head value. Requires a monoid for the tail type to provide an identity element for the Of operation and a semigroup for combining tail values in Chain and Ap operations.

Example:

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

stringMonoid := M.MakeMonoid(
    func(a, b string) string { return a + b },
    "",
)
monad := pair.MonadHead[int, string, int](stringMonoid)
p := monad.Of(42)  // Pair[int, string]{42, ""}

func MonadSequence

func MonadSequence[L, A, HKTA, HKTPA any](
	mmap func(HKTA, Kleisli[L, A, A]) HKTPA,
	fas Pair[L, HKTA],
) HKTPA

func MonadTail

func MonadTail[B, A, B1 any](m monoid.Monoid[A]) monad.Monad[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]]

MonadTail implements the monadic operations for Pair operating on the tail value. Requires a monoid for the head type to provide an identity element for the Of operation and a semigroup for combining head values in Chain and Ap operations.

Example:

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

intSum := M.MonoidSum[int]()
monad := pair.MonadTail[string, int, int](intSum)
p := monad.Of("hello")  // Pair[int, string]{0, "hello"}

func MonadTraverse

func MonadTraverse[L, A, HKTA, HKTPA any](
	mmap func(HKTA, Kleisli[L, A, A]) HKTPA,
	f func(A) HKTA,
	fas Pair[L, A],
) HKTPA

func Paired

func Paired[F ~func(T1, T2) R, T1, T2, R any](f F) func(Pair[T1, T2]) R

Paired converts a function with 2 parameters into a function taking a Pair. The inverse function is Unpaired.

Example:

add := func(a, b int) int { return a + b }
pairedAdd := pair.Paired(add)
result := pairedAdd(pair.MakePair(3, 4))  // 7

func Pointed

func Pointed[B, A any](m monoid.Monoid[A]) pointed.Pointed[B, Pair[A, B]]

Pointed implements the pointed operations for Pair operating on the tail value (alias for PointedTail). This is the default pointed instance for Pair.

Example:

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

intSum := M.MonoidSum[int]()
pointed := pair.Pointed[string, int](intSum)
p := pointed.Of("hello")  // Pair[int, string]{0, "hello"}

func PointedHead

func PointedHead[A, B any](m monoid.Monoid[B]) pointed.Pointed[A, Pair[A, B]]

PointedHead implements the pointed operations for Pair operating on the head value. Requires a monoid for the tail type to provide an identity element.

Example:

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

stringMonoid := M.MakeMonoid(
    func(a, b string) string { return a + b },
    "",
)
pointed := pair.PointedHead[int, string](stringMonoid)
p := pointed.Of(42)  // Pair[int, string]{42, ""}

func PointedTail

func PointedTail[B, A any](m monoid.Monoid[A]) pointed.Pointed[B, Pair[A, B]]

PointedTail implements the pointed operations for Pair operating on the tail value. Requires a monoid for the head type to provide an identity element.

Example:

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

intSum := M.MonoidSum[int]()
pointed := pair.PointedTail[string, int](intSum)
p := pointed.Of("hello")  // Pair[int, string]{0, "hello"}

func Second

func Second[A, B any](fa Pair[A, B]) B

Second returns the second value of the pair (alias for Tail).

Example:

p := pair.MakePair("hello", 42)
s := pair.Second(p)  // 42
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	s := pair.Second(p)
	fmt.Println(s)
}
Output:

42

func Sequence

func Sequence[L, A, HKTA, HKTPA any](
	mmap func(Kleisli[L, A, A]) func(HKTA) HKTPA,
) func(Pair[L, HKTA]) HKTPA

func Tail

func Tail[A, B any](fa Pair[A, B]) B

Tail returns the tail (second) value of the pair.

Example:

p := pair.MakePair("hello", 42)
t := pair.Tail(p)  // 42
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	t := pair.Tail(p)
	fmt.Println(t)
}
Output:

42

func Traverse

func Traverse[L, A, HKTA, HKTPA any](
	mmap func(Kleisli[L, A, A]) func(HKTA) HKTPA,
) func(func(A) HKTA) func(Pair[L, A]) HKTPA

func Unpaired

func Unpaired[F ~func(Pair[T1, T2]) R, T1, T2, R any](f F) func(T1, T2) R

Unpaired converts a function with a Pair parameter into a function with 2 parameters. The inverse function is Paired.

Example:

pairedAdd := func(p pair.Pair[int, int]) int {
    return pair.Head(p) + pair.Tail(p)
}
add := pair.Unpaired(pairedAdd)
result := add(3, 4)  // 7

Types

type Kleisli

type Kleisli[L, R1, R2 any] = func(R1) Pair[L, R2]

Kleisli represents a Kleisli arrow for Pair. It is a function that takes a value of type R1 and returns a Pair[L, R2].

Kleisli arrows are used for monadic composition, allowing you to chain operations that produce Pairs. They are particularly useful with Chain and ChainTail operations.

Example:

// A Kleisli arrow that takes a string and returns a Pair
lengthPair := func(s string) pair.Pair[int, string] {
    return pair.MakePair(len(s), s + "!")
}
// Type: Kleisli[int, string, string]

func FromHead

func FromHead[B, A any](a A) Kleisli[A, B, B]

FromHead creates a function that constructs a Pair from a given head value. It returns a function that takes a tail value and combines it with the head to create a Pair.

This is useful for functional composition where you want to partially apply the head value and later provide the tail value.

Example:

makePair := pair.FromHead[int]("hello")
p := makePair(42)  // Pair[string, int]{"hello", 42}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	makePair := pair.FromHead[int]("hello")
	p := makePair(42)
	fmt.Println(p)
}
Output:

Pair[string, int](hello, 42)

func FromTail

func FromTail[A, B any](b B) Kleisli[A, A, B]

FromTail creates a function that constructs a Pair from a given tail value. It returns a function that takes a head value and combines it with the tail to create a Pair.

This is useful for functional composition where you want to partially apply the tail value and later provide the head value.

Example:

makePair := pair.FromTail[string](42)
p := makePair("hello")  // Pair[string, int]{"hello", 42}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	makePair := pair.FromTail[string](42)
	p := makePair("hello")
	fmt.Println(p)
}
Output:

Pair[string, int](hello, 42)

type Operator

type Operator[L, R1, R2 any] = func(Pair[L, R1]) Pair[L, R2]

Operator represents an endomorphism on Pair that transforms the tail value. It is a function that takes a Pair[L, R1] and returns a Pair[L, R2], preserving the head type L while potentially transforming the tail from R1 to R2.

Operators are commonly used as the return type of curried functions like Map, Chain, and Ap, enabling function composition and point-free style programming.

Example:

// An operator that maps the tail value
toLengths := pair.Map[string](func(s string) int {
    return len(s)
})
// Type: Operator[string, string, int]
// Usage: p2 := toLengths(pair.MakePair("key", "value"))

func Ap

func Ap[A, B, B1 any](sg Semigroup[A], fa Pair[A, B]) Operator[A, func(B) B1, B1]

Ap returns a function that applies a function in a pair to a value in a pair, operating on tail values (alias for ApTail).

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
pv := pair.MakePair(5, "hello")
ap := pair.Ap(intSum, pv)
pf := pair.MakePair(10, func(s string) int { return len(s) })
result := ap(pf)  // Pair[int, int]{15, 5}

func ApTail

func ApTail[A, B, B1 any](sg Semigroup[A], fb Pair[A, B]) Operator[A, func(B) B1, B1]

ApTail returns a function that applies a function in a pair to a value in a pair, operating on tail values. This is the curried version of MonadApTail.

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
pv := pair.MakePair(5, "hello")
ap := pair.ApTail(intSum, pv)
pf := pair.MakePair(10, func(s string) int { return len(s) })
result := ap(pf)  // Pair[int, int]{15, 5}

func Chain

func Chain[A, B, B1 any](sg Semigroup[A], f Kleisli[A, B, B1]) Operator[A, B, B1]

Chain returns a function that chains over the tail value (alias for ChainTail).

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
chain := pair.Chain(intSum, func(s string) pair.Pair[int, int] {
    return pair.MakePair(len(s), len(s) * 2)
})
p := pair.MakePair(5, "hello")
p2 := chain(p)  // Pair[int, int]{10, 10}

func ChainTail

func ChainTail[A, B, B1 any](sg Semigroup[A], f Kleisli[A, B, B1]) Operator[A, B, B1]

ChainTail returns a function that chains over the tail value. This is the curried version of MonadChainTail.

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
chain := pair.ChainTail(intSum, func(s string) pair.Pair[int, int] {
    return pair.MakePair(len(s), len(s) * 2)
})
p := pair.MakePair(5, "hello")
p2 := chain(p)  // Pair[int, int]{10, 10}

func Map

func Map[A, B, B1 any](f func(B) B1) Operator[A, B, B1]

Map returns a function that maps over the tail value of a pair (alias for MapTail). This is the curried version of MonadMapTail.

Example:

mapper := pair.Map[int](func(s string) int { return len(s) })
p := pair.MakePair(5, "hello")
p2 := mapper(p)  // Pair[int, int]{5, 5}
Example
package main

import (
	"fmt"

	N "github.com/IBM/fp-go/v2/number"
	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	doubled := pair.Map[string](N.Mul(2))(p)
	fmt.Println(doubled)
}
Output:

Pair[string, int](hello, 84)

func MapTail

func MapTail[A, B, B1 any](f func(B) B1) Operator[A, B, B1]

MapTail returns a function that maps over the tail value of a pair. This is the curried version of MonadMapTail.

Example:

mapper := pair.MapTail[int](func(s string) int { return len(s) })
p := pair.MakePair(5, "hello")
p2 := mapper(p)  // Pair[int, int]{5, 5}

type Pair

type Pair[L, R any] struct {
	// contains filtered or unexported fields
}

Pair defines a data structure that holds two strongly typed values. The first value is called the "head" or "left" (L), and the second is called the "tail" or "right" (R).

Pair provides a foundation for functional programming patterns, supporting operations like mapping, chaining, and applicative application on either or both values.

Example:

p := pair.MakePair("hello", 42)
head := pair.Head(p)  // "hello"
tail := pair.Tail(p)  // 42
Example (Formatting_comparison)

ExamplePair_formatting_comparison demonstrates different formatting options.

package main

import (
	"fmt"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	type Config struct {
		Host string
		Port int
	}

	config := Config{Host: "localhost", Port: 8080}
	p := P.MakePair(config, []string{"api", "web"})

	fmt.Printf("String():   %s\n", p.String())
	fmt.Printf("GoString(): %s\n", p.GoString())
	fmt.Printf("%%v:         %v\n", p)
	fmt.Printf("%%#v:        %#v\n", p)

}
Output:

String():   Pair[pair_test.Config, []string]({localhost 8080}, [api web])
GoString(): pair.MakePair[pair_test.Config, []string](pair_test.Config{Host:"localhost", Port:8080}, []string{"api", "web"})
%v:         Pair[pair_test.Config, []string]({localhost 8080}, [api web])
%#v:        pair.MakePair[pair_test.Config, []string](pair_test.Config{Host:"localhost", Port:8080}, []string{"api", "web"})
Example (Formatting_nested)

ExamplePair_formatting_nested demonstrates formatting nested pairs.

package main

import (
	"fmt"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	inner := P.MakePair("inner", 10)
	outer := P.MakePair(inner, "outer")

	fmt.Printf("%%v: %v\n", outer)
	fmt.Printf("%%#v: %#v\n", outer)

}
Output:

%v: Pair[pair.Pair[string,int], string](Pair[string, int](inner, 10), outer)
%#v: pair.MakePair[pair.Pair[string,int], string](pair.MakePair[string, int]("inner", 10), "outer")
Example (Formatting_with_maps)

ExamplePair_formatting_with_maps demonstrates formatting pairs containing maps.

package main

import (
	"fmt"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	metadata := map[string]string{
		"version": "1.0",
		"author":  "Alice",
	}
	p := P.MakePair("config", metadata)

	fmt.Printf("%%v: %v\n", p)
	fmt.Printf("%%s: %s\n", p)

}
Output:

%v: Pair[string, map[string]string](config, map[author:Alice version:1.0])
%s: Pair[string, map[string]string](config, map[author:Alice version:1.0])

func FromTuple

func FromTuple[A, B any](t Tuple2[A, B]) Pair[A, B]

FromTuple creates a Pair from a Tuple2. The first element of the tuple becomes the head, and the second becomes the tail.

Example:

t := tuple.MakeTuple2("hello", 42)
p := pair.FromTuple(t)  // Pair[string, int]{"hello", 42}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
	"github.com/IBM/fp-go/v2/tuple"
)

func main() {
	t := tuple.MakeTuple2("hello", 42)
	p := pair.FromTuple(t)
	fmt.Println(p)
}
Output:

Pair[string, int](hello, 42)

func MakePair

func MakePair[A, B any](a A, b B) Pair[A, B]

MakePair creates a Pair from two values. The first value becomes the head, and the second becomes the tail.

Example:

p := pair.MakePair("hello", 42)  // Pair[string, int]{"hello", 42}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	fmt.Println(p)
}
Output:

Pair[string, int](hello, 42)

func MonadAp

func MonadAp[A, B, B1 any](sg Semigroup[A], faa Pair[A, func(B) B1], fa Pair[A, B]) Pair[A, B1]

MonadAp applies a function wrapped in a pair to a value wrapped in a pair, operating on the tail values (alias for MonadApTail).

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
pf := pair.MakePair(10, func(s string) int { return len(s) })
pv := pair.MakePair(5, "hello")
result := pair.MonadAp(intSum, pf, pv)  // Pair[int, int]{15, 5}

func MonadApHead

func MonadApHead[B, A, A1 any](sg Semigroup[B], faa Pair[func(A) A1, B], fa Pair[A, B]) Pair[A1, B]

MonadApHead applies a function wrapped in a pair to a value wrapped in a pair, operating on the head values and combining tail values using a semigroup.

Example:

import SG "github.com/IBM/fp-go/v2/semigroup"

strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b })
pf := pair.MakePair(func(n int) string { return fmt.Sprintf("%d", n) }, "!")
pv := pair.MakePair(42, "hello")
result := pair.MonadApHead(strConcat, pf, pv)  // Pair[string, string]{"42", "!hello"}

func MonadApTail

func MonadApTail[A, B, B1 any](sg Semigroup[A], fbb Pair[A, func(B) B1], fb Pair[A, B]) Pair[A, B1]

MonadApTail applies a function wrapped in a pair to a value wrapped in a pair, operating on the tail values and combining head values using a semigroup.

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
pf := pair.MakePair(10, func(s string) int { return len(s) })
pv := pair.MakePair(5, "hello")
result := pair.MonadApTail(intSum, pf, pv)  // Pair[int, int]{15, 5}

func MonadBiMap

func MonadBiMap[A, B, A1, B1 any](fa Pair[A, B], f func(A) A1, g func(B) B1) Pair[A1, B1]

MonadBiMap maps functions over both the head and tail values of the pair.

Example:

p := pair.MakePair(5, "hello")
p2 := pair.MonadBiMap(p,
    func(n int) string { return fmt.Sprintf("%d", n) },
    func(s string) int { return len(s) },
)  // Pair[string, int]{"5", 5}

func MonadChain

func MonadChain[A, B, B1 any](sg Semigroup[A], fa Pair[A, B], f Kleisli[A, B, B1]) Pair[A, B1]

MonadChain chains a function over the tail value (alias for MonadChainTail).

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
p := pair.MakePair(5, "hello")
p2 := pair.MonadChain(intSum, p, func(s string) pair.Pair[int, int] {
    return pair.MakePair(len(s), len(s) * 2)
})  // Pair[int, int]{10, 10}

func MonadChainHead

func MonadChainHead[B, A, A1 any](sg Semigroup[B], fa Pair[A, B], f func(A) Pair[A1, B]) Pair[A1, B]

MonadChainHead chains a function over the head value, combining tail values using a semigroup. The function receives the head value and returns a new pair. The tail values from both pairs are combined using the provided semigroup.

Example:

import SG "github.com/IBM/fp-go/v2/semigroup"

strConcat := SG.MakeSemigroup(func(a, b string) string { return a + b })
p := pair.MakePair(5, "hello")
p2 := pair.MonadChainHead(strConcat, p, func(n int) pair.Pair[string, string] {
    return pair.MakePair(fmt.Sprintf("%d", n), "!")
})  // Pair[string, string]{"5", "hello!"}

func MonadChainTail

func MonadChainTail[A, B, B1 any](sg Semigroup[A], fb Pair[A, B], f Kleisli[A, B, B1]) Pair[A, B1]

MonadChainTail chains a function over the tail value, combining head values using a semigroup. The function receives the tail value and returns a new pair. The head values from both pairs are combined using the provided semigroup.

Example:

import N "github.com/IBM/fp-go/v2/number"

intSum := N.SemigroupSum[int]()
p := pair.MakePair(5, "hello")
p2 := pair.MonadChainTail(intSum, p, func(s string) pair.Pair[int, int] {
    return pair.MakePair(len(s), len(s) * 2)
})  // Pair[int, int]{10, 10}

func MonadMap

func MonadMap[A, B, B1 any](fa Pair[A, B], f func(B) B1) Pair[A, B1]

func MonadMapHead

func MonadMapHead[B, A, A1 any](fa Pair[A, B], f func(A) A1) Pair[A1, B]

MonadMapHead maps a function over the head value of the pair, leaving the tail unchanged.

Example:

p := pair.MakePair(5, "hello")
p2 := pair.MonadMapHead(p, func(n int) string {
    return fmt.Sprintf("%d", n)
})  // Pair[string, string]{"5", "hello"}

func MonadMapTail

func MonadMapTail[A, B, B1 any](fa Pair[A, B], f func(B) B1) Pair[A, B1]

MonadMapTail maps a function over the tail value of the pair, leaving the head unchanged.

Example:

p := pair.MakePair(5, "hello")
p2 := pair.MonadMapTail(p, func(s string) int {
    return len(s)
})  // Pair[int, int]{5, 5}

func Of

func Of[A any](value A) Pair[A, A]

Of creates a Pair with the same value in both the head and tail positions.

Example:

p := pair.Of(42)  // Pair[int, int]{42, 42}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.Of(42)
	fmt.Println(p)
}
Output:

Pair[int, int](42, 42)

func Swap

func Swap[A, B any](fa Pair[A, B]) Pair[B, A]

Swap swaps the head and tail values of a pair.

Example:

p := pair.MakePair("hello", 42)
swapped := pair.Swap(p)  // Pair[int, string]{42, "hello"}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	swapped := pair.Swap(p)
	fmt.Println(swapped)
}
Output:

Pair[int, string](42, hello)

func (Pair[L, R]) Format

func (p Pair[L, R]) Format(f fmt.State, c rune)

Format implements fmt.Formatter for Pair. Supports all standard format verbs:

  • %s, %v, %+v: uses String() representation
  • %#v: uses GoString() representation
  • %q: quoted String() representation
  • other verbs: uses String() representation

Example:

p := pair.MakePair("key", 42)
fmt.Printf("%s", p)   // "Pair[string, int](key, 42)"
fmt.Printf("%v", p)   // "Pair[string, int](key, 42)"
fmt.Printf("%#v", p)  // "pair.MakePair[string, int]("key", 42)"
Example

ExamplePair_Format demonstrates the fmt.Formatter interface implementation.

package main

import (
	"fmt"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := P.MakePair("config", 8080)

	// Different format verbs
	fmt.Printf("%%s: %s\n", p)
	fmt.Printf("%%v: %v\n", p)
	fmt.Printf("%%+v: %+v\n", p)
	fmt.Printf("%%#v: %#v\n", p)

}
Output:

%s: Pair[string, int](config, 8080)
%v: Pair[string, int](config, 8080)
%+v: Pair[string, int](config, 8080)
%#v: pair.MakePair[string, int]("config", 8080)

func (Pair[L, R]) GoString

func (p Pair[L, R]) GoString() string

GoString implements fmt.GoStringer for Pair. Returns a Go-syntax representation of the Pair value.

Example:

pair.MakePair("key", 42).GoString() // "pair.MakePair[string, int]("key", 42)"
Example

ExamplePair_GoString demonstrates the fmt.GoStringer interface implementation.

package main

import (
	"errors"
	"fmt"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	p1 := P.MakePair("key", 42)
	p2 := P.MakePair(errors.New("error"), "value")

	fmt.Printf("%#v\n", p1)
	fmt.Printf("%#v\n", p2)

}
Output:

pair.MakePair[string, int]("key", 42)
pair.MakePair[error, string](&errors.errorString{s:"error"}, "value")

func (Pair[L, R]) LogValue

func (p Pair[L, R]) LogValue() slog.Value

LogValue implements slog.LogValuer for Pair. Returns a slog.Value that represents the Pair for structured logging. Returns a group value with "head" and "tail" keys.

Example:

logger := slog.Default()
p := pair.MakePair("key", 42)
logger.Info("pair value", "data", p)
// Logs: {"msg":"pair value","data":{"head":"key","tail":42}}
Example

ExamplePair_LogValue demonstrates the slog.LogValuer interface implementation.

package main

import (
	"errors"
	"log/slog"
	"os"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
			// Remove time for consistent output
			if a.Key == slog.TimeKey {
				return slog.Attr{}
			}
			return a
		},
	}))

	// Pair with string and int
	p1 := P.MakePair("username", 42)
	logger.Info("user data", "data", p1)

	// Pair with error and string
	p2 := P.MakePair(errors.New("connection failed"), "retry")
	logger.Error("operation failed", "status", p2)

}
Output:

level=INFO msg="user data" data.head=username data.tail=42
level=ERROR msg="operation failed" status.head="connection failed" status.tail=retry
Example (Structured)

ExamplePair_LogValue_structured demonstrates structured logging with Pair.

package main

import (
	"log/slog"
	"os"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		Level: slog.LevelInfo,
		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
			if a.Key == slog.TimeKey {
				return slog.Attr{}
			}
			return a
		},
	}))

	// Simulate a key-value store operation
	operation := func(key string, value int) P.Pair[string, int] {
		return P.MakePair(key, value)
	}

	// Log successful operation
	result1 := operation("counter", 42)
	logger.Info("store operation", "key", "counter", "result", result1)

	// Log another operation
	result2 := operation("timeout", 30)
	logger.Info("store operation", "key", "timeout", "result", result2)

}
Output:

level=INFO msg="store operation" key=counter result.head=counter result.tail=42
level=INFO msg="store operation" key=timeout result.head=timeout result.tail=30

func (Pair[L, R]) String

func (p Pair[L, R]) String() string

String prints some debug info for the object

Example

ExamplePair_String demonstrates the fmt.Stringer interface implementation.

package main

import (
	"fmt"

	P "github.com/IBM/fp-go/v2/pair"
)

func main() {
	p1 := P.MakePair("username", 42)
	p2 := P.MakePair(100, "active")

	fmt.Println(p1.String())
	fmt.Println(p2.String())

}
Output:

Pair[string, int](username, 42)
Pair[int, string](100, active)

type Semigroup

type Semigroup[A any] = semigroup.Semigroup[A]

Semigroup is a type alias for semigroup.Semigroup. A Semigroup represents an algebraic structure with an associative binary operation. It is used in various Pair operations to combine values when chaining or applying operations that need to merge the head or tail values.

Example:

import N "github.com/IBM/fp-go/v2/number"
intSum := N.SemigroupSum[int]()  // Combines integers by addition

type Tuple2

type Tuple2[A, B any] = tuple.Tuple2[A, B]

Tuple2 is a type alias for tuple.Tuple2. It represents a 2-tuple with two values. Pairs can be converted to and from Tuple2 using the FromTuple and ToTuple functions.

Example:

t := tuple.MakeTuple2("hello", 42)
p := pair.FromTuple(t)  // Convert Tuple2 to Pair

func ToTuple

func ToTuple[A, B any](t Pair[A, B]) Tuple2[A, B]

ToTuple creates a Tuple2 from a Pair. The head becomes the first element, and the tail becomes the second element.

Example:

p := pair.MakePair("hello", 42)
t := pair.ToTuple(p)  // Tuple2[string, int]{"hello", 42}
Example
package main

import (
	"fmt"

	"github.com/IBM/fp-go/v2/pair"
)

func main() {
	p := pair.MakePair("hello", 42)
	t := pair.ToTuple(p)
	fmt.Println(t)
}
Output:

Tuple2[string, int](hello, 42)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL