mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
232 lines
6.6 KiB
Go
232 lines
6.6 KiB
Go
// Copyright (c) 2024 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 pair
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
F "github.com/IBM/fp-go/function"
|
|
Sg "github.com/IBM/fp-go/semigroup"
|
|
T "github.com/IBM/fp-go/tuple"
|
|
)
|
|
|
|
type (
|
|
pair struct {
|
|
h, t any
|
|
}
|
|
|
|
// Pair defines a data structure that holds two strongly typed values
|
|
Pair[A, B any] pair
|
|
)
|
|
|
|
// String prints some debug info for the object
|
|
//
|
|
// go:noinline
|
|
func pairString(s *pair) string {
|
|
return fmt.Sprintf("Pair[%T, %T](%v, %v)", s.h, s.t, s.h, s.t)
|
|
}
|
|
|
|
// Format prints some debug info for the object
|
|
//
|
|
// go:noinline
|
|
func pairFormat(e *pair, f fmt.State, c rune) {
|
|
switch c {
|
|
case 's':
|
|
fmt.Fprint(f, pairString(e))
|
|
default:
|
|
fmt.Fprint(f, pairString(e))
|
|
}
|
|
}
|
|
|
|
// String prints some debug info for the object
|
|
func (s Pair[A, B]) String() string {
|
|
return pairString((*pair)(&s))
|
|
}
|
|
|
|
// Format prints some debug info for the object
|
|
func (s Pair[A, B]) Format(f fmt.State, c rune) {
|
|
pairFormat((*pair)(&s), f, c)
|
|
}
|
|
|
|
// Of creates a [Pair] with the same value to to both fields
|
|
func Of[A any](value A) Pair[A, A] {
|
|
return Pair[A, A]{h: value, t: value}
|
|
}
|
|
|
|
// FromTuple creates a [Pair] from a [T.Tuple2]
|
|
func FromTuple[A, B any](t T.Tuple2[A, B]) Pair[A, B] {
|
|
return Pair[A, B]{h: t.F1, t: t.F2}
|
|
}
|
|
|
|
// ToTuple creates a [T.Tuple2] from a [Pair]
|
|
func ToTuple[A, B any](t Pair[A, B]) T.Tuple2[A, B] {
|
|
return T.MakeTuple2(Head(t), Tail(t))
|
|
}
|
|
|
|
// MakePair creates a [Pair] from two values
|
|
func MakePair[A, B any](a A, b B) Pair[A, B] {
|
|
return Pair[A, B]{h: a, t: b}
|
|
}
|
|
|
|
// Head returns the head value of the pair
|
|
func Head[A, B any](fa Pair[A, B]) A {
|
|
return fa.h.(A)
|
|
}
|
|
|
|
// Tail returns the head value of the pair
|
|
func Tail[A, B any](fa Pair[A, B]) B {
|
|
return fa.t.(B)
|
|
}
|
|
|
|
// MonadMapHead maps the head value
|
|
func MonadMapHead[B, A, A1 any](fa Pair[A, B], f func(A) A1) Pair[A1, B] {
|
|
return Pair[A1, B]{f(Head(fa)), fa.t}
|
|
}
|
|
|
|
// MonadMap maps the head value
|
|
func MonadMap[B, A, A1 any](fa Pair[A, B], f func(A) A1) Pair[A1, B] {
|
|
return MonadMapHead(fa, f)
|
|
}
|
|
|
|
// MonadMapTail maps the Tail value
|
|
func MonadMapTail[A, B, B1 any](fa Pair[A, B], f func(B) B1) Pair[A, B1] {
|
|
return Pair[A, B1]{fa.h, f(Tail(fa))}
|
|
}
|
|
|
|
// MonadBiMap maps both values
|
|
func MonadBiMap[A, B, A1, B1 any](fa Pair[A, B], f func(A) A1, g func(B) B1) Pair[A1, B1] {
|
|
return Pair[A1, B1]{f(Head(fa)), g(Tail(fa))}
|
|
}
|
|
|
|
// Map maps the head value
|
|
func Map[B, A, A1 any](f func(A) A1) func(Pair[A, B]) Pair[A1, B] {
|
|
return MapHead[B, A, A1](f)
|
|
}
|
|
|
|
// MapHead maps the head value
|
|
func MapHead[B, A, A1 any](f func(A) A1) func(Pair[A, B]) Pair[A1, B] {
|
|
return F.Bind2nd(MonadMapHead[B, A, A1], f)
|
|
}
|
|
|
|
// MapTail maps the Tail value
|
|
func MapTail[A, B, B1 any](f func(B) B1) func(Pair[A, B]) Pair[A, B1] {
|
|
return F.Bind2nd(MonadMapTail[A, B, B1], f)
|
|
}
|
|
|
|
// BiMap maps both values
|
|
func BiMap[A, B, A1, B1 any](f func(A) A1, g func(B) B1) func(Pair[A, B]) Pair[A1, B1] {
|
|
return func(fa Pair[A, B]) Pair[A1, B1] {
|
|
return MonadBiMap(fa, f, g)
|
|
}
|
|
}
|
|
|
|
// MonadChainHead chains on the head value
|
|
func MonadChainHead[B, A, A1 any](sg Sg.Semigroup[B], fa Pair[A, B], f func(A) Pair[A1, B]) Pair[A1, B] {
|
|
fb := f(Head(fa))
|
|
return Pair[A1, B]{fb.h, sg.Concat(Tail(fa), Tail(fb))}
|
|
}
|
|
|
|
// MonadChainTail chains on the Tail value
|
|
func MonadChainTail[A, B, B1 any](sg Sg.Semigroup[A], fb Pair[A, B], f func(B) Pair[A, B1]) Pair[A, B1] {
|
|
fa := f(Tail(fb))
|
|
return Pair[A, B1]{sg.Concat(Head(fb), Head(fa)), fa.t}
|
|
}
|
|
|
|
// MonadChain chains on the head value
|
|
func MonadChain[B, A, A1 any](sg Sg.Semigroup[B], fa Pair[A, B], f func(A) Pair[A1, B]) Pair[A1, B] {
|
|
return MonadChainHead(sg, fa, f)
|
|
}
|
|
|
|
// ChainHead chains on the head value
|
|
func ChainHead[B, A, A1 any](sg Sg.Semigroup[B], f func(A) Pair[A1, B]) func(Pair[A, B]) Pair[A1, B] {
|
|
return func(fa Pair[A, B]) Pair[A1, B] {
|
|
return MonadChainHead(sg, fa, f)
|
|
}
|
|
}
|
|
|
|
// ChainTail chains on the Tail value
|
|
func ChainTail[A, B, B1 any](sg Sg.Semigroup[A], f func(B) Pair[A, B1]) func(Pair[A, B]) Pair[A, B1] {
|
|
return func(fa Pair[A, B]) Pair[A, B1] {
|
|
return MonadChainTail(sg, fa, f)
|
|
}
|
|
}
|
|
|
|
// Chain chains on the head value
|
|
func Chain[B, A, A1 any](sg Sg.Semigroup[B], f func(A) Pair[A1, B]) func(Pair[A, B]) Pair[A1, B] {
|
|
return ChainHead[B, A, A1](sg, f)
|
|
}
|
|
|
|
// MonadApHead applies on the head value
|
|
func MonadApHead[B, A, A1 any](sg Sg.Semigroup[B], faa Pair[func(A) A1, B], fa Pair[A, B]) Pair[A1, B] {
|
|
return Pair[A1, B]{Head(faa)(Head(fa)), sg.Concat(Tail(fa), Tail(faa))}
|
|
}
|
|
|
|
// MonadApTail applies on the Tail value
|
|
func MonadApTail[A, B, B1 any](sg Sg.Semigroup[A], fbb Pair[A, func(B) B1], fb Pair[A, B]) Pair[A, B1] {
|
|
return Pair[A, B1]{sg.Concat(Head(fb), Head(fbb)), Tail(fbb)(Tail(fb))}
|
|
}
|
|
|
|
// MonadAp applies on the head value
|
|
func MonadAp[B, A, A1 any](sg Sg.Semigroup[B], faa Pair[func(A) A1, B], fa Pair[A, B]) Pair[A1, B] {
|
|
return MonadApHead(sg, faa, fa)
|
|
}
|
|
|
|
// ApHead applies on the head value
|
|
func ApHead[B, A, A1 any](sg Sg.Semigroup[B], fa Pair[A, B]) func(Pair[func(A) A1, B]) Pair[A1, B] {
|
|
return func(faa Pair[func(A) A1, B]) Pair[A1, B] {
|
|
return MonadApHead(sg, faa, fa)
|
|
}
|
|
}
|
|
|
|
// ApTail applies on the Tail value
|
|
func ApTail[A, B, B1 any](sg Sg.Semigroup[A], fb Pair[A, B]) func(Pair[A, func(B) B1]) Pair[A, B1] {
|
|
return func(fbb Pair[A, func(B) B1]) Pair[A, B1] {
|
|
return MonadApTail(sg, fbb, fb)
|
|
}
|
|
}
|
|
|
|
// Ap applies on the head value
|
|
func Ap[B, A, A1 any](sg Sg.Semigroup[B], fa Pair[A, B]) func(Pair[func(A) A1, B]) Pair[A1, B] {
|
|
return ApHead[B, A, A1](sg, fa)
|
|
}
|
|
|
|
// Swap swaps the two channels
|
|
func Swap[A, B any](fa Pair[A, B]) Pair[B, A] {
|
|
return MakePair(Tail(fa), Head(fa))
|
|
}
|
|
|
|
// Paired converts a function with 2 parameters into a function taking a [Pair]
|
|
// The inverse function is [Unpaired]
|
|
func Paired[F ~func(T1, T2) R, T1, T2, R any](f F) func(Pair[T1, T2]) R {
|
|
return func(t Pair[T1, T2]) R {
|
|
return f(Head(t), Tail(t))
|
|
}
|
|
}
|
|
|
|
// Unpaired converts a function with a [Pair] parameter into a function with 2 parameters
|
|
// The inverse function is [Paired]
|
|
func Unpaired[F ~func(Pair[T1, T2]) R, T1, T2, R any](f F) func(T1, T2) R {
|
|
return func(t1 T1, t2 T2) R {
|
|
return f(MakePair(t1, t2))
|
|
}
|
|
}
|
|
|
|
func Merge[F ~func(B) func(A) R, A, B, R any](f F) func(Pair[A, B]) R {
|
|
return func(p Pair[A, B]) R {
|
|
return f(Tail(p))(Head(p))
|
|
}
|
|
}
|