1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-25 22:21:49 +02:00

fix: switch internal implementation of iterator from Tuple2 to Pair

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2024-02-12 10:33:42 +01:00
parent 51ed1693a5
commit d0e4984b60
30 changed files with 301 additions and 175 deletions

View File

@@ -26,7 +26,7 @@ import (
IOE "github.com/IBM/fp-go/ioeither" IOE "github.com/IBM/fp-go/ioeither"
IOEF "github.com/IBM/fp-go/ioeither/file" IOEF "github.com/IBM/fp-go/ioeither/file"
J "github.com/IBM/fp-go/json" J "github.com/IBM/fp-go/json"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
type ( type (
@@ -79,7 +79,7 @@ func ReadFullResponse(client Client) func(Requester) RIOE.ReaderIOEither[H.FullR
IOE.Of[error, io.ReadCloser], IOE.Of[error, io.ReadCloser],
IOEF.ReadAll[io.ReadCloser], IOEF.ReadAll[io.ReadCloser],
), ),
IOE.Map[error](F.Bind1st(T.MakeTuple2[*http.Response, []byte], resp)), IOE.Map[error](F.Bind1st(P.MakePair[*http.Response, []byte], resp)),
) )
}), }),
) )

View File

@@ -16,18 +16,18 @@
package exec package exec
import ( import (
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
type ( type (
// CommandOutput represents the output of executing a command. The first field in the [Tuple2] is // CommandOutput represents the output of executing a command. The first field in the [Tuple2] is
// stdout, the second one is stderr. Use [StdOut] and [StdErr] to access these fields // stdout, the second one is stderr. Use [StdOut] and [StdErr] to access these fields
CommandOutput = T.Tuple2[[]byte, []byte] CommandOutput = P.Pair[[]byte, []byte]
) )
var ( var (
// StdOut returns the field of a [CommandOutput] representing `stdout` // StdOut returns the field of a [CommandOutput] representing `stdout`
StdOut = T.First[[]byte, []byte] StdOut = P.Head[[]byte, []byte]
// StdErr returns the field of a [CommandOutput] representing `stderr` // StdErr returns the field of a [CommandOutput] representing `stderr`
StdErr = T.Second[[]byte, []byte] StdErr = P.Tail[[]byte, []byte]
) )

View File

@@ -18,15 +18,15 @@ package http
import ( import (
H "net/http" H "net/http"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
type ( type (
// FullResponse represents a full http response, including headers and body // FullResponse represents a full http response, including headers and body
FullResponse = T.Tuple2[*H.Response, []byte] FullResponse = P.Pair[*H.Response, []byte]
) )
var ( var (
Response = T.First[*H.Response, []byte] Response = P.Head[*H.Response, []byte]
Body = T.Second[*H.Response, []byte] Body = P.Tail[*H.Response, []byte]
) )

View File

@@ -28,12 +28,12 @@ import (
"github.com/IBM/fp-go/errors" "github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
P "github.com/IBM/fp-go/pair"
R "github.com/IBM/fp-go/record/generic" R "github.com/IBM/fp-go/record/generic"
T "github.com/IBM/fp-go/tuple"
) )
type ( type (
ParsedMediaType = T.Tuple2[string, map[string]string] ParsedMediaType = P.Pair[string, map[string]string]
HttpError struct { HttpError struct {
statusCode int statusCode int
@@ -45,17 +45,15 @@ type (
var ( var (
// mime type to check if a media type matches // mime type to check if a media type matches
reJSONMimeType = regexp.MustCompile(`application/(?:\w+\+)?json`) isJSONMimeType = regexp.MustCompile(`application/(?:\w+\+)?json`).MatchString
// ValidateResponse validates an HTTP response and returns an [E.Either] if the response is not a success // ValidateResponse validates an HTTP response and returns an [E.Either] if the response is not a success
ValidateResponse = E.FromPredicate(isValidStatus, StatusCodeError) ValidateResponse = E.FromPredicate(isValidStatus, StatusCodeError)
// alidateJsonContentTypeString parses a content type a validates that it is valid JSON // alidateJsonContentTypeString parses a content type a validates that it is valid JSON
validateJSONContentTypeString = F.Flow2( validateJSONContentTypeString = F.Flow2(
ParseMediaType, ParseMediaType,
E.ChainFirst(F.Flow2( E.ChainFirst(F.Flow2(
T.First[string, map[string]string], P.Head[string, map[string]string],
E.FromPredicate(reJSONMimeType.MatchString, func(mimeType string) error { E.FromPredicate(isJSONMimeType, errors.OnSome[string]("mimetype [%s] is not a valid JSON content type")),
return fmt.Errorf("mimetype [%s] is not a valid JSON content type", mimeType)
}),
)), )),
) )
// ValidateJSONResponse checks if an HTTP response is a valid JSON response // ValidateJSONResponse checks if an HTTP response is a valid JSON response
@@ -81,7 +79,7 @@ const (
// ParseMediaType parses a media type into a tuple // ParseMediaType parses a media type into a tuple
func ParseMediaType(mediaType string) E.Either[error, ParsedMediaType] { func ParseMediaType(mediaType string) E.Either[error, ParsedMediaType] {
m, p, err := mime.ParseMediaType(mediaType) m, p, err := mime.ParseMediaType(mediaType)
return E.TryCatchError(T.MakeTuple2(m, p), err) return E.TryCatchError(P.MakePair(m, p), err)
} }
// Error fulfills the error interface // Error fulfills the error interface

View File

@@ -23,7 +23,7 @@ import (
EX "github.com/IBM/fp-go/exec" EX "github.com/IBM/fp-go/exec"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
func Exec(ctx context.Context, name string, args []string, in []byte) (EX.CommandOutput, error) { func Exec(ctx context.Context, name string, args []string, in []byte) (EX.CommandOutput, error) {
@@ -42,5 +42,5 @@ func Exec(ctx context.Context, name string, args []string, in []byte) (EX.Comman
err = fmt.Errorf("command execution of [%s][%s] failed, stdout [%s], stderr [%s], cause [%w]", name, args, stdOut.String(), stdErr.String(), err) err = fmt.Errorf("command execution of [%s][%s] failed, stdout [%s], stderr [%s], cause [%w]", name, args, stdOut.String(), stdErr.String(), err)
} }
// return the outputs // return the outputs
return T.MakeTuple2(stdOut.Bytes(), stdErr.Bytes()), err return P.MakePair(stdOut.Bytes(), stdErr.Bytes()), err
} }

View File

@@ -27,7 +27,7 @@ import (
IOE "github.com/IBM/fp-go/ioeither" IOE "github.com/IBM/fp-go/ioeither"
IOEF "github.com/IBM/fp-go/ioeither/file" IOEF "github.com/IBM/fp-go/ioeither/file"
J "github.com/IBM/fp-go/json" J "github.com/IBM/fp-go/json"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
type ( type (
@@ -95,7 +95,7 @@ func ReadFullResponse(client Client) func(Requester) IOE.IOEither[error, H.FullR
IOE.Of[error, io.ReadCloser], IOE.Of[error, io.ReadCloser],
IOEF.ReadAll[io.ReadCloser], IOEF.ReadAll[io.ReadCloser],
), ),
IOE.Map[error](F.Bind1st(T.MakeTuple2[*http.Response, []byte], resp)), IOE.Map[error](F.Bind1st(P.MakePair[*http.Response, []byte], resp)),
) )
}), }),
) )

View File

@@ -17,11 +17,11 @@ package stateless
import ( import (
G "github.com/IBM/fp-go/iterator/stateless/generic" G "github.com/IBM/fp-go/iterator/stateless/generic"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`. // Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`.
// Stops when either the data or selectors iterator has been exhausted. // Stops when either the data or selectors iterator has been exhausted.
func Compress[U any](sel Iterator[bool]) func(Iterator[U]) Iterator[U] { func Compress[U any](sel Iterator[bool]) func(Iterator[U]) Iterator[U] {
return G.Compress[Iterator[U], Iterator[bool], Iterator[T.Tuple2[U, bool]]](sel) return G.Compress[Iterator[U], Iterator[bool], Iterator[P.Pair[U, bool]]](sel)
} }

View File

@@ -18,11 +18,11 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false` // Any returns `true` if any element of the iterable is `true`. If the iterable is empty, return `false`
func Any[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) bool, U any](pred FCT) func(ma GU) bool { func Any[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) bool, U any](pred FCT) func(ma GU) bool {
return F.Flow3( return F.Flow3(
Filter[GU](pred), Filter[GU](pred),
First[GU], First[GU],

View File

@@ -20,18 +20,18 @@ import (
C "github.com/IBM/fp-go/internal/chain" C "github.com/IBM/fp-go/internal/chain"
F "github.com/IBM/fp-go/internal/functor" F "github.com/IBM/fp-go/internal/functor"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// Bind creates an empty context of type [S] to be used with the [Bind] operation // Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[GS ~func() O.Option[T.Tuple2[GS, S]], S any]( func Do[GS ~func() O.Option[P.Pair[GS, S]], S any](
empty S, empty S,
) GS { ) GS {
return Of[GS](empty) return Of[GS](empty)
} }
// Bind attaches the result of a computation to a context [S1] to produce a context [S2] // Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], GA ~func() O.Option[T.Tuple2[GA, A]], S1, S2, A any]( func Bind[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], GA ~func() O.Option[P.Pair[GA, A]], S1, S2, A any](
setter func(A) func(S1) S2, setter func(A) func(S1) S2,
f func(S1) GA, f func(S1) GA,
) func(GS1) GS2 { ) func(GS1) GS2 {
@@ -45,7 +45,7 @@ func Bind[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2
} }
// Let attaches the result of a computation to a context [S1] to produce a context [S2] // Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], S1, S2, A any]( func Let[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], S1, S2, A any](
key func(A) func(S1) S2, key func(A) func(S1) S2,
f func(S1) A, f func(S1) A,
) func(GS1) GS2 { ) func(GS1) GS2 {
@@ -57,7 +57,7 @@ func Let[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[
} }
// LetTo attaches the a value to a context [S1] to produce a context [S2] // LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], S1, S2, B any]( func LetTo[GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], S1, S2, B any](
key func(B) func(S1) S2, key func(B) func(S1) S2,
b B, b B,
) func(GS1) GS2 { ) func(GS1) GS2 {
@@ -69,7 +69,7 @@ func LetTo[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple
} }
// BindTo initializes a new state [S1] from a value [T] // BindTo initializes a new state [S1] from a value [T]
func BindTo[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GA ~func() O.Option[T.Tuple2[GA, A]], S1, A any]( func BindTo[GS1 ~func() O.Option[P.Pair[GS1, S1]], GA ~func() O.Option[P.Pair[GA, A]], S1, A any](
setter func(A) S1, setter func(A) S1,
) func(GA) GS1 { ) func(GA) GS1 {
return C.BindTo( return C.BindTo(
@@ -79,7 +79,7 @@ func BindTo[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GA ~func() O.Option[T.Tuple
} }
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently // ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[GAS2 ~func() O.Option[T.Tuple2[GAS2, func(A) S2]], GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], GA ~func() O.Option[T.Tuple2[GA, A]], S1, S2, A any]( func ApS[GAS2 ~func() O.Option[P.Pair[GAS2, func(A) S2]], GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], GA ~func() O.Option[P.Pair[GA, A]], S1, S2, A any](
setter func(A) func(S1) S2, setter func(A) func(S1) S2,
fa GA, fa GA,
) func(GS1) GS2 { ) func(GS1) GS2 {

View File

@@ -18,17 +18,17 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`. // Compress returns an [Iterator] that filters elements from a data [Iterator] returning only those that have a corresponding element in selector [Iterator] that evaluates to `true`.
// Stops when either the data or selectors iterator has been exhausted. // Stops when either the data or selectors iterator has been exhausted.
func Compress[GU ~func() O.Option[T.Tuple2[GU, U]], GB ~func() O.Option[T.Tuple2[GB, bool]], CS ~func() O.Option[T.Tuple2[CS, T.Tuple2[U, bool]]], U any](sel GB) func(GU) GU { func Compress[GU ~func() O.Option[P.Pair[GU, U]], GB ~func() O.Option[P.Pair[GB, bool]], CS ~func() O.Option[P.Pair[CS, P.Pair[U, bool]]], U any](sel GB) func(GU) GU {
return F.Flow2( return F.Flow2(
Zip[GU, GB, CS](sel), Zip[GU, GB, CS](sel),
FilterMap[GU, CS](F.Flow2( FilterMap[GU, CS](F.Flow2(
O.FromPredicate(T.Second[U, bool]), O.FromPredicate(P.Tail[U, bool]),
O.Map(T.First[U, bool]), O.Map(P.Head[U, bool]),
)), )),
) )
} }

View File

@@ -18,12 +18,12 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
func Cycle[GU ~func() O.Option[T.Tuple2[GU, U]], U any](ma GU) GU { func Cycle[GU ~func() O.Option[P.Pair[GU, U]], U any](ma GU) GU {
// avoid cyclic references // avoid cyclic references
var m func(O.Option[T.Tuple2[GU, U]]) O.Option[T.Tuple2[GU, U]] var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GU, U]]
recurse := func(mu GU) GU { recurse := func(mu GU) GU {
return F.Nullary2( return F.Nullary2(
@@ -32,11 +32,11 @@ func Cycle[GU ~func() O.Option[T.Tuple2[GU, U]], U any](ma GU) GU {
) )
} }
m = O.Fold(func() O.Option[T.Tuple2[GU, U]] { m = O.Fold(func() O.Option[P.Pair[GU, U]] {
return recurse(ma)() return recurse(ma)()
}, F.Flow2( }, F.Flow2(
T.Map2(recurse, F.Identity[U]), P.BiMap(recurse, F.Identity[U]),
O.Of[T.Tuple2[GU, U]], O.Of[P.Pair[GU, U]],
)) ))
return recurse(ma) return recurse(ma)

View File

@@ -18,17 +18,17 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
P "github.com/IBM/fp-go/predicate" P "github.com/IBM/fp-go/pair"
T "github.com/IBM/fp-go/tuple" PR "github.com/IBM/fp-go/predicate"
) )
// DropWhile creates an [Iterator] that drops elements from the [Iterator] as long as the predicate is true; afterwards, returns every element. // DropWhile creates an [Iterator] that drops elements from the [Iterator] as long as the predicate is true; afterwards, returns every element.
// Note, the [Iterator] does not produce any output until the predicate first becomes false // Note, the [Iterator] does not produce any output until the predicate first becomes false
func DropWhile[GU ~func() O.Option[T.Tuple2[GU, U]], U any](pred func(U) bool) func(GU) GU { func DropWhile[GU ~func() O.Option[P.Pair[GU, U]], U any](pred func(U) bool) func(GU) GU {
// avoid cyclic references // avoid cyclic references
var m func(O.Option[T.Tuple2[GU, U]]) O.Option[T.Tuple2[GU, U]] var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GU, U]]
fromPred := O.FromPredicate(P.Not(P.ContraMap(T.Second[GU, U])(pred))) fromPred := O.FromPredicate(PR.Not(PR.ContraMap(P.Tail[GU, U])(pred)))
recurse := func(mu GU) GU { recurse := func(mu GU) GU {
return F.Nullary2( return F.Nullary2(
@@ -37,11 +37,11 @@ func DropWhile[GU ~func() O.Option[T.Tuple2[GU, U]], U any](pred func(U) bool) f
) )
} }
m = O.Chain(func(t T.Tuple2[GU, U]) O.Option[T.Tuple2[GU, U]] { m = O.Chain(func(t P.Pair[GU, U]) O.Option[P.Pair[GU, U]] {
return F.Pipe2( return F.Pipe2(
t, t,
fromPred, fromPred,
O.Fold(recurse(Next(t)), O.Of[T.Tuple2[GU, U]]), O.Fold(recurse(Next(t)), O.Of[P.Pair[GU, U]]),
) )
}) })

View File

@@ -18,13 +18,13 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// First returns the first item in an iterator if such an item exists // First returns the first item in an iterator if such an item exists
func First[GU ~func() O.Option[T.Tuple2[GU, U]], U any](mu GU) O.Option[U] { func First[GU ~func() O.Option[P.Pair[GU, U]], U any](mu GU) O.Option[U] {
return F.Pipe1( return F.Pipe1(
mu(), mu(),
O.Map(T.Second[GU, U]), O.Map(P.Tail[GU, U]),
) )
} }

View File

@@ -19,16 +19,16 @@ import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
L "github.com/IBM/fp-go/io/generic" L "github.com/IBM/fp-go/io/generic"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// FromLazy returns an iterator on top of a lazy function // FromLazy returns an iterator on top of a lazy function
func FromLazy[GU ~func() O.Option[T.Tuple2[GU, U]], LZ ~func() U, U any](l LZ) GU { func FromLazy[GU ~func() O.Option[P.Pair[GU, U]], LZ ~func() U, U any](l LZ) GU {
return F.Pipe1( return F.Pipe1(
l, l,
L.Map[LZ, GU](F.Flow2( L.Map[LZ, GU](F.Flow2(
F.Bind1st(T.MakeTuple2[GU, U], Empty[GU]()), F.Bind1st(P.MakePair[GU, U], Empty[GU]()),
O.Of[T.Tuple2[GU, U]], O.Of[P.Pair[GU, U]],
)), )),
) )
} }

View File

@@ -24,45 +24,45 @@ import (
M "github.com/IBM/fp-go/monoid" M "github.com/IBM/fp-go/monoid"
N "github.com/IBM/fp-go/number" N "github.com/IBM/fp-go/number"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// Next returns the iterator for the next element in an iterator `T.Tuple2` // Next returns the iterator for the next element in an iterator `P.Pair`
func Next[GU ~func() O.Option[T.Tuple2[GU, U]], U any](m T.Tuple2[GU, U]) GU { func Next[GU ~func() O.Option[P.Pair[GU, U]], U any](m P.Pair[GU, U]) GU {
return T.First(m) return P.Head(m)
} }
// Current returns the current element in an iterator `T.Tuple2` // Current returns the current element in an iterator `P.Pair`
func Current[GU ~func() O.Option[T.Tuple2[GU, U]], U any](m T.Tuple2[GU, U]) U { func Current[GU ~func() O.Option[P.Pair[GU, U]], U any](m P.Pair[GU, U]) U {
return T.Second(m) return P.Tail(m)
} }
// From constructs an array from a set of variadic arguments // From constructs an array from a set of variadic arguments
func From[GU ~func() O.Option[T.Tuple2[GU, U]], U any](data ...U) GU { func From[GU ~func() O.Option[P.Pair[GU, U]], U any](data ...U) GU {
return FromArray[GU](data) return FromArray[GU](data)
} }
// Empty returns the empty iterator // Empty returns the empty iterator
func Empty[GU ~func() O.Option[T.Tuple2[GU, U]], U any]() GU { func Empty[GU ~func() O.Option[P.Pair[GU, U]], U any]() GU {
return IO.None[GU]() return IO.None[GU]()
} }
// Of returns an iterator with one single element // Of returns an iterator with one single element
func Of[GU ~func() O.Option[T.Tuple2[GU, U]], U any](a U) GU { func Of[GU ~func() O.Option[P.Pair[GU, U]], U any](a U) GU {
return IO.Of[GU](T.MakeTuple2(Empty[GU](), a)) return IO.Of[GU](P.MakePair(Empty[GU](), a))
} }
// FromArray returns an iterator from multiple elements // FromArray returns an iterator from multiple elements
func FromArray[GU ~func() O.Option[T.Tuple2[GU, U]], US ~[]U, U any](as US) GU { func FromArray[GU ~func() O.Option[P.Pair[GU, U]], US ~[]U, U any](as US) GU {
return A.MatchLeft(Empty[GU], func(head U, tail US) GU { return A.MatchLeft(Empty[GU], func(head U, tail US) GU {
return func() O.Option[T.Tuple2[GU, U]] { return func() O.Option[P.Pair[GU, U]] {
return O.Of(T.MakeTuple2(FromArray[GU](tail), head)) return O.Of(P.MakePair(FromArray[GU](tail), head))
} }
})(as) })(as)
} }
// reduce applies a function for each value of the iterator with a floating result // reduce applies a function for each value of the iterator with a floating result
func reduce[GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](as GU, f func(V, U) V, initial V) V { func reduce[GU ~func() O.Option[P.Pair[GU, U]], U, V any](as GU, f func(V, U) V, initial V) V {
next, ok := O.Unwrap(as()) next, ok := O.Unwrap(as())
current := initial current := initial
for ok { for ok {
@@ -74,18 +74,18 @@ func reduce[GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](as GU, f func(V, U)
} }
// Reduce applies a function for each value of the iterator with a floating result // Reduce applies a function for each value of the iterator with a floating result
func Reduce[GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](f func(V, U) V, initial V) func(GU) V { func Reduce[GU ~func() O.Option[P.Pair[GU, U]], U, V any](f func(V, U) V, initial V) func(GU) V {
return F.Bind23of3(reduce[GU, U, V])(f, initial) return F.Bind23of3(reduce[GU, U, V])(f, initial)
} }
// ToArray converts the iterator to an array // ToArray converts the iterator to an array
func ToArray[GU ~func() O.Option[T.Tuple2[GU, U]], US ~[]U, U any](u GU) US { func ToArray[GU ~func() O.Option[P.Pair[GU, U]], US ~[]U, U any](u GU) US {
return Reduce[GU](A.Append[US], A.Empty[US]())(u) return Reduce[GU](A.Append[US], A.Empty[US]())(u)
} }
func Map[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) V, U, V any](f FCT) func(ma GU) GV { func Map[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) V, U, V any](f FCT) func(ma GU) GV {
// pre-declare to avoid cyclic reference // pre-declare to avoid cyclic reference
var m func(O.Option[T.Tuple2[GU, U]]) O.Option[T.Tuple2[GV, V]] var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GV, V]]
recurse := func(ma GU) GV { recurse := func(ma GU) GV {
return F.Nullary2( return F.Nullary2(
@@ -94,17 +94,17 @@ func Map[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU,
) )
} }
m = O.Map(T.Map2(recurse, f)) m = O.Map(P.BiMap(recurse, f))
return recurse return recurse
} }
func MonadMap[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](ma GU, f func(U) V) GV { func MonadMap[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU, f func(U) V) GV {
return Map[GV, GU](f)(ma) return Map[GV, GU](f)(ma)
} }
func concat[GU ~func() O.Option[T.Tuple2[GU, U]], U any](right, left GU) GU { func concat[GU ~func() O.Option[P.Pair[GU, U]], U any](right, left GU) GU {
var m func(ma O.Option[T.Tuple2[GU, U]]) O.Option[T.Tuple2[GU, U]] var m func(ma O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GU, U]]
recurse := func(left GU) GU { recurse := func(left GU) GU {
return F.Nullary2(left, m) return F.Nullary2(left, m)
@@ -113,16 +113,16 @@ func concat[GU ~func() O.Option[T.Tuple2[GU, U]], U any](right, left GU) GU {
m = O.Fold( m = O.Fold(
right, right,
F.Flow2( F.Flow2(
T.Map2(recurse, F.Identity[U]), P.BiMap(recurse, F.Identity[U]),
O.Some[T.Tuple2[GU, U]], O.Some[P.Pair[GU, U]],
)) ))
return recurse(left) return recurse(left)
} }
func Chain[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](f func(U) GV) func(GU) GV { func Chain[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](f func(U) GV) func(GU) GV {
// pre-declare to avoid cyclic reference // pre-declare to avoid cyclic reference
var m func(O.Option[T.Tuple2[GU, U]]) O.Option[T.Tuple2[GV, V]] var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GV, V]]
recurse := func(ma GU) GV { recurse := func(ma GU) GV {
return F.Nullary2( return F.Nullary2(
@@ -132,9 +132,9 @@ func Chain[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU
} }
m = O.Chain( m = O.Chain(
F.Flow3( F.Flow3(
T.Map2(recurse, f), P.BiMap(recurse, f),
T.Tupled2(concat[GV]), P.Paired(concat[GV]),
func(v GV) O.Option[T.Tuple2[GV, V]] { func(v GV) O.Option[P.Pair[GV, V]] {
return v() return v()
}, },
), ),
@@ -143,11 +143,11 @@ func Chain[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU
return recurse return recurse
} }
func MonadChain[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](ma GU, f func(U) GV) GV { func MonadChain[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU, f func(U) GV) GV {
return Chain[GV, GU](f)(ma) return Chain[GV, GU](f)(ma)
} }
func MonadChainFirst[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](ma GU, f func(U) GV) GU { func MonadChainFirst[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU, f func(U) GV) GU {
return C.MonadChainFirst( return C.MonadChainFirst(
MonadChain[GU, GU, U, U], MonadChain[GU, GU, U, U],
MonadMap[GU, GV, V, U], MonadMap[GU, GV, V, U],
@@ -156,7 +156,7 @@ func MonadChainFirst[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T
) )
} }
func ChainFirst[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](f func(U) GV) func(GU) GU { func ChainFirst[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](f func(U) GV) func(GU) GU {
return C.ChainFirst( return C.ChainFirst(
Chain[GU, GU, U, U], Chain[GU, GU, U, U],
Map[GU, GV, func(V) U, V, U], Map[GU, GV, func(V) U, V, U],
@@ -164,14 +164,14 @@ func ChainFirst[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tupl
) )
} }
func Flatten[GV ~func() O.Option[T.Tuple2[GV, GU]], GU ~func() O.Option[T.Tuple2[GU, U]], U any](ma GV) GU { func Flatten[GV ~func() O.Option[P.Pair[GV, GU]], GU ~func() O.Option[P.Pair[GU, U]], U any](ma GV) GU {
return MonadChain(ma, F.Identity[GU]) return MonadChain(ma, F.Identity[GU])
} }
// MakeBy returns an [Iterator] with an infinite number of elements initialized with `f(i)` // MakeBy returns an [Iterator] with an infinite number of elements initialized with `f(i)`
func MakeBy[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(int) U, U any](f FCT) GU { func MakeBy[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(int) U, U any](f FCT) GU {
var m func(int) O.Option[T.Tuple2[GU, U]] var m func(int) O.Option[P.Pair[GU, U]]
recurse := func(i int) GU { recurse := func(i int) GU {
return F.Nullary2( return F.Nullary2(
@@ -181,12 +181,12 @@ func MakeBy[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(int) U, U any](f FCT
} }
m = F.Flow3( m = F.Flow3(
T.Replicate2[int], P.Of[int],
T.Map2(F.Flow2( P.BiMap(F.Flow2(
utils.Inc, utils.Inc,
recurse), recurse),
f), f),
O.Of[T.Tuple2[GU, U]], O.Of[P.Pair[GU, U]],
) )
// bootstrap // bootstrap
@@ -194,13 +194,13 @@ func MakeBy[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(int) U, U any](f FCT
} }
// Replicate creates an infinite [Iterator] containing a value. // Replicate creates an infinite [Iterator] containing a value.
func Replicate[GU ~func() O.Option[T.Tuple2[GU, U]], U any](a U) GU { func Replicate[GU ~func() O.Option[P.Pair[GU, U]], U any](a U) GU {
return MakeBy[GU](F.Constant1[int](a)) return MakeBy[GU](F.Constant1[int](a))
} }
// Repeat creates an [Iterator] containing a value repeated the specified number of times. // Repeat creates an [Iterator] containing a value repeated the specified number of times.
// Alias of [Replicate] combined with [Take] // Alias of [Replicate] combined with [Take]
func Repeat[GU ~func() O.Option[T.Tuple2[GU, U]], U any](n int, a U) GU { func Repeat[GU ~func() O.Option[P.Pair[GU, U]], U any](n int, a U) GU {
return F.Pipe2( return F.Pipe2(
a, a,
Replicate[GU], Replicate[GU],
@@ -209,13 +209,13 @@ func Repeat[GU ~func() O.Option[T.Tuple2[GU, U]], U any](n int, a U) GU {
} }
// Count creates an [Iterator] containing a consecutive sequence of integers starting with the provided start value // Count creates an [Iterator] containing a consecutive sequence of integers starting with the provided start value
func Count[GU ~func() O.Option[T.Tuple2[GU, int]]](start int) GU { func Count[GU ~func() O.Option[P.Pair[GU, int]]](start int) GU {
return MakeBy[GU](N.Add(start)) return MakeBy[GU](N.Add(start))
} }
func FilterMap[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) O.Option[V], U, V any](f FCT) func(ma GU) GV { func FilterMap[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) O.Option[V], U, V any](f FCT) func(ma GU) GV {
// pre-declare to avoid cyclic reference // pre-declare to avoid cyclic reference
var m func(O.Option[T.Tuple2[GU, U]]) O.Option[T.Tuple2[GV, V]] var m func(O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GV, V]]
recurse := func(ma GU) GV { recurse := func(ma GU) GV {
return F.Nullary2( return F.Nullary2(
@@ -226,11 +226,11 @@ func FilterMap[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple
m = O.Fold( m = O.Fold(
Empty[GV](), Empty[GV](),
func(t T.Tuple2[GU, U]) O.Option[T.Tuple2[GV, V]] { func(t P.Pair[GU, U]) O.Option[P.Pair[GV, V]] {
r := recurse(Next(t)) r := recurse(Next(t))
return O.MonadFold(f(Current(t)), r, F.Flow2( return O.MonadFold(f(Current(t)), r, F.Flow2(
F.Bind1st(T.MakeTuple2[GV, V], r), F.Bind1st(P.MakePair[GV, V], r),
O.Some[T.Tuple2[GV, V]], O.Some[P.Pair[GV, V]],
)) ))
}, },
) )
@@ -238,26 +238,26 @@ func FilterMap[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple
return recurse return recurse
} }
func Filter[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) bool, U any](f FCT) func(ma GU) GU { func Filter[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) bool, U any](f FCT) func(ma GU) GU {
return FilterMap[GU, GU](O.FromPredicate(f)) return FilterMap[GU, GU](O.FromPredicate(f))
} }
func Ap[GUV ~func() O.Option[T.Tuple2[GUV, func(U) V]], GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](ma GU) func(fab GUV) GV { func Ap[GUV ~func() O.Option[P.Pair[GUV, func(U) V]], GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](ma GU) func(fab GUV) GV {
return Chain[GV, GUV](F.Bind1st(MonadMap[GV, GU], ma)) return Chain[GV, GUV](F.Bind1st(MonadMap[GV, GU], ma))
} }
func MonadAp[GUV ~func() O.Option[T.Tuple2[GUV, func(U) V]], GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], U, V any](fab GUV, ma GU) GV { func MonadAp[GUV ~func() O.Option[P.Pair[GUV, func(U) V]], GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], U, V any](fab GUV, ma GU) GV {
return Ap[GUV, GV, GU](ma)(fab) return Ap[GUV, GV, GU](ma)(fab)
} }
func FilterChain[GVV ~func() O.Option[T.Tuple2[GVV, GV]], GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) O.Option[GV], U, V any](f FCT) func(ma GU) GV { func FilterChain[GVV ~func() O.Option[P.Pair[GVV, GV]], GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) O.Option[GV], U, V any](f FCT) func(ma GU) GV {
return F.Flow2( return F.Flow2(
FilterMap[GVV, GU](f), FilterMap[GVV, GU](f),
Flatten[GVV], Flatten[GVV],
) )
} }
func FoldMap[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) V, U, V any](m M.Monoid[V]) func(FCT) func(ma GU) V { func FoldMap[GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(U) V, U, V any](m M.Monoid[V]) func(FCT) func(ma GU) V {
return func(f FCT) func(ma GU) V { return func(f FCT) func(ma GU) V {
return Reduce[GU](func(cur V, a U) V { return Reduce[GU](func(cur V, a U) V {
return m.Concat(cur, f(a)) return m.Concat(cur, f(a))
@@ -265,6 +265,6 @@ func FoldMap[GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(U) V, U, V any](m M
} }
} }
func Fold[GU ~func() O.Option[T.Tuple2[GU, U]], U any](m M.Monoid[U]) func(ma GU) U { func Fold[GU ~func() O.Option[P.Pair[GU, U]], U any](m M.Monoid[U]) func(ma GU) U {
return Reduce[GU](m.Concat, m.Empty()) return Reduce[GU](m.Concat, m.Empty())
} }

View File

@@ -18,10 +18,10 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// Last returns the last item in an iterator if such an item exists // Last returns the last item in an iterator if such an item exists
func Last[GU ~func() O.Option[T.Tuple2[GU, U]], U any](mu GU) O.Option[U] { func Last[GU ~func() O.Option[P.Pair[GU, U]], U any](mu GU) O.Option[U] {
return reduce(mu, F.Ignore1of2[O.Option[U]](O.Of[U]), O.None[U]()) return reduce(mu, F.Ignore1of2[O.Option[U]](O.Of[U]), O.None[U]())
} }

View File

@@ -18,10 +18,10 @@ package generic
import ( import (
"github.com/IBM/fp-go/internal/monad" "github.com/IBM/fp-go/internal/monad"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
type iteratorMonad[A, B any, GA ~func() O.Option[T.Tuple2[GA, A]], GB ~func() O.Option[T.Tuple2[GB, B]], GAB ~func() O.Option[T.Tuple2[GAB, func(A) B]]] struct{} type iteratorMonad[A, B any, GA ~func() O.Option[P.Pair[GA, A]], GB ~func() O.Option[P.Pair[GB, B]], GAB ~func() O.Option[P.Pair[GAB, func(A) B]]] struct{}
func (o *iteratorMonad[A, B, GA, GB, GAB]) Of(a A) GA { func (o *iteratorMonad[A, B, GA, GB, GAB]) Of(a A) GA {
return Of[GA, A](a) return Of[GA, A](a)
@@ -40,6 +40,6 @@ func (o *iteratorMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
} }
// Monad implements the monadic operations for iterators // Monad implements the monadic operations for iterators
func Monad[A, B any, GA ~func() O.Option[T.Tuple2[GA, A]], GB ~func() O.Option[T.Tuple2[GB, B]], GAB ~func() O.Option[T.Tuple2[GAB, func(A) B]]]() monad.Monad[A, B, GA, GB, GAB] { func Monad[A, B any, GA ~func() O.Option[P.Pair[GA, A]], GB ~func() O.Option[P.Pair[GB, B]], GAB ~func() O.Option[P.Pair[GAB, func(A) B]]]() monad.Monad[A, B, GA, GB, GAB] {
return &iteratorMonad[A, B, GA, GB, GAB]{} return &iteratorMonad[A, B, GA, GB, GAB]{}
} }

View File

@@ -19,10 +19,10 @@ import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
M "github.com/IBM/fp-go/monoid" M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
func Monoid[GU ~func() O.Option[T.Tuple2[GU, U]], U any]() M.Monoid[GU] { func Monoid[GU ~func() O.Option[P.Pair[GU, U]], U any]() M.Monoid[GU] {
return M.MakeMonoid( return M.MakeMonoid(
F.Swap(concat[GU]), F.Swap(concat[GU]),
Empty[GU](), Empty[GU](),

View File

@@ -24,10 +24,10 @@ import (
N "github.com/IBM/fp-go/number" N "github.com/IBM/fp-go/number"
I "github.com/IBM/fp-go/number/integer" I "github.com/IBM/fp-go/number/integer"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
func FromReflect[GR ~func() O.Option[T.Tuple2[GR, R.Value]]](val R.Value) GR { func FromReflect[GR ~func() O.Option[P.Pair[GR, R.Value]]](val R.Value) GR {
// recursive callback // recursive callback
var recurse func(idx int) GR var recurse func(idx int) GR
@@ -41,8 +41,8 @@ func FromReflect[GR ~func() O.Option[T.Tuple2[GR, R.Value]]](val R.Value) GR {
L.Map(fromPred), L.Map(fromPred),
LG.Map[L.Lazy[O.Option[int]], GR](O.Map( LG.Map[L.Lazy[O.Option[int]], GR](O.Map(
F.Flow2( F.Flow2(
T.Replicate2[int], P.Of[int],
T.Map2(F.Flow2(N.Add(1), recurse), val.Index), P.BiMap(F.Flow2(N.Add(1), recurse), val.Index),
), ),
)), )),
) )

View File

@@ -18,14 +18,14 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
func apTuple[A, B any](t T.Tuple2[func(A) B, A]) T.Tuple2[B, A] { func apTuple[A, B any](t P.Pair[func(A) B, A]) P.Pair[B, A] {
return T.MakeTuple2(t.F1(t.F2), t.F2) return P.MakePair(P.Head(t)(P.Tail(t)), P.Tail(t))
} }
func Scan[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU, U]], FCT ~func(V, U) V, U, V any](f FCT, initial V) func(ma GU) GV { func Scan[GV ~func() O.Option[P.Pair[GV, V]], GU ~func() O.Option[P.Pair[GU, U]], FCT ~func(V, U) V, U, V any](f FCT, initial V) func(ma GU) GV {
// pre-declare to avoid cyclic reference // pre-declare to avoid cyclic reference
var m func(GU) func(V) GV var m func(GU) func(V) GV
@@ -33,7 +33,7 @@ func Scan[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU,
return F.Nullary2( return F.Nullary2(
ma, ma,
O.Map(F.Flow2( O.Map(F.Flow2(
T.Map2(m, F.Bind1st(f, current)), P.BiMap(m, F.Bind1st(f, current)),
apTuple[V, GV], apTuple[V, GV],
)), )),
) )

View File

@@ -19,10 +19,10 @@ import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
N "github.com/IBM/fp-go/number/integer" N "github.com/IBM/fp-go/number/integer"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
func Take[GU ~func() O.Option[T.Tuple2[GU, U]], U any](n int) func(ma GU) GU { func Take[GU ~func() O.Option[P.Pair[GU, U]], U any](n int) func(ma GU) GU {
// pre-declare to avoid cyclic reference // pre-declare to avoid cyclic reference
var recurse func(ma GU, idx int) GU var recurse func(ma GU, idx int) GU
@@ -34,7 +34,7 @@ func Take[GU ~func() O.Option[T.Tuple2[GU, U]], U any](n int) func(ma GU) GU {
fromPred, fromPred,
O.Chain(F.Ignore1of1[int](F.Nullary2( O.Chain(F.Ignore1of1[int](F.Nullary2(
ma, ma,
O.Map(T.Map2(F.Bind2nd(recurse, idx+1), F.Identity[U])), O.Map(P.BiMap(F.Bind2nd(recurse, idx+1), F.Identity[U])),
))), ))),
) )
} }

View File

@@ -18,7 +18,7 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// addToMap makes a deep copy of a map and adds a value // addToMap makes a deep copy of a map and adds a value
@@ -31,23 +31,23 @@ func addToMap[A comparable](a A, m map[A]bool) map[A]bool {
return cpy return cpy
} }
func Uniq[AS ~func() O.Option[T.Tuple2[AS, A]], K comparable, A any](f func(A) K) func(as AS) AS { func Uniq[AS ~func() O.Option[P.Pair[AS, A]], K comparable, A any](f func(A) K) func(as AS) AS {
var recurse func(as AS, mp map[K]bool) AS var recurse func(as AS, mp map[K]bool) AS
recurse = func(as AS, mp map[K]bool) AS { recurse = func(as AS, mp map[K]bool) AS {
return F.Nullary2( return F.Nullary2(
as, as,
O.Chain(func(a T.Tuple2[AS, A]) O.Option[T.Tuple2[AS, A]] { O.Chain(func(a P.Pair[AS, A]) O.Option[P.Pair[AS, A]] {
return F.Pipe3( return F.Pipe3(
a.F2, P.Tail(a),
f, f,
O.FromPredicate(func(k K) bool { O.FromPredicate(func(k K) bool {
_, ok := mp[k] _, ok := mp[k]
return !ok return !ok
}), }),
O.Fold(recurse(a.F1, mp), func(k K) O.Option[T.Tuple2[AS, A]] { O.Fold(recurse(P.Head(a), mp), func(k K) O.Option[P.Pair[AS, A]] {
return O.Of(T.MakeTuple2(recurse(a.F1, addToMap(k, mp)), a.F2)) return O.Of(P.MakePair(recurse(P.Head(a), addToMap(k, mp)), P.Tail(a)))
}), }),
) )
}), }),
@@ -57,6 +57,6 @@ func Uniq[AS ~func() O.Option[T.Tuple2[AS, A]], K comparable, A any](f func(A) K
return F.Bind2nd(recurse, make(map[K]bool, 0)) return F.Bind2nd(recurse, make(map[K]bool, 0))
} }
func StrictUniq[AS ~func() O.Option[T.Tuple2[AS, A]], A comparable](as AS) AS { func StrictUniq[AS ~func() O.Option[P.Pair[AS, A]], A comparable](as AS) AS {
return Uniq[AS](F.Identity[A])(as) return Uniq[AS](F.Identity[A])(as)
} }

View File

@@ -18,29 +18,29 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one // ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one
// input iterator is short, excess elements of the longer iterator are discarded. // input iterator is short, excess elements of the longer iterator are discarded.
func ZipWith[AS ~func() O.Option[T.Tuple2[AS, A]], BS ~func() O.Option[T.Tuple2[BS, B]], CS ~func() O.Option[T.Tuple2[CS, C]], FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS { func ZipWith[AS ~func() O.Option[P.Pair[AS, A]], BS ~func() O.Option[P.Pair[BS, B]], CS ~func() O.Option[P.Pair[CS, C]], FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
// pre-declare to avoid cyclic reference // pre-declare to avoid cyclic reference
var m func(T.Tuple2[O.Option[T.Tuple2[AS, A]], O.Option[T.Tuple2[BS, B]]]) O.Option[T.Tuple2[CS, C]] var m func(P.Pair[O.Option[P.Pair[AS, A]], O.Option[P.Pair[BS, B]]]) O.Option[P.Pair[CS, C]]
recurse := func(as AS, bs BS) CS { recurse := func(as AS, bs BS) CS {
return func() O.Option[T.Tuple2[CS, C]] { return func() O.Option[P.Pair[CS, C]] {
// combine // combine
return F.Pipe1( return F.Pipe1(
T.MakeTuple2(as(), bs()), P.MakePair(as(), bs()),
m, m,
) )
} }
} }
m = F.Flow2( m = F.Flow2(
O.SequenceTuple2[T.Tuple2[AS, A], T.Tuple2[BS, B]], O.SequencePair[P.Pair[AS, A], P.Pair[BS, B]],
O.Map(func(t T.Tuple2[T.Tuple2[AS, A], T.Tuple2[BS, B]]) T.Tuple2[CS, C] { O.Map(func(t P.Pair[P.Pair[AS, A], P.Pair[BS, B]]) P.Pair[CS, C] {
return T.MakeTuple2(recurse(t.F1.F1, t.F2.F1), f(t.F1.F2, t.F2.F2)) return P.MakePair(recurse(P.Head(P.Head(t)), P.Head(P.Tail(t))), f(P.Tail(P.Head(t)), P.Tail(P.Tail(t))))
})) }))
// trigger the recursion // trigger the recursion
@@ -49,6 +49,6 @@ func ZipWith[AS ~func() O.Option[T.Tuple2[AS, A]], BS ~func() O.Option[T.Tuple2[
// Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the // Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the
// longer iterator are discarded // longer iterator are discarded
func Zip[AS ~func() O.Option[T.Tuple2[AS, A]], BS ~func() O.Option[T.Tuple2[BS, B]], CS ~func() O.Option[T.Tuple2[CS, T.Tuple2[A, B]]], A, B any](fb BS) func(AS) CS { func Zip[AS ~func() O.Option[P.Pair[AS, A]], BS ~func() O.Option[P.Pair[BS, B]], CS ~func() O.Option[P.Pair[CS, P.Pair[A, B]]], A, B any](fb BS) func(AS) CS {
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) T.Tuple2[A, B]])(fb, T.MakeTuple2[A, B]) return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) P.Pair[A, B]])(fb, P.MakePair[A, B])
} }

View File

@@ -20,19 +20,19 @@ import (
L "github.com/IBM/fp-go/lazy" L "github.com/IBM/fp-go/lazy"
M "github.com/IBM/fp-go/monoid" M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// Iterator represents a stateless, pure way to iterate over a sequence // Iterator represents a stateless, pure way to iterate over a sequence
type Iterator[U any] L.Lazy[O.Option[T.Tuple2[Iterator[U], U]]] type Iterator[U any] L.Lazy[O.Option[P.Pair[Iterator[U], U]]]
// Next returns the [Iterator] for the next element in an iterator `T.Tuple2` // Next returns the [Iterator] for the next element in an iterator `P.Pair`
func Next[U any](m T.Tuple2[Iterator[U], U]) Iterator[U] { func Next[U any](m P.Pair[Iterator[U], U]) Iterator[U] {
return G.Next(m) return G.Next(m)
} }
// Current returns the current element in an [Iterator] `T.Tuple2` // Current returns the current element in an [Iterator] `P.Pair`
func Current[U any](m T.Tuple2[Iterator[U], U]) U { func Current[U any](m P.Pair[Iterator[U], U]) U {
return G.Current(m) return G.Current(m)
} }

View File

@@ -19,7 +19,7 @@ import (
"testing" "testing"
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -29,14 +29,14 @@ func TestScan(t *testing.T) {
dst := F.Pipe1( dst := F.Pipe1(
src, src,
Scan(func(cur T.Tuple2[int, string], val string) T.Tuple2[int, string] { Scan(func(cur P.Pair[int, string], val string) P.Pair[int, string] {
return T.MakeTuple2(cur.F1+1, val) return P.MakePair(P.Head(cur)+1, val)
}, T.MakeTuple2(0, "")), }, P.MakePair(0, "")),
) )
assert.Equal(t, ToArray(From( assert.Equal(t, ToArray(From(
T.MakeTuple2(1, "a"), P.MakePair(1, "a"),
T.MakeTuple2(2, "b"), P.MakePair(2, "b"),
T.MakeTuple2(3, "c"), P.MakePair(3, "c"),
)), ToArray(dst)) )), ToArray(dst))
} }

View File

@@ -17,7 +17,7 @@ package stateless
import ( import (
G "github.com/IBM/fp-go/iterator/stateless/generic" G "github.com/IBM/fp-go/iterator/stateless/generic"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
) )
// ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one // ZipWith applies a function to pairs of elements at the same index in two iterators, collecting the results in a new iterator. If one
@@ -28,6 +28,6 @@ func ZipWith[FCT ~func(A, B) C, A, B, C any](fa Iterator[A], fb Iterator[B], f F
// Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the // Zip takes two iterators and returns an iterators of corresponding pairs. If one input iterators is short, excess elements of the
// longer iterator are discarded // longer iterator are discarded
func Zip[A, B any](fb Iterator[B]) func(Iterator[A]) Iterator[T.Tuple2[A, B]] { func Zip[A, B any](fb Iterator[B]) func(Iterator[A]) Iterator[P.Pair[A, B]] {
return G.Zip[Iterator[A], Iterator[B], Iterator[T.Tuple2[A, B]]](fb) return G.Zip[Iterator[A], Iterator[B], Iterator[P.Pair[A, B]]](fb)
} }

View File

@@ -19,7 +19,7 @@ import (
"fmt" "fmt"
"testing" "testing"
T "github.com/IBM/fp-go/tuple" P "github.com/IBM/fp-go/pair"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -40,5 +40,5 @@ func TestZip(t *testing.T) {
res := Zip[string](left)(right) res := Zip[string](left)(right)
assert.Equal(t, ToArray(From(T.MakeTuple2("a", 1), T.MakeTuple2("b", 2), T.MakeTuple2("c", 3))), ToArray(res)) assert.Equal(t, ToArray(From(P.MakePair("a", 1), P.MakePair("b", 2), P.MakePair("c", 3))), ToArray(res))
} }

30
option/pair.go Normal file
View File

@@ -0,0 +1,30 @@
// 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 option
import (
P "github.com/IBM/fp-go/pair"
PG "github.com/IBM/fp-go/pair/generic"
)
// SequencePair converts a [Pair] of [Option[T]] into an [Option[Pair]].
func SequencePair[T1, T2 any](t P.Pair[Option[T1], Option[T2]]) Option[P.Pair[T1, T2]] {
return PG.SequencePair(
Map[T1, func(T2) P.Pair[T1, T2]],
Ap[P.Pair[T1, T2], T2],
t,
)
}

71
pair/generic/sequence.go Normal file
View File

@@ -0,0 +1,71 @@
// 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 generic
import (
F "github.com/IBM/fp-go/function"
P "github.com/IBM/fp-go/pair"
)
// SequencePair is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes a [Pair] of higher higher kinded types and returns a higher kinded type of a [Pair] with the resolved values.
func SequencePair[
MAP ~func(func(T1) func(T2) P.Pair[T1, T2]) func(HKT_T1) HKT_F_T2,
AP1 ~func(HKT_T2) func(HKT_F_T2) HKT_PAIR,
T1,
T2,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_F_T2, // HKT[func(T2) P.Pair[T1, T2]]
HKT_PAIR any, // HKT[Pair[T1, T2]]
](
fmap MAP,
fap1 AP1,
t P.Pair[HKT_T1, HKT_T2],
) HKT_PAIR {
return F.Pipe2(
P.Head(t),
fmap(F.Curry2(P.MakePair[T1, T2])),
fap1(P.Tail(t)),
)
}
// TraversePair is a utility function used to implement the sequence operation for higher kinded types based only on map and ap.
// The function takes a [Pair] of base types and 2 functions that transform these based types into higher higher kinded types. It returns a higher kinded type of a [Pair] with the resolved values.
func TraversePair[
MAP ~func(func(T1) func(T2) P.Pair[T1, T2]) func(HKT_T1) HKT_F_T2,
AP1 ~func(HKT_T2) func(HKT_F_T2) HKT_PAIR,
F1 ~func(A1) HKT_T1,
F2 ~func(A2) HKT_T2,
A1, T1,
A2, T2,
HKT_T1, // HKT[T1]
HKT_T2, // HKT[T2]
HKT_F_T2, // HKT[func(T2) P.Pair[T1, T2]]
HKT_PAIR any, // HKT[Pair[T1, T2]]
](
fmap MAP,
fap1 AP1,
f1 F1,
f2 F2,
t P.Pair[A1, A2],
) HKT_PAIR {
return F.Pipe2(
f1(P.Head(t)),
fmap(F.Curry2(P.MakePair[T1, T2])),
fap1(f2(P.Tail(t))),
)
}

View File

@@ -25,7 +25,7 @@ import (
type ( type (
pair struct { pair struct {
head, Tail any h, t any
} }
// Pair defines a data structure that holds two strongly typed values // Pair defines a data structure that holds two strongly typed values
@@ -36,7 +36,7 @@ type (
// //
// go:noinline // go:noinline
func pairString(s *pair) string { func pairString(s *pair) string {
return fmt.Sprintf("Pair[%T, %t](%v, %v)", s.head, s.Tail, s.head, s.Tail) return fmt.Sprintf("Pair[%T, %t](%v, %v)", s.h, s.t, s.h, s.t)
} }
// Format prints some debug info for the object // Format prints some debug info for the object
@@ -63,12 +63,12 @@ func (s Pair[A, B]) Format(f fmt.State, c rune) {
// Of creates a [Pair] with the same value to to both fields // Of creates a [Pair] with the same value to to both fields
func Of[A any](value A) Pair[A, A] { func Of[A any](value A) Pair[A, A] {
return Pair[A, A]{head: value, Tail: value} return Pair[A, A]{h: value, t: value}
} }
// FromTuple creates a [Pair] from a [T.Tuple2] // FromTuple creates a [Pair] from a [T.Tuple2]
func FromTuple[A, B any](t T.Tuple2[A, B]) Pair[A, B] { func FromTuple[A, B any](t T.Tuple2[A, B]) Pair[A, B] {
return Pair[A, B]{head: t.F1, Tail: t.F2} return Pair[A, B]{h: t.F1, t: t.F2}
} }
// ToTuple creates a [T.Tuple2] from a [Pair] // ToTuple creates a [T.Tuple2] from a [Pair]
@@ -78,22 +78,22 @@ func ToTuple[A, B any](t Pair[A, B]) T.Tuple2[A, B] {
// MakePair creates a [Pair] from two values // MakePair creates a [Pair] from two values
func MakePair[A, B any](a A, b B) Pair[A, B] { func MakePair[A, B any](a A, b B) Pair[A, B] {
return Pair[A, B]{head: a, Tail: b} return Pair[A, B]{h: a, t: b}
} }
// Head returns the head value of the pair // Head returns the head value of the pair
func Head[A, B any](fa Pair[A, B]) A { func Head[A, B any](fa Pair[A, B]) A {
return fa.head.(A) return fa.h.(A)
} }
// Tail returns the head value of the pair // Tail returns the head value of the pair
func Tail[A, B any](fa Pair[A, B]) B { func Tail[A, B any](fa Pair[A, B]) B {
return fa.Tail.(B) return fa.t.(B)
} }
// MonadMapHead maps the head value // MonadMapHead maps the head value
func MonadMapHead[B, A, A1 any](fa Pair[A, B], f func(A) A1) Pair[A1, B] { 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.Tail} return Pair[A1, B]{f(Head(fa)), fa.t}
} }
// MonadMap maps the head value // MonadMap maps the head value
@@ -103,7 +103,7 @@ func MonadMap[B, A, A1 any](fa Pair[A, B], f func(A) A1) Pair[A1, B] {
// MonadMapTail maps the Tail value // MonadMapTail maps the Tail value
func MonadMapTail[A, B, B1 any](fa Pair[A, B], f func(B) B1) Pair[A, B1] { func MonadMapTail[A, B, B1 any](fa Pair[A, B], f func(B) B1) Pair[A, B1] {
return Pair[A, B1]{fa.head, f(Tail(fa))} return Pair[A, B1]{fa.h, f(Tail(fa))}
} }
// MonadBiMap maps both values // MonadBiMap maps both values
@@ -136,13 +136,13 @@ func BiMap[A, B, A1, B1 any](f func(A) A1, g func(B) B1) func(Pair[A, B]) Pair[A
// MonadChainHead chains on the head value // 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] { 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)) fb := f(Head(fa))
return Pair[A1, B]{fb.head, sg.Concat(Tail(fa), Tail(fb))} return Pair[A1, B]{fb.h, sg.Concat(Tail(fa), Tail(fb))}
} }
// MonadChainTail chains on the Tail value // 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] { 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)) fa := f(Tail(fb))
return Pair[A, B1]{sg.Concat(Head(fb), Head(fa)), fa.Tail} return Pair[A, B1]{sg.Concat(Head(fb), Head(fa)), fa.t}
} }
// MonadChain chains on the head value // MonadChain chains on the head value
@@ -202,3 +202,30 @@ func ApTail[A, B, B1 any](sg Sg.Semigroup[A], fb Pair[A, B]) func(Pair[A, func(B
func Ap[B, A, A1 any](sg Sg.Semigroup[B], fa Pair[A, B]) func(Pair[func(A) A1, B]) Pair[A1, B] { 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) 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))
}
}