mirror of
https://github.com/IBM/fp-go.git
synced 2025-09-01 19:56:12 +02:00
Compare commits
14 Commits
cleue-swit
...
v1.0.132
Author | SHA1 | Date | |
---|---|---|---|
|
6ab6ff094b | ||
|
e6e35d643c | ||
|
01d490b710 | ||
|
01786a054b | ||
|
d0e4984b60 | ||
|
51ed1693a5 | ||
|
0afedbd7fe | ||
|
3f1bde219a | ||
|
6f91e91eb9 | ||
|
9f6b6d4968 | ||
|
79652d8474 | ||
|
a774d63e66 | ||
|
d86cf55a3d | ||
|
8150ae2a68 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.20.x', '1.21.x']
|
||||
go-version: [ '1.20.x', '1.21.x', '1.22.x']
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
|
@@ -15,6 +15,10 @@
|
||||
|
||||
package bytes
|
||||
|
||||
func Empty() []byte {
|
||||
return Monoid.Empty()
|
||||
}
|
||||
|
||||
func ToString(a []byte) string {
|
||||
return string(a)
|
||||
}
|
||||
|
40
cli/tuple.go
40
cli/tuple.go
@@ -405,8 +405,6 @@ func generateTupleHelpers(filename string, count int) error {
|
||||
|
||||
fmt.Fprintf(f, `
|
||||
import (
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/ord"
|
||||
)
|
||||
@@ -457,7 +455,7 @@ func generateTupleMarshal(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "func (t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
|
||||
fmt.Fprintf(f, " return json.Marshal([]any{")
|
||||
fmt.Fprintf(f, " return tupleMarshalJSON(")
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
@@ -465,7 +463,7 @@ func generateTupleMarshal(f *os.File, i int) {
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, "})\n")
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
@@ -475,19 +473,12 @@ func generateTupleUnmarshal(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "func (t *")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") UnmarshalJSON(data []byte) error {\n")
|
||||
fmt.Fprintf(f, " var tmp []json.RawMessage\n")
|
||||
fmt.Fprintf(f, " if err := json.Unmarshal(data, &tmp); err != nil {return err}\n")
|
||||
fmt.Fprintf(f, " l := len(tmp)\n")
|
||||
// unmarshal fields
|
||||
fmt.Fprintf(f, " return tupleUnmarshalJSON(data")
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " if l > %d {\n", j-1)
|
||||
fmt.Fprintf(f, " if err := json.Unmarshal(tmp[%d], &t.F%d); err != nil {return err}\n", j-1, j)
|
||||
fmt.Fprintf(f, ", &t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " ")
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, "}")
|
||||
}
|
||||
fmt.Fprintf(f, "\n return nil\n")
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
@@ -570,30 +561,13 @@ func generateTupleString(f *os.File, i int) {
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") String() string {\n")
|
||||
// convert to string
|
||||
fmt.Fprintf(f, " return fmt.Sprintf(\"Tuple%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", "%T")
|
||||
}
|
||||
fmt.Fprintf(f, "](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", "%v")
|
||||
}
|
||||
fmt.Fprintf(f, ")\", ")
|
||||
fmt.Fprint(f, " return tupleString(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
@@ -47,5 +47,5 @@ func ExampleReadFile() {
|
||||
fmt.Println(result())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](Carsten)
|
||||
// Right[string](Carsten)
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ import (
|
||||
func onWriteAll[W io.Writer](data []byte) func(w W) RIOE.ReaderIOEither[[]byte] {
|
||||
return func(w W) RIOE.ReaderIOEither[[]byte] {
|
||||
return F.Pipe1(
|
||||
RIOE.TryCatch(func(ctx context.Context) func() ([]byte, error) {
|
||||
RIOE.TryCatch(func(_ context.Context) func() ([]byte, error) {
|
||||
return func() ([]byte, error) {
|
||||
_, err := w.Write(data)
|
||||
return data, err
|
||||
|
@@ -182,10 +182,7 @@ func withCancelCauseFunc[
|
||||
ma,
|
||||
IOE.Swap[GIOA, func() E.Either[A, error]],
|
||||
IOE.ChainFirstIOK[func() E.Either[A, error], func() any](func(err error) func() any {
|
||||
return IO.MakeIO[func() any](func() any {
|
||||
cancel(err)
|
||||
return nil
|
||||
})
|
||||
return IO.FromImpure[func() any](func() { cancel(err) })
|
||||
}),
|
||||
IOE.Swap[func() E.Either[A, error], GIOA],
|
||||
)
|
||||
|
@@ -32,7 +32,7 @@ import (
|
||||
func TestBuilderWithQuery(t *testing.T) {
|
||||
// add some query
|
||||
withLimit := R.WithQueryArg("limit")("10")
|
||||
withURL := R.WithUrl("http://www.example.org?a=b")
|
||||
withURL := R.WithURL("http://www.example.org?a=b")
|
||||
|
||||
b := F.Pipe2(
|
||||
R.Default,
|
||||
|
@@ -26,7 +26,7 @@ import (
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
IOEF "github.com/IBM/fp-go/ioeither/file"
|
||||
J "github.com/IBM/fp-go/json"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -79,7 +79,7 @@ func ReadFullResponse(client Client) func(Requester) RIOE.ReaderIOEither[H.FullR
|
||||
IOE.Of[error, 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)),
|
||||
)
|
||||
}),
|
||||
)
|
||||
@@ -109,17 +109,21 @@ func ReadJson[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
|
||||
return ReadJSON[A](client)
|
||||
}
|
||||
|
||||
// ReadJSON sends a request, reads the response and parses the response as JSON
|
||||
func ReadJSON[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
|
||||
func readJSON(client Client) func(Requester) RIOE.ReaderIOEither[[]byte] {
|
||||
return F.Flow3(
|
||||
ReadFullResponse(client),
|
||||
RIOE.ChainFirstEitherK(F.Flow2(
|
||||
H.Response,
|
||||
H.ValidateJSONResponse,
|
||||
)),
|
||||
RIOE.ChainEitherK(F.Flow2(
|
||||
H.Body,
|
||||
J.Unmarshal[A],
|
||||
)),
|
||||
RIOE.Map(H.Body),
|
||||
)
|
||||
}
|
||||
|
||||
// ReadJSON sends a request, reads the response and parses the response as JSON
|
||||
func ReadJSON[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
|
||||
return F.Flow2(
|
||||
readJSON(client),
|
||||
RIOE.ChainEitherK(J.Unmarshal[A]),
|
||||
)
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ func eraseTuple[A, R any](f func(A) IOE.IOEither[error, R]) func(E.Either[error,
|
||||
}
|
||||
|
||||
func eraseProviderFactory0[R any](f IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
||||
return func(params ...any) IOE.IOEither[error, any] {
|
||||
return func(_ ...any) IOE.IOEither[error, any] {
|
||||
return F.Pipe1(
|
||||
f,
|
||||
IOE.Map[error](F.ToAny[R]),
|
||||
|
@@ -20,30 +20,45 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
// Either defines a data structure that logically holds either an E or an A. The flag discriminates the cases
|
||||
Either[E, A any] struct {
|
||||
either struct {
|
||||
isLeft bool
|
||||
left E
|
||||
right A
|
||||
value any
|
||||
}
|
||||
|
||||
// Either defines a data structure that logically holds either an E or an A. The flag discriminates the cases
|
||||
Either[E, A any] either
|
||||
)
|
||||
|
||||
// String prints some debug info for the object
|
||||
func (s Either[E, A]) String() string {
|
||||
//
|
||||
// go:noinline
|
||||
func eitherString(s *either) string {
|
||||
if s.isLeft {
|
||||
return fmt.Sprintf("Left[%T, %T](%v)", s.left, s.right, s.left)
|
||||
return fmt.Sprintf("Left[%T](%v)", s.value, s.value)
|
||||
}
|
||||
return fmt.Sprintf("Right[%T, %T](%v)", s.left, s.right, s.right)
|
||||
return fmt.Sprintf("Right[%T](%v)", s.value, s.value)
|
||||
}
|
||||
|
||||
// Format prints some debug info for the object
|
||||
//
|
||||
// go:noinline
|
||||
func eitherFormat(e *either, f fmt.State, c rune) {
|
||||
switch c {
|
||||
case 's':
|
||||
fmt.Fprint(f, eitherString(e))
|
||||
default:
|
||||
fmt.Fprint(f, eitherString(e))
|
||||
}
|
||||
}
|
||||
|
||||
// String prints some debug info for the object
|
||||
func (s Either[E, A]) String() string {
|
||||
return eitherString((*either)(&s))
|
||||
}
|
||||
|
||||
// Format prints some debug info for the object
|
||||
func (s Either[E, A]) Format(f fmt.State, c rune) {
|
||||
switch c {
|
||||
case 's':
|
||||
fmt.Fprint(f, s.String())
|
||||
default:
|
||||
fmt.Fprint(f, s.String())
|
||||
}
|
||||
eitherFormat((*either)(&s), f, c)
|
||||
}
|
||||
|
||||
// IsLeft tests if the [Either] is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
|
||||
@@ -58,23 +73,29 @@ func IsRight[E, A any](val Either[E, A]) bool {
|
||||
|
||||
// Left creates a new instance of an [Either] representing the left value.
|
||||
func Left[A, E any](value E) Either[E, A] {
|
||||
return Either[E, A]{isLeft: true, left: value}
|
||||
return Either[E, A]{true, value}
|
||||
}
|
||||
|
||||
// Right creates a new instance of an [Either] representing the right value.
|
||||
func Right[E, A any](value A) Either[E, A] {
|
||||
return Either[E, A]{isLeft: false, right: value}
|
||||
return Either[E, A]{false, value}
|
||||
}
|
||||
|
||||
// MonadFold extracts the values from an [Either] by invoking the [onLeft] callback or the [onRight] callback depending on the case
|
||||
func MonadFold[E, A, B any](ma Either[E, A], onLeft func(e E) B, onRight func(a A) B) B {
|
||||
if ma.isLeft {
|
||||
return onLeft(ma.left)
|
||||
return onLeft(ma.value.(E))
|
||||
}
|
||||
return onRight(ma.right)
|
||||
return onRight(ma.value.(A))
|
||||
}
|
||||
|
||||
// Unwrap converts an [Either] into the idiomatic tuple
|
||||
func Unwrap[E, A any](ma Either[E, A]) (A, E) {
|
||||
return ma.right, ma.left
|
||||
if ma.isLeft {
|
||||
var a A
|
||||
return a, ma.value.(E)
|
||||
} else {
|
||||
var e E
|
||||
return ma.value.(A), e
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ package either
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
@@ -26,12 +27,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDefault(t *testing.T) {
|
||||
var e Either[error, string]
|
||||
|
||||
assert.Equal(t, Of[error](""), e)
|
||||
}
|
||||
|
||||
func TestIsLeft(t *testing.T) {
|
||||
err := errors.New("Some error")
|
||||
withError := Left[string](err)
|
||||
@@ -115,3 +110,13 @@ func TestFromOption(t *testing.T) {
|
||||
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
|
||||
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
|
||||
}
|
||||
|
||||
func TestStringer(t *testing.T) {
|
||||
e := Of[error]("foo")
|
||||
exp := "Right[string](foo)"
|
||||
|
||||
assert.Equal(t, exp, e.String())
|
||||
|
||||
var s fmt.Stringer = e
|
||||
assert.Equal(t, exp, s.String())
|
||||
}
|
||||
|
@@ -48,11 +48,11 @@ func ExampleEither_creation() {
|
||||
fmt.Println(rightFromPred)
|
||||
|
||||
// Output:
|
||||
// Left[*errors.errorString, string](some error)
|
||||
// Right[<nil>, string](value)
|
||||
// Left[*errors.errorString, *string](value was nil)
|
||||
// Left[*errors.errorString](some error)
|
||||
// Right[string](value)
|
||||
// Left[*errors.errorString](value was nil)
|
||||
// true
|
||||
// Left[*errors.errorString, int](3 is an odd number)
|
||||
// Right[<nil>, int](4)
|
||||
// Left[*errors.errorString](3 is an odd number)
|
||||
// Right[int](4)
|
||||
|
||||
}
|
||||
|
@@ -53,8 +53,8 @@ func ExampleEither_extraction() {
|
||||
fmt.Println(doubleFromRightBis)
|
||||
|
||||
// Output:
|
||||
// Left[*errors.errorString, int](Division by Zero!)
|
||||
// Right[<nil>, int](10)
|
||||
// Left[*errors.errorString](Division by Zero!)
|
||||
// Right[int](10)
|
||||
// 0
|
||||
// 10
|
||||
// 0
|
||||
|
@@ -16,18 +16,18 @@
|
||||
package exec
|
||||
|
||||
import (
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
type (
|
||||
// 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
|
||||
CommandOutput = T.Tuple2[[]byte, []byte]
|
||||
CommandOutput = P.Pair[[]byte, []byte]
|
||||
)
|
||||
|
||||
var (
|
||||
// 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 = T.Second[[]byte, []byte]
|
||||
StdErr = P.Tail[[]byte, []byte]
|
||||
)
|
||||
|
@@ -25,13 +25,13 @@ func Memoize[K comparable, T any](f func(K) T) func(K) T {
|
||||
}
|
||||
|
||||
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
|
||||
func ContramapMemoize[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
|
||||
func ContramapMemoize[T, A any, K comparable](kf func(A) K) func(func(A) T) func(A) T {
|
||||
return G.ContramapMemoize[func(A) T](kf)
|
||||
}
|
||||
|
||||
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
|
||||
func CacheCallback[
|
||||
A any, K comparable, T any](kf func(A) K, getOrCreate func(K, func() func() T) func() T) func(func(A) T) func(A) T {
|
||||
T, A any, K comparable](kf func(A) K, getOrCreate func(K, func() func() T) func() T) func(func(A) T) func(A) T {
|
||||
return G.CacheCallback[func(func(A) T) func(A) T](kf, getOrCreate)
|
||||
}
|
||||
|
||||
|
@@ -16,9 +16,14 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
B "github.com/IBM/fp-go/bytes"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
ENDO "github.com/IBM/fp-go/endomorphism"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
@@ -29,6 +34,7 @@ import (
|
||||
LZ "github.com/IBM/fp-go/lazy"
|
||||
L "github.com/IBM/fp-go/optics/lens"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
R "github.com/IBM/fp-go/record"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
@@ -138,6 +144,9 @@ var (
|
||||
WithBytes,
|
||||
ENDO.Chain(WithContentType(C.FormEncoded)),
|
||||
)
|
||||
|
||||
// bodyAsBytes returns a []byte with a fallback to the empty array
|
||||
bodyAsBytes = O.Fold(B.Empty, E.Fold(F.Ignore1of1[error](B.Empty), F.Identity[[]byte]))
|
||||
)
|
||||
|
||||
func setRawQuery(u *url.URL, raw string) *url.URL {
|
||||
@@ -272,6 +281,11 @@ func (builder *Builder) GetHeaderValues(name string) []string {
|
||||
return builder.headers.Values(name)
|
||||
}
|
||||
|
||||
// GetHash returns a hash value for the builder that can be used as a cache key
|
||||
func (builder *Builder) GetHash() string {
|
||||
return MakeHash(builder)
|
||||
}
|
||||
|
||||
// Header returns a [L.Lens] for a single header
|
||||
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
||||
get := getHeader(name)
|
||||
@@ -342,3 +356,32 @@ func WithQueryArg(name string) func(value string) Endomorphism {
|
||||
func WithoutQueryArg(name string) Endomorphism {
|
||||
return QueryArg(name).Set(noQueryArg)
|
||||
}
|
||||
|
||||
func hashWriteValue(buf *bytes.Buffer, value string) *bytes.Buffer {
|
||||
buf.WriteString(value)
|
||||
return buf
|
||||
}
|
||||
|
||||
func hashWriteQuery(name string, buf *bytes.Buffer, values []string) *bytes.Buffer {
|
||||
buf.WriteString(name)
|
||||
return A.Reduce(hashWriteValue, buf)(values)
|
||||
}
|
||||
|
||||
func makeBytes(b *Builder) []byte {
|
||||
var buf bytes.Buffer
|
||||
|
||||
buf.WriteString(b.GetMethod())
|
||||
buf.WriteString(b.GetURL())
|
||||
b.GetHeaders().Write(&buf) // #nosec: G104
|
||||
|
||||
R.ReduceOrdWithIndex[[]string, *bytes.Buffer](S.Ord)(hashWriteQuery, &buf)(b.GetQuery())
|
||||
|
||||
buf.Write(bodyAsBytes(b.GetBody()))
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// MakeHash converts a [Builder] into a hash string, convenient to use as a cache key
|
||||
func MakeHash(b *Builder) string {
|
||||
return fmt.Sprintf("%x", sha256.Sum256(makeBytes(b)))
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
@@ -66,3 +67,27 @@ func TestWithFormData(t *testing.T) {
|
||||
|
||||
assert.Equal(t, C.FormEncoded, Headers.Get(res).Get(H.ContentType))
|
||||
}
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
|
||||
b1 := F.Pipe4(
|
||||
Default,
|
||||
WithContentType(C.JSON),
|
||||
WithHeader(H.Accept)(C.JSON),
|
||||
WithURL("http://www.example.com"),
|
||||
WithJSON(map[string]string{"a": "b"}),
|
||||
)
|
||||
|
||||
b2 := F.Pipe4(
|
||||
Default,
|
||||
WithURL("http://www.example.com"),
|
||||
WithHeader(H.Accept)(C.JSON),
|
||||
WithContentType(C.JSON),
|
||||
WithJSON(map[string]string{"a": "b"}),
|
||||
)
|
||||
|
||||
assert.Equal(t, MakeHash(b1), MakeHash(b2))
|
||||
assert.NotEqual(t, MakeHash(Default), MakeHash(b2))
|
||||
|
||||
fmt.Println(MakeHash(b1))
|
||||
}
|
||||
|
@@ -18,15 +18,15 @@ package http
|
||||
import (
|
||||
H "net/http"
|
||||
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
type (
|
||||
// FullResponse represents a full http response, including headers and body
|
||||
FullResponse = T.Tuple2[*H.Response, []byte]
|
||||
FullResponse = P.Pair[*H.Response, []byte]
|
||||
)
|
||||
|
||||
var (
|
||||
Response = T.First[*H.Response, []byte]
|
||||
Body = T.Second[*H.Response, []byte]
|
||||
Response = P.Head[*H.Response, []byte]
|
||||
Body = P.Tail[*H.Response, []byte]
|
||||
)
|
||||
|
@@ -28,12 +28,12 @@ import (
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
R "github.com/IBM/fp-go/record/generic"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
type (
|
||||
ParsedMediaType = T.Tuple2[string, map[string]string]
|
||||
ParsedMediaType = P.Pair[string, map[string]string]
|
||||
|
||||
HttpError struct {
|
||||
statusCode int
|
||||
@@ -45,17 +45,15 @@ type (
|
||||
|
||||
var (
|
||||
// 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 = E.FromPredicate(isValidStatus, StatusCodeError)
|
||||
// alidateJsonContentTypeString parses a content type a validates that it is valid JSON
|
||||
validateJSONContentTypeString = F.Flow2(
|
||||
ParseMediaType,
|
||||
E.ChainFirst(F.Flow2(
|
||||
T.First[string, map[string]string],
|
||||
E.FromPredicate(reJSONMimeType.MatchString, func(mimeType string) error {
|
||||
return fmt.Errorf("mimetype [%s] is not a valid JSON content type", mimeType)
|
||||
}),
|
||||
P.Head[string, map[string]string],
|
||||
E.FromPredicate(isJSONMimeType, errors.OnSome[string]("mimetype [%s] is not a valid JSON content type")),
|
||||
)),
|
||||
)
|
||||
// ValidateJSONResponse checks if an HTTP response is a valid JSON response
|
||||
@@ -81,7 +79,7 @@ const (
|
||||
// ParseMediaType parses a media type into a tuple
|
||||
func ParseMediaType(mediaType string) E.Either[error, ParsedMediaType] {
|
||||
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
|
||||
|
@@ -36,7 +36,7 @@ func Map[A, B any](f func(A) B) func(A) B {
|
||||
return G.Map(f)
|
||||
}
|
||||
|
||||
func MonadMapTo[A, B any](fa A, b B) B {
|
||||
func MonadMapTo[A, B any](_ A, b B) B {
|
||||
return b
|
||||
}
|
||||
|
||||
|
@@ -20,13 +20,19 @@ import (
|
||||
|
||||
E "github.com/IBM/fp-go/eq"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
L "github.com/IBM/fp-go/internal/apply/testing"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Applicative identity law
|
||||
//
|
||||
// A.ap(A.of(a => a), fa) <-> fa
|
||||
//
|
||||
// Deprecated: use [ApplicativeAssertIdentity]
|
||||
func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
|
||||
eq E.Eq[HKTA],
|
||||
|
||||
@@ -46,9 +52,33 @@ func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
|
||||
}
|
||||
}
|
||||
|
||||
// Applicative identity law
|
||||
//
|
||||
// A.ap(A.of(a => a), fa) <-> fa
|
||||
func ApplicativeAssertIdentity[HKTA, HKTFAA, A any](t *testing.T,
|
||||
eq E.Eq[HKTA],
|
||||
|
||||
ap applicative.Applicative[A, A, HKTA, HKTA, HKTFAA],
|
||||
paa pointed.Pointed[func(A) A, HKTFAA],
|
||||
|
||||
) func(fa HKTA) bool {
|
||||
// mark as test helper
|
||||
t.Helper()
|
||||
|
||||
return func(fa HKTA) bool {
|
||||
|
||||
left := ap.Ap(fa)(paa.Of(F.Identity[A]))
|
||||
right := fa
|
||||
|
||||
return assert.True(t, eq.Equals(left, right), "Applicative identity")
|
||||
}
|
||||
}
|
||||
|
||||
// Applicative homomorphism law
|
||||
//
|
||||
// A.ap(A.of(ab), A.of(a)) <-> A.of(ab(a))
|
||||
//
|
||||
// Deprecated: use [ApplicativeAssertHomomorphism]
|
||||
func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
|
||||
eq E.Eq[HKTB],
|
||||
|
||||
@@ -72,9 +102,35 @@ func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
|
||||
}
|
||||
}
|
||||
|
||||
// Applicative homomorphism law
|
||||
//
|
||||
// A.ap(A.of(ab), A.of(a)) <-> A.of(ab(a))
|
||||
func ApplicativeAssertHomomorphism[HKTA, HKTB, HKTFAB, A, B any](t *testing.T,
|
||||
eq E.Eq[HKTB],
|
||||
|
||||
apab applicative.Applicative[A, B, HKTA, HKTB, HKTFAB],
|
||||
pb pointed.Pointed[B, HKTB],
|
||||
pfab pointed.Pointed[func(A) B, HKTFAB],
|
||||
|
||||
ab func(A) B,
|
||||
) func(a A) bool {
|
||||
// mark as test helper
|
||||
t.Helper()
|
||||
|
||||
return func(a A) bool {
|
||||
|
||||
left := apab.Ap(apab.Of(a))(pfab.Of(ab))
|
||||
right := pb.Of(ab(a))
|
||||
|
||||
return assert.True(t, eq.Equals(left, right), "Applicative homomorphism")
|
||||
}
|
||||
}
|
||||
|
||||
// Applicative interchange law
|
||||
//
|
||||
// A.ap(fab, A.of(a)) <-> A.ap(A.of(ab => ab(a)), fab)
|
||||
//
|
||||
// Deprecated: use [ApplicativeAssertInterchange]
|
||||
func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
|
||||
eq E.Eq[HKTB],
|
||||
|
||||
@@ -103,7 +159,38 @@ func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
|
||||
}
|
||||
}
|
||||
|
||||
// Applicative interchange law
|
||||
//
|
||||
// A.ap(fab, A.of(a)) <-> A.ap(A.of(ab => ab(a)), fab)
|
||||
func ApplicativeAssertInterchange[HKTA, HKTB, HKTFAB, HKTABB, A, B any](t *testing.T,
|
||||
eq E.Eq[HKTB],
|
||||
|
||||
apab applicative.Applicative[A, B, HKTA, HKTB, HKTFAB],
|
||||
apabb applicative.Applicative[func(A) B, B, HKTFAB, HKTB, HKTABB],
|
||||
pabb pointed.Pointed[func(func(A) B) B, HKTABB],
|
||||
|
||||
ab func(A) B,
|
||||
) func(a A) bool {
|
||||
// mark as test helper
|
||||
t.Helper()
|
||||
|
||||
return func(a A) bool {
|
||||
|
||||
fab := apabb.Of(ab)
|
||||
|
||||
left := apab.Ap(apab.Of(a))(fab)
|
||||
|
||||
right := apabb.Ap(fab)(pabb.Of(func(ab func(A) B) B {
|
||||
return ab(a)
|
||||
}))
|
||||
|
||||
return assert.True(t, eq.Equals(left, right), "Applicative homomorphism")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange'
|
||||
//
|
||||
// Deprecated: use [ApplicativeAssertLaws] instead
|
||||
func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqb E.Eq[HKTB],
|
||||
@@ -150,3 +237,47 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A
|
||||
return apply(fa) && identity(fa) && homomorphism(a) && interchange(a)
|
||||
}
|
||||
}
|
||||
|
||||
// ApplicativeAssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange'
|
||||
func ApplicativeAssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqb E.Eq[HKTB],
|
||||
eqc E.Eq[HKTC],
|
||||
|
||||
fofb pointed.Pointed[B, HKTB],
|
||||
|
||||
fofaa pointed.Pointed[func(A) A, HKTAA],
|
||||
fofbc pointed.Pointed[func(B) C, HKTBC],
|
||||
|
||||
fofabb pointed.Pointed[func(func(A) B) B, HKTABB],
|
||||
|
||||
faa functor.Functor[A, A, HKTA, HKTA],
|
||||
|
||||
fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],
|
||||
|
||||
fapaa applicative.Applicative[A, A, HKTA, HKTA, HKTAA],
|
||||
fapab applicative.Applicative[A, B, HKTA, HKTB, HKTAB],
|
||||
fapbc apply.Apply[B, C, HKTB, HKTC, HKTBC],
|
||||
fapac apply.Apply[A, C, HKTA, HKTC, HKTAC],
|
||||
|
||||
fapabb applicative.Applicative[func(A) B, B, HKTAB, HKTB, HKTABB],
|
||||
fapabac applicative.Applicative[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(a A) bool {
|
||||
// mark as test helper
|
||||
t.Helper()
|
||||
|
||||
// apply laws
|
||||
apply := L.ApplyAssertLaws(t, eqa, eqc, applicative.ToPointed(fapabac), fofbc, faa, fmap, applicative.ToApply(fapab), fapbc, fapac, applicative.ToApply(fapabac), ab, bc)
|
||||
// applicative laws
|
||||
identity := ApplicativeAssertIdentity(t, eqa, fapaa, fofaa)
|
||||
homomorphism := ApplicativeAssertHomomorphism(t, eqb, fapab, fofb, applicative.ToPointed(fapabb), ab)
|
||||
interchange := ApplicativeAssertInterchange(t, eqb, fapab, fapabb, fofabb, ab)
|
||||
|
||||
return func(a A) bool {
|
||||
fa := fapaa.Of(a)
|
||||
return apply(fa) && identity(fa) && homomorphism(a) && interchange(a)
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ package applicative
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
)
|
||||
|
||||
@@ -24,3 +25,18 @@ type Applicative[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||
apply.Apply[A, B, HKTA, HKTB, HKTFAB]
|
||||
pointed.Pointed[A, HKTA]
|
||||
}
|
||||
|
||||
// ToFunctor converts from [Applicative] to [functor.Functor]
|
||||
func ToFunctor[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) functor.Functor[A, B, HKTA, HKTB] {
|
||||
return ap
|
||||
}
|
||||
|
||||
// ToApply converts from [Applicative] to [apply.Apply]
|
||||
func ToApply[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) apply.Apply[A, B, HKTA, HKTB, HKTFAB] {
|
||||
return ap
|
||||
}
|
||||
|
||||
// ToPointed converts from [Applicative] to [pointed.Pointed]
|
||||
func ToPointed[A, B, HKTA, HKTB, HKTFAB any](ap Applicative[A, B, HKTA, HKTB, HKTFAB]) pointed.Pointed[A, HKTA] {
|
||||
return ap
|
||||
}
|
||||
|
@@ -19,13 +19,18 @@ import (
|
||||
"testing"
|
||||
|
||||
E "github.com/IBM/fp-go/eq"
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
FCT "github.com/IBM/fp-go/internal/functor/testing"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Apply associative composition law
|
||||
//
|
||||
// F.ap(F.ap(F.map(fbc, bc => ab => a => bc(ab(a))), fab), fa) <-> F.ap(fbc, F.ap(fab, fa))
|
||||
//
|
||||
// Deprecated: use [ApplyAssertAssociativeComposition] instead
|
||||
func AssertAssociativeComposition[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
|
||||
eq E.Eq[HKTC],
|
||||
|
||||
@@ -63,7 +68,49 @@ func AssertAssociativeComposition[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC
|
||||
}
|
||||
}
|
||||
|
||||
// Apply associative composition law
|
||||
//
|
||||
// F.ap(F.ap(F.map(fbc, bc => ab => a => bc(ab(a))), fab), fa) <-> F.ap(fbc, F.ap(fab, fa))
|
||||
func ApplyAssertAssociativeComposition[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
|
||||
eq E.Eq[HKTC],
|
||||
|
||||
fofab pointed.Pointed[func(A) B, HKTAB],
|
||||
fofbc pointed.Pointed[func(B) C, HKTBC],
|
||||
|
||||
fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],
|
||||
|
||||
fapab apply.Apply[A, B, HKTA, HKTB, HKTAB],
|
||||
fapbc apply.Apply[B, C, HKTB, HKTC, HKTBC],
|
||||
fapac apply.Apply[A, C, HKTA, HKTC, HKTAC],
|
||||
|
||||
fapabac apply.Apply[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(fa HKTA) bool {
|
||||
t.Helper()
|
||||
return func(fa HKTA) bool {
|
||||
|
||||
fab := fofab.Of(ab)
|
||||
fbc := fofbc.Of(bc)
|
||||
|
||||
left := fapac.Ap(fa)(fapabac.Ap(fab)(fmap.Map(func(bc func(B) C) func(func(A) B) func(A) C {
|
||||
return func(ab func(A) B) func(A) C {
|
||||
return func(a A) C {
|
||||
return bc(ab(a))
|
||||
}
|
||||
}
|
||||
})(fbc)))
|
||||
|
||||
right := fapbc.Ap(fapab.Ap(fa)(fab))(fbc)
|
||||
|
||||
return assert.True(t, eq.Equals(left, right), "Apply associative composition")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertLaws asserts the apply laws `identity`, `composition` and `associative composition`
|
||||
//
|
||||
// Deprecated: use [ApplyAssertLaws] instead
|
||||
func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqc E.Eq[HKTC],
|
||||
@@ -98,3 +145,36 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *
|
||||
return functor(fa) && composition(fa)
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyAssertLaws asserts the apply laws `identity`, `composition` and `associative composition`
|
||||
func ApplyAssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqc E.Eq[HKTC],
|
||||
|
||||
fofab pointed.Pointed[func(A) B, HKTAB],
|
||||
fofbc pointed.Pointed[func(B) C, HKTBC],
|
||||
|
||||
faa functor.Functor[A, A, HKTA, HKTA],
|
||||
|
||||
fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],
|
||||
|
||||
fapab apply.Apply[A, B, HKTA, HKTB, HKTAB],
|
||||
fapbc apply.Apply[B, C, HKTB, HKTC, HKTBC],
|
||||
fapac apply.Apply[A, C, HKTA, HKTC, HKTAC],
|
||||
|
||||
fapabac apply.Apply[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(fa HKTA) bool {
|
||||
// mark as test helper
|
||||
t.Helper()
|
||||
// functor laws
|
||||
functor := FCT.FunctorAssertLaws(t, eqa, eqc, faa, apply.ToFunctor(fapab), apply.ToFunctor(fapac), apply.ToFunctor(fapbc), ab, bc)
|
||||
// associative composition laws
|
||||
composition := ApplyAssertAssociativeComposition(t, eqc, fofab, fofbc, fmap, fapab, fapbc, fapac, fapabac, ab, bc)
|
||||
|
||||
return func(fa HKTA) bool {
|
||||
return functor(fa) && composition(fa)
|
||||
}
|
||||
}
|
||||
|
@@ -23,3 +23,8 @@ type Apply[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||
functor.Functor[A, B, HKTA, HKTB]
|
||||
Ap(HKTA) func(HKTFAB) HKTB
|
||||
}
|
||||
|
||||
// ToFunctor converts from [Apply] to [functor.Functor]
|
||||
func ToFunctor[A, B, HKTA, HKTB, HKTFAB any](ap Apply[A, B, HKTA, HKTB, HKTFAB]) functor.Functor[A, B, HKTA, HKTB] {
|
||||
return ap
|
||||
}
|
||||
|
@@ -20,13 +20,19 @@ import (
|
||||
|
||||
E "github.com/IBM/fp-go/eq"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
L "github.com/IBM/fp-go/internal/apply/testing"
|
||||
"github.com/IBM/fp-go/internal/chain"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Chain associativity law
|
||||
//
|
||||
// F.chain(F.chain(fa, afb), bfc) <-> F.chain(fa, a => F.chain(afb(a), bfc))
|
||||
//
|
||||
// Deprecated: use [ChainAssertAssociativity] instead
|
||||
func AssertAssociativity[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
||||
eq E.Eq[HKTC],
|
||||
|
||||
@@ -55,7 +61,40 @@ func AssertAssociativity[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
||||
}
|
||||
}
|
||||
|
||||
// Chain associativity law
|
||||
//
|
||||
// F.chain(F.chain(fa, afb), bfc) <-> F.chain(fa, a => F.chain(afb(a), bfc))
|
||||
func ChainAssertAssociativity[HKTA, HKTB, HKTC, HKTAB, HKTAC, HKTBC, A, B, C any](t *testing.T,
|
||||
eq E.Eq[HKTC],
|
||||
|
||||
fofb pointed.Pointed[B, HKTB],
|
||||
fofc pointed.Pointed[C, HKTC],
|
||||
|
||||
chainab chain.Chainable[A, B, HKTA, HKTB, HKTAB],
|
||||
chainac chain.Chainable[A, C, HKTA, HKTC, HKTAC],
|
||||
chainbc chain.Chainable[B, C, HKTB, HKTC, HKTBC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(fa HKTA) bool {
|
||||
return func(fa HKTA) bool {
|
||||
|
||||
afb := F.Flow2(ab, fofb.Of)
|
||||
bfc := F.Flow2(bc, fofc.Of)
|
||||
|
||||
left := chainbc.Chain(bfc)(chainab.Chain(afb)(fa))
|
||||
|
||||
right := chainac.Chain(func(a A) HKTC {
|
||||
return chainbc.Chain(bfc)(afb(a))
|
||||
})(fa)
|
||||
|
||||
return assert.True(t, eq.Equals(left, right), "Chain associativity")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertLaws asserts the apply laws `identity`, `composition`, `associative composition` and `associativity`
|
||||
//
|
||||
// Deprecated: use [ChainAssertLaws] instead
|
||||
func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqc E.Eq[HKTC],
|
||||
@@ -95,3 +134,37 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *
|
||||
return apply(fa) && associativity(fa)
|
||||
}
|
||||
}
|
||||
|
||||
// ChainAssertLaws asserts the apply laws `identity`, `composition`, `associative composition` and `associativity`
|
||||
func ChainAssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqc E.Eq[HKTC],
|
||||
|
||||
fofb pointed.Pointed[B, HKTB],
|
||||
fofc pointed.Pointed[C, HKTC],
|
||||
|
||||
fofab pointed.Pointed[func(A) B, HKTAB],
|
||||
fofbc pointed.Pointed[func(B) C, HKTBC],
|
||||
|
||||
faa functor.Functor[A, A, HKTA, HKTA],
|
||||
|
||||
fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],
|
||||
|
||||
chainab chain.Chainable[A, B, HKTA, HKTB, HKTAB],
|
||||
chainac chain.Chainable[A, C, HKTA, HKTC, HKTAC],
|
||||
chainbc chain.Chainable[B, C, HKTB, HKTC, HKTBC],
|
||||
|
||||
fapabac apply.Apply[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(fa HKTA) bool {
|
||||
// apply laws
|
||||
apply := L.ApplyAssertLaws(t, eqa, eqc, fofab, fofbc, faa, fmap, chain.ToApply(chainab), chain.ToApply(chainbc), chain.ToApply(chainac), fapabac, ab, bc)
|
||||
// chain laws
|
||||
associativity := ChainAssertAssociativity(t, eqc, fofb, fofc, chainab, chainac, chainbc, ab, bc)
|
||||
|
||||
return func(fa HKTA) bool {
|
||||
return apply(fa) && associativity(fa)
|
||||
}
|
||||
}
|
||||
|
@@ -17,9 +17,20 @@ package chain
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
)
|
||||
|
||||
type Chainable[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||
apply.Apply[A, B, HKTA, HKTB, HKTFAB]
|
||||
Chain(func(A) HKTB) func(HKTA) HKTB
|
||||
}
|
||||
|
||||
// ToFunctor converts from [Chainable] to [functor.Functor]
|
||||
func ToFunctor[A, B, HKTA, HKTB, HKTFAB any](ap Chainable[A, B, HKTA, HKTB, HKTFAB]) functor.Functor[A, B, HKTA, HKTB] {
|
||||
return ap
|
||||
}
|
||||
|
||||
// ToApply converts from [Chainable] to [functor.Functor]
|
||||
func ToApply[A, B, HKTA, HKTB, HKTFAB any](ap Chainable[A, B, HKTA, HKTB, HKTFAB]) apply.Apply[A, B, HKTA, HKTB, HKTFAB] {
|
||||
return ap
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
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) {
|
||||
@@ -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)
|
||||
}
|
||||
// return the outputs
|
||||
return T.MakeTuple2(stdOut.Bytes(), stdErr.Bytes()), err
|
||||
return P.MakePair(stdOut.Bytes(), stdErr.Bytes()), err
|
||||
}
|
||||
|
@@ -20,12 +20,15 @@ import (
|
||||
|
||||
E "github.com/IBM/fp-go/eq"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Functor identity law
|
||||
//
|
||||
// F.map(fa, a => a) <-> fa
|
||||
//
|
||||
// Deprecated: use [FunctorAssertIdentity]
|
||||
func AssertIdentity[HKTA, A any](t *testing.T, eq E.Eq[HKTA], fmap func(HKTA, func(A) A) HKTA) func(fa HKTA) bool {
|
||||
t.Helper()
|
||||
return func(fa HKTA) bool {
|
||||
@@ -33,9 +36,28 @@ func AssertIdentity[HKTA, A any](t *testing.T, eq E.Eq[HKTA], fmap func(HKTA, fu
|
||||
}
|
||||
}
|
||||
|
||||
// Functor identity law
|
||||
//
|
||||
// F.map(fa, a => a) <-> fa
|
||||
func FunctorAssertIdentity[HKTA, A any](
|
||||
t *testing.T,
|
||||
eq E.Eq[HKTA],
|
||||
|
||||
fca functor.Functor[A, A, HKTA, HKTA],
|
||||
) func(fa HKTA) bool {
|
||||
|
||||
t.Helper()
|
||||
return func(fa HKTA) bool {
|
||||
|
||||
return assert.True(t, eq.Equals(fa, fca.Map(F.Identity[A])(fa)), "Functor identity law")
|
||||
}
|
||||
}
|
||||
|
||||
// Functor composition law
|
||||
//
|
||||
// F.map(fa, a => bc(ab(a))) <-> F.map(F.map(fa, ab), bc)
|
||||
//
|
||||
// Deprecated: use [FunctorAssertComposition] instead
|
||||
func AssertComposition[HKTA, HKTB, HKTC, A, B, C any](
|
||||
t *testing.T,
|
||||
|
||||
@@ -53,7 +75,30 @@ func AssertComposition[HKTA, HKTB, HKTC, A, B, C any](
|
||||
}
|
||||
}
|
||||
|
||||
// Functor composition law
|
||||
//
|
||||
// F.map(fa, a => bc(ab(a))) <-> F.map(F.map(fa, ab), bc)
|
||||
func FunctorAssertComposition[HKTA, HKTB, HKTC, A, B, C any](
|
||||
t *testing.T,
|
||||
|
||||
eq E.Eq[HKTC],
|
||||
|
||||
fab functor.Functor[A, B, HKTA, HKTB],
|
||||
fac functor.Functor[A, C, HKTA, HKTC],
|
||||
fbc functor.Functor[B, C, HKTB, HKTC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(fa HKTA) bool {
|
||||
t.Helper()
|
||||
return func(fa HKTA) bool {
|
||||
return assert.True(t, eq.Equals(fac.Map(F.Flow2(ab, bc))(fa), fbc.Map(bc)(fab.Map(ab)(fa))), "Functor composition law")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertLaws asserts the functor laws `identity` and `composition`
|
||||
//
|
||||
// Deprecated: use [FunctorAssertLaws] instead
|
||||
func AssertLaws[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqc E.Eq[HKTC],
|
||||
@@ -62,6 +107,7 @@ func AssertLaws[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
||||
fab func(HKTA, func(A) B) HKTB,
|
||||
fac func(HKTA, func(A) C) HKTC,
|
||||
fbc func(HKTB, func(B) C) HKTC,
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(fa HKTA) bool {
|
||||
@@ -73,3 +119,25 @@ func AssertLaws[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
||||
return identity(fa) && composition(fa)
|
||||
}
|
||||
}
|
||||
|
||||
// FunctorAssertLaws asserts the functor laws `identity` and `composition`
|
||||
func FunctorAssertLaws[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqc E.Eq[HKTC],
|
||||
|
||||
faa functor.Functor[A, A, HKTA, HKTA],
|
||||
fab functor.Functor[A, B, HKTA, HKTB],
|
||||
fac functor.Functor[A, C, HKTA, HKTC],
|
||||
fbc functor.Functor[B, C, HKTB, HKTC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(fa HKTA) bool {
|
||||
t.Helper()
|
||||
identity := FunctorAssertIdentity(t, eqa, faa)
|
||||
composition := FunctorAssertComposition(t, eqc, fab, fac, fbc, ab, bc)
|
||||
|
||||
return func(fa HKTA) bool {
|
||||
return identity(fa) && composition(fa)
|
||||
}
|
||||
}
|
||||
|
@@ -17,10 +17,38 @@ package monad
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
"github.com/IBM/fp-go/internal/chain"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
)
|
||||
|
||||
type Monad[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||
applicative.Applicative[A, B, HKTA, HKTB, HKTFAB]
|
||||
chain.Chainable[A, B, HKTA, HKTB, HKTFAB]
|
||||
}
|
||||
|
||||
// ToFunctor converts from [Monad] to [functor.Functor]
|
||||
func ToFunctor[A, B, HKTA, HKTB, HKTFAB any](ap Monad[A, B, HKTA, HKTB, HKTFAB]) functor.Functor[A, B, HKTA, HKTB] {
|
||||
return ap
|
||||
}
|
||||
|
||||
// ToApply converts from [Monad] to [apply.Apply]
|
||||
func ToApply[A, B, HKTA, HKTB, HKTFAB any](ap Monad[A, B, HKTA, HKTB, HKTFAB]) apply.Apply[A, B, HKTA, HKTB, HKTFAB] {
|
||||
return ap
|
||||
}
|
||||
|
||||
// ToPointed converts from [Monad] to [pointed.Pointed]
|
||||
func ToPointed[A, B, HKTA, HKTB, HKTFAB any](ap Monad[A, B, HKTA, HKTB, HKTFAB]) pointed.Pointed[A, HKTA] {
|
||||
return ap
|
||||
}
|
||||
|
||||
// ToApplicative converts from [Monad] to [applicative.Applicative]
|
||||
func ToApplicative[A, B, HKTA, HKTB, HKTFAB any](ap Monad[A, B, HKTA, HKTB, HKTFAB]) applicative.Applicative[A, B, HKTA, HKTB, HKTFAB] {
|
||||
return ap
|
||||
}
|
||||
|
||||
// ToChainable converts from [Monad] to [chain.Chainable]
|
||||
func ToChainable[A, B, HKTA, HKTB, HKTFAB any](ap Monad[A, B, HKTA, HKTB, HKTFAB]) chain.Chainable[A, B, HKTA, HKTB, HKTFAB] {
|
||||
return ap
|
||||
}
|
||||
|
@@ -19,14 +19,21 @@ import (
|
||||
"testing"
|
||||
|
||||
E "github.com/IBM/fp-go/eq"
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
LA "github.com/IBM/fp-go/internal/applicative/testing"
|
||||
"github.com/IBM/fp-go/internal/chain"
|
||||
LC "github.com/IBM/fp-go/internal/chain/testing"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Apply monad left identity law
|
||||
//
|
||||
// M.chain(M.of(a), f) <-> f(a)
|
||||
//
|
||||
// Deprecated: use [MonadAssertLeftIdentity] instead
|
||||
func AssertLeftIdentity[HKTA, HKTB, A, B any](t *testing.T,
|
||||
eq E.Eq[HKTB],
|
||||
|
||||
@@ -50,9 +57,36 @@ func AssertLeftIdentity[HKTA, HKTB, A, B any](t *testing.T,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply monad left identity law
|
||||
//
|
||||
// M.chain(M.of(a), f) <-> f(a)
|
||||
func MonadAssertLeftIdentity[HKTA, HKTB, HKTFAB, A, B any](t *testing.T,
|
||||
eq E.Eq[HKTB],
|
||||
|
||||
fofb pointed.Pointed[B, HKTB],
|
||||
|
||||
ma monad.Monad[A, B, HKTA, HKTB, HKTFAB],
|
||||
|
||||
ab func(A) B,
|
||||
) func(a A) bool {
|
||||
return func(a A) bool {
|
||||
|
||||
f := func(a A) HKTB {
|
||||
return fofb.Of(ab(a))
|
||||
}
|
||||
|
||||
left := ma.Chain(f)(ma.Of(a))
|
||||
right := f(a)
|
||||
|
||||
return assert.True(t, eq.Equals(left, right), "Monad left identity")
|
||||
}
|
||||
}
|
||||
|
||||
// Apply monad right identity law
|
||||
//
|
||||
// M.chain(fa, M.of) <-> fa
|
||||
//
|
||||
// Deprecated: use [MonadAssertRightIdentity] instead
|
||||
func AssertRightIdentity[HKTA, A any](t *testing.T,
|
||||
eq E.Eq[HKTA],
|
||||
|
||||
@@ -69,7 +103,27 @@ func AssertRightIdentity[HKTA, A any](t *testing.T,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply monad right identity law
|
||||
//
|
||||
// M.chain(fa, M.of) <-> fa
|
||||
func MonadAssertRightIdentity[HKTA, HKTAA, A any](t *testing.T,
|
||||
eq E.Eq[HKTA],
|
||||
|
||||
ma monad.Monad[A, A, HKTA, HKTA, HKTAA],
|
||||
|
||||
) func(fa HKTA) bool {
|
||||
return func(fa HKTA) bool {
|
||||
|
||||
left := ma.Chain(ma.Of)(fa)
|
||||
right := fa
|
||||
|
||||
return assert.True(t, eq.Equals(left, right), "Monad right identity")
|
||||
}
|
||||
}
|
||||
|
||||
// AssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange', `associativity`, `left identity`, `right identity`
|
||||
//
|
||||
// Deprecated: use [MonadAssertLaws] instead
|
||||
func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqb E.Eq[HKTB],
|
||||
@@ -120,3 +174,55 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A
|
||||
return applicative(a) && chain(fa) && leftIdentity(a) && rightIdentity(fa)
|
||||
}
|
||||
}
|
||||
|
||||
// MonadAssertLaws asserts the apply laws `identity`, `composition`, `associative composition`, 'applicative identity', 'homomorphism', 'interchange', `associativity`, `left identity`, `right identity`
|
||||
func MonadAssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A, B, C any](t *testing.T,
|
||||
eqa E.Eq[HKTA],
|
||||
eqb E.Eq[HKTB],
|
||||
eqc E.Eq[HKTC],
|
||||
|
||||
fofc pointed.Pointed[C, HKTC],
|
||||
fofaa pointed.Pointed[func(A) A, HKTAA],
|
||||
fofbc pointed.Pointed[func(B) C, HKTBC],
|
||||
fofabb pointed.Pointed[func(func(A) B) B, HKTABB],
|
||||
|
||||
fmap functor.Functor[func(B) C, func(func(A) B) func(A) C, HKTBC, HKTABAC],
|
||||
|
||||
fapabb applicative.Applicative[func(A) B, B, HKTAB, HKTB, HKTABB],
|
||||
fapabac applicative.Applicative[func(A) B, func(A) C, HKTAB, HKTAC, HKTABAC],
|
||||
|
||||
maa monad.Monad[A, A, HKTA, HKTA, HKTAA],
|
||||
mab monad.Monad[A, B, HKTA, HKTB, HKTAB],
|
||||
mac monad.Monad[A, C, HKTA, HKTC, HKTAC],
|
||||
mbc monad.Monad[B, C, HKTB, HKTC, HKTBC],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(a A) bool {
|
||||
// derivations
|
||||
fofa := monad.ToPointed(maa)
|
||||
fofb := monad.ToPointed(mbc)
|
||||
fofab := applicative.ToPointed(fapabb)
|
||||
fapaa := monad.ToApplicative(maa)
|
||||
fapab := monad.ToApplicative(mab)
|
||||
chainab := monad.ToChainable(mab)
|
||||
chainac := monad.ToChainable(mac)
|
||||
chainbc := monad.ToChainable(mbc)
|
||||
fapbc := chain.ToApply(chainbc)
|
||||
fapac := chain.ToApply(chainac)
|
||||
|
||||
faa := monad.ToFunctor(maa)
|
||||
|
||||
// applicative laws
|
||||
apLaw := LA.ApplicativeAssertLaws(t, eqa, eqb, eqc, fofb, fofaa, fofbc, fofabb, faa, fmap, fapaa, fapab, fapbc, fapac, fapabb, fapabac, ab, bc)
|
||||
// chain laws
|
||||
chainLaw := LC.ChainAssertLaws(t, eqa, eqc, fofb, fofc, fofab, fofbc, faa, fmap, chainab, chainac, chainbc, applicative.ToApply(fapabac), ab, bc)
|
||||
// monad laws
|
||||
leftIdentity := MonadAssertLeftIdentity(t, eqb, fofb, mab, ab)
|
||||
rightIdentity := MonadAssertRightIdentity(t, eqa, maa)
|
||||
|
||||
return func(a A) bool {
|
||||
fa := fofa.Of(a)
|
||||
return apLaw(a) && chainLaw(fa) && leftIdentity(a) && rightIdentity(fa)
|
||||
}
|
||||
}
|
||||
|
@@ -27,16 +27,11 @@ const (
|
||||
|
||||
// MonadApSeq implements the applicative on a single thread by first executing mab and the ma
|
||||
func MonadApSeq[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](mab GAB, ma GA) GB {
|
||||
return MakeIO[GB](func() B {
|
||||
return F.Pipe1(
|
||||
ma(),
|
||||
mab(),
|
||||
)
|
||||
})
|
||||
return MonadChain(mab, F.Bind1st(MonadMap[GA, GB], ma))
|
||||
}
|
||||
|
||||
// MonadApPar implements the applicative on two threads, the main thread executes mab and the actuall
|
||||
// apply operation and the second thred computes ma. Communication between the threads happens via a channel
|
||||
// apply operation and the second thread computes ma. Communication between the threads happens via a channel
|
||||
func MonadApPar[GA ~func() A, GB ~func() B, GAB ~func() func(A) B, A, B any](mab GAB, ma GA) GB {
|
||||
return MakeIO[GB](func() B {
|
||||
c := make(chan A)
|
||||
|
@@ -25,6 +25,11 @@ import (
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
var (
|
||||
// undefined represents an undefined value
|
||||
undefined = struct{}{}
|
||||
)
|
||||
|
||||
// type IO[A any] = func() A
|
||||
|
||||
func MakeIO[GA ~func() A, A any](f func() A) GA {
|
||||
@@ -43,7 +48,7 @@ func FromIO[GA ~func() A, A any](a GA) GA {
|
||||
func FromImpure[GA ~func() any, IMP ~func()](f IMP) GA {
|
||||
return MakeIO[GA](func() any {
|
||||
f()
|
||||
return nil
|
||||
return undefined
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,28 @@ func MonadTraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B
|
||||
)
|
||||
}
|
||||
|
||||
func MonadTraverseArraySeq[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](tas AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse(
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApSeq[GBS, func() func(B) BBS, GB],
|
||||
|
||||
tas,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func MonadTraverseArrayPar[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](tas AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse(
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApPar[GBS, func() func(B) BBS, GB],
|
||||
|
||||
tas,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, BBS],
|
||||
@@ -42,6 +64,26 @@ func TraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArraySeq[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApSeq[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayPar[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApPar[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayWithIndex[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(int, A) GB) func(AAS) GBS {
|
||||
return RA.TraverseWithIndex[AAS](
|
||||
Of[GBS, BBS],
|
||||
@@ -52,10 +94,38 @@ func TraverseArrayWithIndex[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayWithIndexSeq[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(int, A) GB) func(AAS) GBS {
|
||||
return RA.TraverseWithIndex[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApSeq[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func TraverseArrayWithIndexPar[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(int, A) GB) func(AAS) GBS {
|
||||
return RA.TraverseWithIndex[AAS](
|
||||
Of[GBS, BBS],
|
||||
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||
ApPar[GBS, func() func(B) BBS, GB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceArray[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
|
||||
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
func SequenceArraySeq[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
|
||||
return MonadTraverseArraySeq[GA, GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
func SequenceArrayPar[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
|
||||
return MonadTraverseArrayPar[GA, GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecord transforms a record using an IO transform an IO of a record
|
||||
func MonadTraverseRecord[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
|
||||
return RR.MonadTraverse[MA](
|
||||
@@ -89,3 +159,71 @@ func TraverseRecordWithIndex[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[
|
||||
func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
|
||||
return MonadTraverseRecord[GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecordSeq transforms a record using an IO transform an IO of a record
|
||||
func MonadTraverseRecordSeq[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
|
||||
return RR.MonadTraverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApSeq[GBS, func() func(B) MB, GB],
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordSeq transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordSeq[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](f func(A) GB) func(MA) GBS {
|
||||
return RR.Traverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApSeq[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexSeq transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordWithIndexSeq[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](f func(K, A) GB) func(MA) GBS {
|
||||
return RR.TraverseWithIndex[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApSeq[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceRecordSeq[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
|
||||
return MonadTraverseRecordSeq[GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecordPar transforms a record using an IO transform an IO of a record
|
||||
func MonadTraverseRecordPar[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](ma MA, f func(A) GB) GBS {
|
||||
return RR.MonadTraverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApPar[GBS, func() func(B) MB, GB],
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordPar transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordPar[GBS ~func() MB, MA ~map[K]A, GB ~func() B, MB ~map[K]B, K comparable, A, B any](f func(A) GB) func(MA) GBS {
|
||||
return RR.Traverse[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApPar[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexPar transforms a record using an IO transform an IO of a record
|
||||
func TraverseRecordWithIndexPar[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](f func(K, A) GB) func(MA) GBS {
|
||||
return RR.TraverseWithIndex[MA](
|
||||
Of[GBS, MB],
|
||||
Map[GBS, func() func(B) MB, MB, func(B) MB],
|
||||
ApPar[GBS, func() func(B) MB, GB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceRecordPar[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
|
||||
return MonadTraverseRecordPar[GAS](tas, F.Identity[GA])
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ func TestLogger(t *testing.T) {
|
||||
|
||||
lio := l("out")
|
||||
|
||||
assert.Equal(t, nil, lio(10)())
|
||||
assert.NotPanics(t, func() { lio(10)() })
|
||||
}
|
||||
|
||||
func TestLogf(t *testing.T) {
|
||||
@@ -36,5 +36,5 @@ func TestLogf(t *testing.T) {
|
||||
|
||||
lio := l("Value is %d")
|
||||
|
||||
assert.Equal(t, nil, lio(10)())
|
||||
assert.NotPanics(t, func() { lio(10)() })
|
||||
}
|
||||
|
47
io/sequence_test.go
Normal file
47
io/sequence_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2023 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 io
|
||||
|
||||
import (
|
||||
A "github.com/IBM/fp-go/array"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMapSeq(t *testing.T) {
|
||||
var results []string
|
||||
|
||||
handler := func(value string) IO[string] {
|
||||
return func() string {
|
||||
results = append(results, value)
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
src := A.From("a", "b", "c")
|
||||
|
||||
res := F.Pipe2(
|
||||
src,
|
||||
TraverseArraySeq(handler),
|
||||
Map(func(data []string) bool {
|
||||
return assert.Equal(t, data, results)
|
||||
}),
|
||||
)
|
||||
|
||||
assert.True(t, res())
|
||||
}
|
@@ -60,3 +60,45 @@ func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) IO[B]) func(ma
|
||||
func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] {
|
||||
return G.SequenceRecord[IO[A], IO[map[K]A]](tas)
|
||||
}
|
||||
|
||||
func MonadTraverseArraySeq[A, B any](tas []A, f func(A) IO[B]) IO[[]B] {
|
||||
return G.MonadTraverseArraySeq[IO[B], IO[[]B]](tas, f)
|
||||
}
|
||||
|
||||
// TraverseArraySeq applies a function returning an [IO] to all elements in an array and the
|
||||
// transforms this into an [IO] of that array
|
||||
func TraverseArraySeq[A, B any](f func(A) IO[B]) func([]A) IO[[]B] {
|
||||
return G.TraverseArraySeq[IO[B], IO[[]B], []A](f)
|
||||
}
|
||||
|
||||
// TraverseArrayWithIndexSeq applies a function returning an [IO] to all elements in an array and the
|
||||
// transforms this into an [IO] of that array
|
||||
func TraverseArrayWithIndexSeq[A, B any](f func(int, A) IO[B]) func([]A) IO[[]B] {
|
||||
return G.TraverseArrayWithIndexSeq[IO[B], IO[[]B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArraySeq converts an array of [IO] to an [IO] of an array
|
||||
func SequenceArraySeq[A any](tas []IO[A]) IO[[]A] {
|
||||
return G.SequenceArraySeq[IO[A], IO[[]A]](tas)
|
||||
}
|
||||
|
||||
func MonadTraverseRecordSeq[K comparable, A, B any](tas map[K]A, f func(A) IO[B]) IO[map[K]B] {
|
||||
return G.MonadTraverseRecordSeq[IO[map[K]B]](tas, f)
|
||||
}
|
||||
|
||||
// TraverseRecord applies a function returning an [IO] to all elements in a record and the
|
||||
// transforms this into an [IO] of that record
|
||||
func TraverseRecordSeq[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] {
|
||||
return G.TraverseRecordSeq[IO[map[K]B], map[K]A, IO[B]](f)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexSeq applies a function returning an [IO] to all elements in a record and the
|
||||
// transforms this into an [IO] of that record
|
||||
func TraverseRecordWithIndeSeq[K comparable, A, B any](f func(K, A) IO[B]) func(map[K]A) IO[map[K]B] {
|
||||
return G.TraverseRecordWithIndexSeq[IO[B], IO[map[K]B], map[K]A](f)
|
||||
}
|
||||
|
||||
// SequenceRecordSeq converts a record of [IO] to an [IO] of a record
|
||||
func SequenceRecordSeq[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] {
|
||||
return G.SequenceRecordSeq[IO[A], IO[map[K]A]](tas)
|
||||
}
|
||||
|
@@ -48,10 +48,10 @@ func ExampleIOEither_creation() {
|
||||
fmt.Println(rightFromPred())
|
||||
|
||||
// Output:
|
||||
// Left[*errors.errorString, string](some error)
|
||||
// Right[<nil>, string](value)
|
||||
// Right[<nil>, int](42)
|
||||
// Left[*errors.errorString, int](3 is an odd number)
|
||||
// Right[<nil>, int](4)
|
||||
// Left[*errors.errorString](some error)
|
||||
// Right[string](value)
|
||||
// Right[int](42)
|
||||
// Left[*errors.errorString](3 is an odd number)
|
||||
// Right[int](4)
|
||||
|
||||
}
|
||||
|
@@ -53,5 +53,5 @@ func ExampleIOEither_do() {
|
||||
fmt.Println(b())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, int](8)
|
||||
// Right[int](8)
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ func ExampleIOEither_extraction() {
|
||||
fmt.Println(valueFromIO)
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, int](42)
|
||||
// Right[int](42)
|
||||
// 42
|
||||
// 42
|
||||
|
||||
|
@@ -27,7 +27,7 @@ import (
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
IOEF "github.com/IBM/fp-go/ioeither/file"
|
||||
J "github.com/IBM/fp-go/json"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -95,7 +95,7 @@ func ReadFullResponse(client Client) func(Requester) IOE.IOEither[error, H.FullR
|
||||
IOE.Of[error, 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)),
|
||||
)
|
||||
}),
|
||||
)
|
||||
@@ -124,17 +124,22 @@ func ReadJson[A any](client Client) func(Requester) IOE.IOEither[error, A] {
|
||||
return ReadJSON[A](client)
|
||||
}
|
||||
|
||||
// ReadJSON sends a request, reads the response and parses the response as JSON
|
||||
func ReadJSON[A any](client Client) func(Requester) IOE.IOEither[error, A] {
|
||||
// readJSON sends a request, reads the response and parses the response as a []byte
|
||||
func readJSON(client Client) func(Requester) IOE.IOEither[error, []byte] {
|
||||
return F.Flow3(
|
||||
ReadFullResponse(client),
|
||||
IOE.ChainFirstEitherK(F.Flow2(
|
||||
H.Response,
|
||||
H.ValidateJSONResponse,
|
||||
)),
|
||||
IOE.ChainEitherK(F.Flow2(
|
||||
H.Body,
|
||||
J.Unmarshal[A],
|
||||
)),
|
||||
IOE.Map[error](H.Body),
|
||||
)
|
||||
}
|
||||
|
||||
// ReadJSON sends a request, reads the response and parses the response as JSON
|
||||
func ReadJSON[A any](client Client) func(Requester) IOE.IOEither[error, A] {
|
||||
return F.Flow2(
|
||||
readJSON(client),
|
||||
IOE.ChainEitherK[error](J.Unmarshal[A]),
|
||||
)
|
||||
}
|
||||
|
48
ioeither/sequence_test.go
Normal file
48
ioeither/sequence_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2023 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 ioeither
|
||||
|
||||
import (
|
||||
A "github.com/IBM/fp-go/array"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMapSeq(t *testing.T) {
|
||||
var results []string
|
||||
|
||||
handler := func(value string) IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
results = append(results, value)
|
||||
return E.Of[error](value)
|
||||
}
|
||||
}
|
||||
|
||||
src := A.From("a", "b", "c")
|
||||
|
||||
res := F.Pipe2(
|
||||
src,
|
||||
TraverseArraySeq(handler),
|
||||
Map[error](func(data []string) bool {
|
||||
return assert.Equal(t, data, results)
|
||||
}),
|
||||
)
|
||||
|
||||
assert.Equal(t, E.Of[error](true), res())
|
||||
}
|
@@ -17,11 +17,11 @@ package stateless
|
||||
|
||||
import (
|
||||
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`.
|
||||
// Stops when either the data or selectors iterator has been exhausted.
|
||||
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)
|
||||
}
|
||||
|
@@ -18,11 +18,11 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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`
|
||||
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(
|
||||
Filter[GU](pred),
|
||||
First[GU],
|
||||
|
@@ -20,18 +20,18 @@ import (
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
F "github.com/IBM/fp-go/internal/functor"
|
||||
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
|
||||
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,
|
||||
) GS {
|
||||
return Of[GS](empty)
|
||||
}
|
||||
|
||||
// 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,
|
||||
f func(S1) GA,
|
||||
) 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]
|
||||
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,
|
||||
f func(S1) A,
|
||||
) 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]
|
||||
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,
|
||||
b B,
|
||||
) 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]
|
||||
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,
|
||||
) func(GA) GS1 {
|
||||
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
|
||||
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,
|
||||
fa GA,
|
||||
) func(GS1) GS2 {
|
||||
|
@@ -18,17 +18,17 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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`.
|
||||
// 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(
|
||||
Zip[GU, GB, CS](sel),
|
||||
FilterMap[GU, CS](F.Flow2(
|
||||
O.FromPredicate(T.Second[U, bool]),
|
||||
O.Map(T.First[U, bool]),
|
||||
O.FromPredicate(P.Tail[U, bool]),
|
||||
O.Map(P.Head[U, bool]),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@@ -18,12 +18,12 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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
|
||||
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 {
|
||||
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)()
|
||||
}, F.Flow2(
|
||||
T.Map2(recurse, F.Identity[U]),
|
||||
O.Of[T.Tuple2[GU, U]],
|
||||
P.BiMap(recurse, F.Identity[U]),
|
||||
O.Of[P.Pair[GU, U]],
|
||||
))
|
||||
|
||||
return recurse(ma)
|
||||
|
@@ -18,17 +18,17 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
P "github.com/IBM/fp-go/predicate"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
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.
|
||||
// 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
|
||||
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 {
|
||||
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(
|
||||
t,
|
||||
fromPred,
|
||||
O.Fold(recurse(Next(t)), O.Of[T.Tuple2[GU, U]]),
|
||||
O.Fold(recurse(Next(t)), O.Of[P.Pair[GU, U]]),
|
||||
)
|
||||
})
|
||||
|
||||
|
@@ -18,13 +18,13 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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
|
||||
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(
|
||||
mu(),
|
||||
O.Map(T.Second[GU, U]),
|
||||
O.Map(P.Tail[GU, U]),
|
||||
)
|
||||
}
|
||||
|
@@ -19,16 +19,16 @@ import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
L "github.com/IBM/fp-go/io/generic"
|
||||
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
|
||||
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(
|
||||
l,
|
||||
L.Map[LZ, GU](F.Flow2(
|
||||
F.Bind1st(T.MakeTuple2[GU, U], Empty[GU]()),
|
||||
O.Of[T.Tuple2[GU, U]],
|
||||
F.Bind1st(P.MakePair[GU, U], Empty[GU]()),
|
||||
O.Of[P.Pair[GU, U]],
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
@@ -24,45 +24,45 @@ import (
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
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`
|
||||
func Next[GU ~func() O.Option[T.Tuple2[GU, U]], U any](m T.Tuple2[GU, U]) GU {
|
||||
return T.First(m)
|
||||
// Next returns the iterator for the next element in an iterator `P.Pair`
|
||||
func Next[GU ~func() O.Option[P.Pair[GU, U]], U any](m P.Pair[GU, U]) GU {
|
||||
return P.Head(m)
|
||||
}
|
||||
|
||||
// Current returns the current element in an iterator `T.Tuple2`
|
||||
func Current[GU ~func() O.Option[T.Tuple2[GU, U]], U any](m T.Tuple2[GU, U]) U {
|
||||
return T.Second(m)
|
||||
// Current returns the current element in an iterator `P.Pair`
|
||||
func Current[GU ~func() O.Option[P.Pair[GU, U]], U any](m P.Pair[GU, U]) U {
|
||||
return P.Tail(m)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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]()
|
||||
}
|
||||
|
||||
// Of returns an iterator with one single element
|
||||
func Of[GU ~func() O.Option[T.Tuple2[GU, U]], U any](a U) GU {
|
||||
return IO.Of[GU](T.MakeTuple2(Empty[GU](), a))
|
||||
func Of[GU ~func() O.Option[P.Pair[GU, U]], U any](a U) GU {
|
||||
return IO.Of[GU](P.MakePair(Empty[GU](), a))
|
||||
}
|
||||
|
||||
// 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 func() O.Option[T.Tuple2[GU, U]] {
|
||||
return O.Of(T.MakeTuple2(FromArray[GU](tail), head))
|
||||
return func() O.Option[P.Pair[GU, U]] {
|
||||
return O.Of(P.MakePair(FromArray[GU](tail), head))
|
||||
}
|
||||
})(as)
|
||||
}
|
||||
|
||||
// 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())
|
||||
current := initial
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func concat[GU ~func() O.Option[T.Tuple2[GU, U]], U any](right, left GU) GU {
|
||||
var m func(ma O.Option[T.Tuple2[GU, U]]) O.Option[T.Tuple2[GU, U]]
|
||||
func concat[GU ~func() O.Option[P.Pair[GU, U]], U any](right, left GU) GU {
|
||||
var m func(ma O.Option[P.Pair[GU, U]]) O.Option[P.Pair[GU, U]]
|
||||
|
||||
recurse := func(left GU) GU {
|
||||
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(
|
||||
right,
|
||||
F.Flow2(
|
||||
T.Map2(recurse, F.Identity[U]),
|
||||
O.Some[T.Tuple2[GU, U]],
|
||||
P.BiMap(recurse, F.Identity[U]),
|
||||
O.Some[P.Pair[GU, U]],
|
||||
))
|
||||
|
||||
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
|
||||
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 {
|
||||
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(
|
||||
F.Flow3(
|
||||
T.Map2(recurse, f),
|
||||
T.Tupled2(concat[GV]),
|
||||
func(v GV) O.Option[T.Tuple2[GV, V]] {
|
||||
P.BiMap(recurse, f),
|
||||
P.Paired(concat[GV]),
|
||||
func(v GV) O.Option[P.Pair[GV, 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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(
|
||||
MonadChain[GU, GU, U, 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(
|
||||
Chain[GU, GU, U, 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])
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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(
|
||||
T.Replicate2[int],
|
||||
T.Map2(F.Flow2(
|
||||
P.Of[int],
|
||||
P.BiMap(F.Flow2(
|
||||
utils.Inc,
|
||||
recurse),
|
||||
f),
|
||||
O.Of[T.Tuple2[GU, U]],
|
||||
O.Of[P.Pair[GU, U]],
|
||||
)
|
||||
|
||||
// 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.
|
||||
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))
|
||||
}
|
||||
|
||||
// Repeat creates an [Iterator] containing a value repeated the specified number of times.
|
||||
// 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(
|
||||
a,
|
||||
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
|
||||
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))
|
||||
}
|
||||
|
||||
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
|
||||
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 {
|
||||
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(
|
||||
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))
|
||||
return O.MonadFold(f(Current(t)), r, F.Flow2(
|
||||
F.Bind1st(T.MakeTuple2[GV, V], r),
|
||||
O.Some[T.Tuple2[GV, V]],
|
||||
F.Bind1st(P.MakePair[GV, V], r),
|
||||
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
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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(
|
||||
FilterMap[GVV, GU](f),
|
||||
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 Reduce[GU](func(cur V, a U) V {
|
||||
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())
|
||||
}
|
||||
|
@@ -18,10 +18,10 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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
|
||||
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]())
|
||||
}
|
||||
|
@@ -18,10 +18,10 @@ package generic
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
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 {
|
||||
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
|
||||
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]{}
|
||||
}
|
||||
|
@@ -19,10 +19,10 @@ import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
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(
|
||||
F.Swap(concat[GU]),
|
||||
Empty[GU](),
|
||||
|
@@ -24,10 +24,10 @@ import (
|
||||
N "github.com/IBM/fp-go/number"
|
||||
I "github.com/IBM/fp-go/number/integer"
|
||||
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
|
||||
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),
|
||||
LG.Map[L.Lazy[O.Option[int]], GR](O.Map(
|
||||
F.Flow2(
|
||||
T.Replicate2[int],
|
||||
T.Map2(F.Flow2(N.Add(1), recurse), val.Index),
|
||||
P.Of[int],
|
||||
P.BiMap(F.Flow2(N.Add(1), recurse), val.Index),
|
||||
),
|
||||
)),
|
||||
)
|
||||
|
@@ -18,14 +18,14 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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] {
|
||||
return T.MakeTuple2(t.F1(t.F2), t.F2)
|
||||
func apTuple[A, B any](t P.Pair[func(A) B, A]) P.Pair[B, A] {
|
||||
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
|
||||
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(
|
||||
ma,
|
||||
O.Map(F.Flow2(
|
||||
T.Map2(m, F.Bind1st(f, current)),
|
||||
P.BiMap(m, F.Bind1st(f, current)),
|
||||
apTuple[V, GV],
|
||||
)),
|
||||
)
|
||||
|
@@ -19,10 +19,10 @@ import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
N "github.com/IBM/fp-go/number/integer"
|
||||
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
|
||||
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,
|
||||
O.Chain(F.Ignore1of1[int](F.Nullary2(
|
||||
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])),
|
||||
))),
|
||||
)
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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
|
||||
@@ -31,23 +31,23 @@ func addToMap[A comparable](a A, m map[A]bool) map[A]bool {
|
||||
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
|
||||
|
||||
recurse = func(as AS, mp map[K]bool) AS {
|
||||
return F.Nullary2(
|
||||
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(
|
||||
a.F2,
|
||||
P.Tail(a),
|
||||
f,
|
||||
O.FromPredicate(func(k K) bool {
|
||||
_, ok := mp[k]
|
||||
return !ok
|
||||
}),
|
||||
O.Fold(recurse(a.F1, mp), func(k K) O.Option[T.Tuple2[AS, A]] {
|
||||
return O.Of(T.MakeTuple2(recurse(a.F1, addToMap(k, mp)), a.F2))
|
||||
O.Fold(recurse(P.Head(a), mp), func(k K) O.Option[P.Pair[AS, A]] {
|
||||
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))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@@ -18,29 +18,29 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
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
|
||||
// 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
|
||||
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 {
|
||||
return func() O.Option[T.Tuple2[CS, C]] {
|
||||
return func() O.Option[P.Pair[CS, C]] {
|
||||
// combine
|
||||
return F.Pipe1(
|
||||
T.MakeTuple2(as(), bs()),
|
||||
P.MakePair(as(), bs()),
|
||||
m,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
m = F.Flow2(
|
||||
O.SequenceTuple2[T.Tuple2[AS, A], T.Tuple2[BS, B]],
|
||||
O.Map(func(t T.Tuple2[T.Tuple2[AS, A], T.Tuple2[BS, B]]) T.Tuple2[CS, C] {
|
||||
return T.MakeTuple2(recurse(t.F1.F1, t.F2.F1), f(t.F1.F2, t.F2.F2))
|
||||
O.SequencePair[P.Pair[AS, A], P.Pair[BS, B]],
|
||||
O.Map(func(t P.Pair[P.Pair[AS, A], P.Pair[BS, B]]) P.Pair[CS, C] {
|
||||
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
|
||||
@@ -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
|
||||
// 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 {
|
||||
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) T.Tuple2[A, B]])(fb, T.MakeTuple2[A, B])
|
||||
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) P.Pair[A, B]])(fb, P.MakePair[A, B])
|
||||
}
|
||||
|
@@ -20,19 +20,19 @@ import (
|
||||
L "github.com/IBM/fp-go/lazy"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
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
|
||||
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`
|
||||
func Next[U any](m T.Tuple2[Iterator[U], U]) Iterator[U] {
|
||||
// Next returns the [Iterator] for the next element in an iterator `P.Pair`
|
||||
func Next[U any](m P.Pair[Iterator[U], U]) Iterator[U] {
|
||||
return G.Next(m)
|
||||
}
|
||||
|
||||
// Current returns the current element in an [Iterator] `T.Tuple2`
|
||||
func Current[U any](m T.Tuple2[Iterator[U], U]) U {
|
||||
// Current returns the current element in an [Iterator] `P.Pair`
|
||||
func Current[U any](m P.Pair[Iterator[U], U]) U {
|
||||
return G.Current(m)
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
"testing"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -29,14 +29,14 @@ func TestScan(t *testing.T) {
|
||||
|
||||
dst := F.Pipe1(
|
||||
src,
|
||||
Scan(func(cur T.Tuple2[int, string], val string) T.Tuple2[int, string] {
|
||||
return T.MakeTuple2(cur.F1+1, val)
|
||||
}, T.MakeTuple2(0, "")),
|
||||
Scan(func(cur P.Pair[int, string], val string) P.Pair[int, string] {
|
||||
return P.MakePair(P.Head(cur)+1, val)
|
||||
}, P.MakePair(0, "")),
|
||||
)
|
||||
|
||||
assert.Equal(t, ToArray(From(
|
||||
T.MakeTuple2(1, "a"),
|
||||
T.MakeTuple2(2, "b"),
|
||||
T.MakeTuple2(3, "c"),
|
||||
P.MakePair(1, "a"),
|
||||
P.MakePair(2, "b"),
|
||||
P.MakePair(3, "c"),
|
||||
)), ToArray(dst))
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ package stateless
|
||||
|
||||
import (
|
||||
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
|
||||
@@ -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
|
||||
// longer iterator are discarded
|
||||
func Zip[A, B any](fb Iterator[B]) func(Iterator[A]) Iterator[T.Tuple2[A, B]] {
|
||||
return G.Zip[Iterator[A], Iterator[B], Iterator[T.Tuple2[A, B]]](fb)
|
||||
func Zip[A, B any](fb Iterator[B]) func(Iterator[A]) Iterator[P.Pair[A, B]] {
|
||||
return G.Zip[Iterator[A], Iterator[B], Iterator[P.Pair[A, B]]](fb)
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -40,5 +40,5 @@ func TestZip(t *testing.T) {
|
||||
|
||||
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))
|
||||
}
|
||||
|
@@ -113,7 +113,7 @@ func fromPredicate[S, A any](creator func(get func(S) O.Option[A], set func(S, A
|
||||
return func(get func(S) A, set func(S, A) S) Optional[S, A] {
|
||||
return creator(
|
||||
F.Flow2(get, fromPred),
|
||||
func(s S, a A) S {
|
||||
func(s S, _ A) S {
|
||||
return F.Pipe3(
|
||||
s,
|
||||
get,
|
||||
|
@@ -19,52 +19,79 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
// jsonNull is the cached representation of the `null` serialization in JSON
|
||||
jsonNull = []byte("null")
|
||||
)
|
||||
|
||||
// Option defines a data structure that logically holds a value or not
|
||||
type Option[A any] struct {
|
||||
isSome bool
|
||||
some A
|
||||
value A
|
||||
}
|
||||
|
||||
// optString prints some debug info for the object
|
||||
//
|
||||
// go:noinline
|
||||
func optString(isSome bool, value any) string {
|
||||
if isSome {
|
||||
return fmt.Sprintf("Some[%T](%v)", value, value)
|
||||
}
|
||||
return fmt.Sprintf("None[%T]", value)
|
||||
}
|
||||
|
||||
// optFormat prints some debug info for the object
|
||||
//
|
||||
// go:noinline
|
||||
func optFormat(isSome bool, value any, f fmt.State, c rune) {
|
||||
switch c {
|
||||
case 's':
|
||||
fmt.Fprint(f, optString(isSome, value))
|
||||
default:
|
||||
fmt.Fprint(f, optString(isSome, value))
|
||||
}
|
||||
}
|
||||
|
||||
// String prints some debug info for the object
|
||||
func (s Option[A]) String() string {
|
||||
if s.isSome {
|
||||
return fmt.Sprintf("Some[%T](%v)", s.some, s.some)
|
||||
}
|
||||
return fmt.Sprintf("None[%T]", s.some)
|
||||
return optString(s.isSome, s.value)
|
||||
}
|
||||
|
||||
// Format prints some debug info for the object
|
||||
func (s Option[A]) Format(f fmt.State, c rune) {
|
||||
switch c {
|
||||
case 's':
|
||||
fmt.Fprint(f, s.String())
|
||||
default:
|
||||
fmt.Fprint(f, s.String())
|
||||
}
|
||||
optFormat(s.isSome, s.value, f, c)
|
||||
}
|
||||
|
||||
func (s Option[A]) MarshalJSON() ([]byte, error) {
|
||||
if IsSome(s) {
|
||||
return json.Marshal(s.some)
|
||||
func optMarshalJSON(isSome bool, value any) ([]byte, error) {
|
||||
if isSome {
|
||||
return json.Marshal(value)
|
||||
}
|
||||
return jsonNull, nil
|
||||
}
|
||||
|
||||
func (s *Option[A]) UnmarshalJSON(data []byte) error {
|
||||
func (s Option[A]) MarshalJSON() ([]byte, error) {
|
||||
return optMarshalJSON(s.isSome, s.value)
|
||||
}
|
||||
|
||||
// optUnmarshalJSON unmarshals the [Option] from a JSON string
|
||||
//
|
||||
// go:noinline
|
||||
func optUnmarshalJSON(isSome *bool, value any, data []byte) error {
|
||||
// decode the value
|
||||
if bytes.Equal(data, jsonNull) {
|
||||
s.isSome = false
|
||||
s.some = *new(A)
|
||||
*isSome = false
|
||||
reflect.ValueOf(value).Elem().SetZero()
|
||||
return nil
|
||||
}
|
||||
s.isSome = true
|
||||
return json.Unmarshal(data, &s.some)
|
||||
*isSome = true
|
||||
return json.Unmarshal(data, value)
|
||||
}
|
||||
|
||||
func (s *Option[A]) UnmarshalJSON(data []byte) error {
|
||||
return optUnmarshalJSON(&s.isSome, &s.value, data)
|
||||
}
|
||||
|
||||
func IsNone[T any](val Option[T]) bool {
|
||||
@@ -72,7 +99,7 @@ func IsNone[T any](val Option[T]) bool {
|
||||
}
|
||||
|
||||
func Some[T any](value T) Option[T] {
|
||||
return Option[T]{isSome: true, some: value}
|
||||
return Option[T]{isSome: true, value: value}
|
||||
}
|
||||
|
||||
func Of[T any](value T) Option[T] {
|
||||
@@ -89,11 +116,11 @@ func IsSome[T any](val Option[T]) bool {
|
||||
|
||||
func MonadFold[A, B any](ma Option[A], onNone func() B, onSome func(A) B) B {
|
||||
if IsSome(ma) {
|
||||
return onSome(ma.some)
|
||||
return onSome(ma.value)
|
||||
}
|
||||
return onNone()
|
||||
}
|
||||
|
||||
func Unwrap[A any](ma Option[A]) (A, bool) {
|
||||
return ma.some, ma.isSome
|
||||
return ma.value, ma.isSome
|
||||
}
|
||||
|
30
option/pair.go
Normal file
30
option/pair.go
Normal 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,
|
||||
)
|
||||
}
|
33
pair/eq.go
Normal file
33
pair/eq.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// 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 (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
)
|
||||
|
||||
// Constructs an equal predicate for an `Either`
|
||||
func Eq[A, B any](a EQ.Eq[A], b EQ.Eq[B]) EQ.Eq[Pair[A, B]] {
|
||||
return EQ.FromEquals(func(l, r Pair[A, B]) bool {
|
||||
return a.Equals(Head(l), Head(r)) && b.Equals(Tail(l), Tail(r))
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||
func FromStrictEquals[A, B comparable]() EQ.Eq[Pair[A, B]] {
|
||||
return Eq(EQ.FromStrictEquals[A](), EQ.FromStrictEquals[B]())
|
||||
}
|
71
pair/generic/sequence.go
Normal file
71
pair/generic/sequence.go
Normal 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))),
|
||||
)
|
||||
}
|
193
pair/monad.go
Normal file
193
pair/monad.go
Normal file
@@ -0,0 +1,193 @@
|
||||
// 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 (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
Sg "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
type (
|
||||
pairPointedHead[A, B any] struct {
|
||||
m M.Monoid[B]
|
||||
}
|
||||
|
||||
pairFunctorHead[A, B, A1 any] struct {
|
||||
}
|
||||
|
||||
pairApplicativeHead[A, B, A1 any] struct {
|
||||
s Sg.Semigroup[B]
|
||||
m M.Monoid[B]
|
||||
}
|
||||
|
||||
pairMonadHead[A, B, A1 any] struct {
|
||||
s Sg.Semigroup[B]
|
||||
m M.Monoid[B]
|
||||
}
|
||||
|
||||
pairPointedTail[A, B any] struct {
|
||||
m M.Monoid[A]
|
||||
}
|
||||
|
||||
pairFunctorTail[A, B, B1 any] struct {
|
||||
}
|
||||
|
||||
pairApplicativeTail[A, B, B1 any] struct {
|
||||
s Sg.Semigroup[A]
|
||||
m M.Monoid[A]
|
||||
}
|
||||
|
||||
pairMonadTail[A, B, B1 any] struct {
|
||||
s Sg.Semigroup[A]
|
||||
m M.Monoid[A]
|
||||
}
|
||||
)
|
||||
|
||||
func (o *pairMonadHead[A, B, A1]) Of(a A) Pair[A, B] {
|
||||
return MakePair(a, o.m.Empty())
|
||||
}
|
||||
|
||||
func (o *pairMonadHead[A, B, A1]) Map(f func(A) A1) func(Pair[A, B]) Pair[A1, B] {
|
||||
return Map[B](f)
|
||||
}
|
||||
|
||||
func (o *pairMonadHead[A, B, A1]) Chain(f func(A) Pair[A1, B]) func(Pair[A, B]) Pair[A1, B] {
|
||||
return Chain[B, A, A1](o.s, f)
|
||||
}
|
||||
|
||||
func (o *pairMonadHead[A, B, A1]) Ap(fa Pair[A, B]) func(Pair[func(A) A1, B]) Pair[A1, B] {
|
||||
return Ap[B, A, A1](o.s, fa)
|
||||
}
|
||||
|
||||
func (o *pairPointedHead[A, B]) Of(a A) Pair[A, B] {
|
||||
return MakePair(a, o.m.Empty())
|
||||
}
|
||||
|
||||
func (o *pairFunctorHead[A, B, A1]) Map(f func(A) A1) func(Pair[A, B]) Pair[A1, B] {
|
||||
return Map[B, A, A1](f)
|
||||
}
|
||||
|
||||
func (o *pairApplicativeHead[A, B, A1]) Map(f func(A) A1) func(Pair[A, B]) Pair[A1, B] {
|
||||
return Map[B, A, A1](f)
|
||||
}
|
||||
|
||||
func (o *pairApplicativeHead[A, B, A1]) Ap(fa Pair[A, B]) func(Pair[func(A) A1, B]) Pair[A1, B] {
|
||||
return Ap[B, A, A1](o.s, fa)
|
||||
}
|
||||
|
||||
func (o *pairApplicativeHead[A, B, A1]) Of(a A) Pair[A, B] {
|
||||
return MakePair(a, o.m.Empty())
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [Pair]
|
||||
func Monad[A, B, A1 any](m M.Monoid[B]) monad.Monad[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]] {
|
||||
return &pairMonadHead[A, B, A1]{s: M.ToSemigroup(m), m: m}
|
||||
}
|
||||
|
||||
// Pointed implements the pointed operations for [Pair]
|
||||
func Pointed[A, B any](m M.Monoid[B]) pointed.Pointed[A, Pair[A, B]] {
|
||||
return &pairPointedHead[A, B]{m: m}
|
||||
}
|
||||
|
||||
// Functor implements the functor operations for [Pair]
|
||||
func Functor[A, B, A1 any]() functor.Functor[A, A1, Pair[A, B], Pair[A1, B]] {
|
||||
return &pairFunctorHead[A, B, A1]{}
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [Pair]
|
||||
func Applicative[A, B, A1 any](m M.Monoid[B]) applicative.Applicative[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]] {
|
||||
return &pairApplicativeHead[A, B, A1]{s: M.ToSemigroup(m), m: m}
|
||||
}
|
||||
|
||||
// MonadHead implements the monadic operations for [Pair]
|
||||
func MonadHead[A, B, A1 any](m M.Monoid[B]) monad.Monad[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]] {
|
||||
return Monad[A, B, A1](m)
|
||||
}
|
||||
|
||||
// PointedHead implements the pointed operations for [Pair]
|
||||
func PointedHead[A, B any](m M.Monoid[B]) pointed.Pointed[A, Pair[A, B]] {
|
||||
return PointedHead[A, B](m)
|
||||
}
|
||||
|
||||
// FunctorHead implements the functor operations for [Pair]
|
||||
func FunctorHead[A, B, A1 any]() functor.Functor[A, A1, Pair[A, B], Pair[A1, B]] {
|
||||
return Functor[A, B, A1]()
|
||||
}
|
||||
|
||||
// ApplicativeHead implements the applicative operations for [Pair]
|
||||
func ApplicativeHead[A, B, A1 any](m M.Monoid[B]) applicative.Applicative[A, A1, Pair[A, B], Pair[A1, B], Pair[func(A) A1, B]] {
|
||||
return Applicative[A, B, A1](m)
|
||||
}
|
||||
|
||||
func (o *pairMonadTail[A, B, B1]) Of(b B) Pair[A, B] {
|
||||
return MakePair(o.m.Empty(), b)
|
||||
}
|
||||
|
||||
func (o *pairMonadTail[A, B, B1]) Map(f func(B) B1) func(Pair[A, B]) Pair[A, B1] {
|
||||
return MapTail[A, B, B1](f)
|
||||
}
|
||||
|
||||
func (o *pairMonadTail[A, B, B1]) Chain(f func(B) Pair[A, B1]) func(Pair[A, B]) Pair[A, B1] {
|
||||
return ChainTail[A, B, B1](o.s, f)
|
||||
}
|
||||
|
||||
func (o *pairMonadTail[A, B, B1]) Ap(fa Pair[A, B]) func(Pair[A, func(B) B1]) Pair[A, B1] {
|
||||
return ApTail[A, B, B1](o.s, fa)
|
||||
}
|
||||
|
||||
func (o *pairPointedTail[A, B]) Of(b B) Pair[A, B] {
|
||||
return MakePair(o.m.Empty(), b)
|
||||
}
|
||||
|
||||
func (o *pairFunctorTail[A, B, B1]) Map(f func(B) B1) func(Pair[A, B]) Pair[A, B1] {
|
||||
return MapTail[A, B, B1](f)
|
||||
}
|
||||
|
||||
func (o *pairApplicativeTail[A, B, B1]) Map(f func(B) B1) func(Pair[A, B]) Pair[A, B1] {
|
||||
return MapTail[A, B, B1](f)
|
||||
}
|
||||
|
||||
func (o *pairApplicativeTail[A, B, B1]) Ap(fa Pair[A, B]) func(Pair[A, func(B) B1]) Pair[A, B1] {
|
||||
return ApTail[A, B, B1](o.s, fa)
|
||||
}
|
||||
|
||||
func (o *pairApplicativeTail[A, B, B1]) Of(b B) Pair[A, B] {
|
||||
return MakePair(o.m.Empty(), b)
|
||||
}
|
||||
|
||||
// MonadTail implements the monadic operations for [Pair]
|
||||
func MonadTail[B, A, B1 any](m M.Monoid[A]) monad.Monad[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]] {
|
||||
return &pairMonadTail[A, B, B1]{s: M.ToSemigroup(m), m: m}
|
||||
}
|
||||
|
||||
// PointedTail implements the pointed operations for [Pair]
|
||||
func PointedTail[B, A any](m M.Monoid[A]) pointed.Pointed[B, Pair[A, B]] {
|
||||
return &pairPointedTail[A, B]{m: m}
|
||||
}
|
||||
|
||||
// FunctorTail implements the functor operations for [Pair]
|
||||
func FunctorTail[B, A, B1 any]() functor.Functor[B, B1, Pair[A, B], Pair[A, B1]] {
|
||||
return &pairFunctorTail[A, B, B1]{}
|
||||
}
|
||||
|
||||
// ApplicativeTail implements the applicative operations for [Pair]
|
||||
func ApplicativeTail[B, A, B1 any](m M.Monoid[A]) applicative.Applicative[B, B1, Pair[A, B], Pair[A, B1], Pair[A, func(B) B1]] {
|
||||
return &pairApplicativeTail[A, B, B1]{s: M.ToSemigroup(m), m: m}
|
||||
}
|
231
pair/pair.go
Normal file
231
pair/pair.go
Normal file
@@ -0,0 +1,231 @@
|
||||
// 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))
|
||||
}
|
||||
}
|
155
pair/testing/laws.go
Normal file
155
pair/testing/laws.go
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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 testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
L "github.com/IBM/fp-go/internal/monad/testing"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
)
|
||||
|
||||
// AssertLaws asserts the apply monad laws for the [P.Pair] monad
|
||||
func assertLawsHead[E, A, B, C any](t *testing.T,
|
||||
m M.Monoid[E],
|
||||
|
||||
eqe EQ.Eq[E],
|
||||
eqa EQ.Eq[A],
|
||||
eqb EQ.Eq[B],
|
||||
eqc EQ.Eq[C],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(a A) bool {
|
||||
|
||||
fofc := P.Pointed[C](m)
|
||||
fofaa := P.Pointed[func(A) A](m)
|
||||
fofbc := P.Pointed[func(B) C](m)
|
||||
fofabb := P.Pointed[func(func(A) B) B](m)
|
||||
|
||||
fmap := P.Functor[func(B) C, E, func(func(A) B) func(A) C]()
|
||||
|
||||
fapabb := P.Applicative[func(A) B, E, B](m)
|
||||
fapabac := P.Applicative[func(A) B, E, func(A) C](m)
|
||||
|
||||
maa := P.Monad[A, E, A](m)
|
||||
mab := P.Monad[A, E, B](m)
|
||||
mac := P.Monad[A, E, C](m)
|
||||
mbc := P.Monad[B, E, C](m)
|
||||
|
||||
return L.MonadAssertLaws(t,
|
||||
P.Eq(eqa, eqe),
|
||||
P.Eq(eqb, eqe),
|
||||
P.Eq(eqc, eqe),
|
||||
|
||||
fofc,
|
||||
fofaa,
|
||||
fofbc,
|
||||
fofabb,
|
||||
|
||||
fmap,
|
||||
|
||||
fapabb,
|
||||
fapabac,
|
||||
|
||||
maa,
|
||||
mab,
|
||||
mac,
|
||||
mbc,
|
||||
|
||||
ab,
|
||||
bc,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// AssertLaws asserts the apply monad laws for the [P.Pair] monad
|
||||
func assertLawsTail[E, A, B, C any](t *testing.T,
|
||||
m M.Monoid[E],
|
||||
|
||||
eqe EQ.Eq[E],
|
||||
eqa EQ.Eq[A],
|
||||
eqb EQ.Eq[B],
|
||||
eqc EQ.Eq[C],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(a A) bool {
|
||||
|
||||
fofc := P.PointedTail[C](m)
|
||||
fofaa := P.PointedTail[func(A) A](m)
|
||||
fofbc := P.PointedTail[func(B) C](m)
|
||||
fofabb := P.PointedTail[func(func(A) B) B](m)
|
||||
|
||||
fmap := P.FunctorTail[func(B) C, E, func(func(A) B) func(A) C]()
|
||||
|
||||
fapabb := P.ApplicativeTail[func(A) B, E, B](m)
|
||||
fapabac := P.ApplicativeTail[func(A) B, E, func(A) C](m)
|
||||
|
||||
maa := P.MonadTail[A, E, A](m)
|
||||
mab := P.MonadTail[A, E, B](m)
|
||||
mac := P.MonadTail[A, E, C](m)
|
||||
mbc := P.MonadTail[B, E, C](m)
|
||||
|
||||
return L.MonadAssertLaws(t,
|
||||
P.Eq(eqe, eqa),
|
||||
P.Eq(eqe, eqb),
|
||||
P.Eq(eqe, eqc),
|
||||
|
||||
fofc,
|
||||
fofaa,
|
||||
fofbc,
|
||||
fofabb,
|
||||
|
||||
fmap,
|
||||
|
||||
fapabb,
|
||||
fapabac,
|
||||
|
||||
maa,
|
||||
mab,
|
||||
mac,
|
||||
mbc,
|
||||
|
||||
ab,
|
||||
bc,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// AssertLaws asserts the apply monad laws for the [P.Pair] monad
|
||||
func AssertLaws[E, A, B, C any](t *testing.T,
|
||||
m M.Monoid[E],
|
||||
|
||||
eqe EQ.Eq[E],
|
||||
eqa EQ.Eq[A],
|
||||
eqb EQ.Eq[B],
|
||||
eqc EQ.Eq[C],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
) func(A) bool {
|
||||
|
||||
head := assertLawsHead(t, m, eqe, eqa, eqb, eqc, ab, bc)
|
||||
tail := assertLawsHead(t, m, eqe, eqa, eqb, eqc, ab, bc)
|
||||
|
||||
return func(a A) bool {
|
||||
return head(a) && tail(a)
|
||||
}
|
||||
}
|
51
pair/testing/laws_test.go
Normal file
51
pair/testing/laws_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2023 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 testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMonadLaws(t *testing.T) {
|
||||
// some comparison
|
||||
eqe := EQ.FromStrictEquals[string]()
|
||||
eqa := EQ.FromStrictEquals[bool]()
|
||||
eqb := EQ.FromStrictEquals[int]()
|
||||
eqc := EQ.FromStrictEquals[string]()
|
||||
|
||||
m := S.Monoid
|
||||
|
||||
ab := func(a bool) int {
|
||||
if a {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
bc := func(b int) string {
|
||||
return fmt.Sprintf("value %d", b)
|
||||
}
|
||||
|
||||
laws := AssertLaws(t, m, eqe, eqa, eqb, eqc, ab, bc)
|
||||
|
||||
assert.True(t, laws(true))
|
||||
assert.True(t, laws(false))
|
||||
}
|
@@ -196,8 +196,8 @@ func Example_getAge() {
|
||||
fmt.Println(zoltar(MakeUser("2005-12-12")))
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, float64](6472)
|
||||
// Left[*time.ParseError, float64](parsing time "July 4, 2001" as "2006-01-02": cannot parse "July 4, 2001" as "2006")
|
||||
// Right[float64](6472)
|
||||
// Left[*time.ParseError](parsing time "July 4, 2001" as "2006-01-02": cannot parse "July 4, 2001" as "2006")
|
||||
// If you survive, you will be 6837
|
||||
}
|
||||
|
||||
@@ -235,8 +235,8 @@ func Example_solution08C() {
|
||||
fmt.Println(eitherWelcome(theresa08))
|
||||
|
||||
// Output:
|
||||
// Left[*errors.errorString, string](your account is not active)
|
||||
// Right[<nil>, string](Welcome Theresa)
|
||||
// Left[*errors.errorString](your account is not active)
|
||||
// Right[string](Welcome Theresa)
|
||||
}
|
||||
|
||||
func Example_solution08D() {
|
||||
@@ -269,8 +269,8 @@ func Example_solution08D() {
|
||||
fmt.Println(register(yi08)())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](Gary)
|
||||
// Left[*errors.errorString, <nil>](Your name Yi is larger than 3 characters)
|
||||
// Right[<nil>, string](Welcome Albert)
|
||||
// Left[*errors.errorString, string](Your name Yi is larger than 3 characters)
|
||||
// Right[string](Gary)
|
||||
// Left[*errors.errorString](Your name Yi is larger than 3 characters)
|
||||
// Right[string](Welcome Albert)
|
||||
// Left[*errors.errorString](Your name Yi is larger than 3 characters)
|
||||
}
|
||||
|
@@ -181,6 +181,6 @@ func Example_solution09C() {
|
||||
fmt.Println(joinMailingList("notanemail")())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](sleepy@grandpa.net)
|
||||
// Left[*errors.errorString, string](email notanemail is invalid)
|
||||
// Right[string](sleepy@grandpa.net)
|
||||
// Left[*errors.errorString](email notanemail is invalid)
|
||||
}
|
||||
|
@@ -117,7 +117,7 @@ func Example_renderPage() {
|
||||
fmt.Println(res(context.TODO())())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](<div>Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]</div>)
|
||||
// Right[string](<div>Destinations: [qui est esse], Events: [ea molestias quasi exercitationem repellat qui ipsa sit aut]</div>)
|
||||
|
||||
}
|
||||
|
||||
|
@@ -63,10 +63,10 @@ func Example_solution11B() {
|
||||
fmt.Println(findByNameID(4)())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](Albert)
|
||||
// Right[<nil>, string](Gary)
|
||||
// Right[<nil>, string](Theresa)
|
||||
// Left[*errors.errorString, string](user 4 not found)
|
||||
// Right[string](Albert)
|
||||
// Right[string](Gary)
|
||||
// Right[string](Theresa)
|
||||
// Left[*errors.errorString](user 4 not found)
|
||||
}
|
||||
|
||||
func Example_solution11C() {
|
||||
|
@@ -60,7 +60,7 @@ func Example_solution12A() {
|
||||
fmt.Println(getJsons(routes)())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, map[string]string](map[/:json for / /about:json for /about])
|
||||
// Right[map[string]string](map[/:json for / /about:json for /about])
|
||||
}
|
||||
|
||||
func Example_solution12B() {
|
||||
@@ -74,8 +74,8 @@ func Example_solution12B() {
|
||||
fmt.Println(startGame(A.From(playerAlbert, Player{Id: 4})))
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](Game started)
|
||||
// Left[*errors.errorString, string](player 4 must have a name)
|
||||
// Right[string](Game started)
|
||||
// Left[*errors.errorString](player 4 must have a name)
|
||||
}
|
||||
|
||||
func Example_solution12C() {
|
||||
@@ -94,5 +94,5 @@ func Example_solution12C() {
|
||||
fmt.Println(readFirst())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, option.Option[string]](Some[string](content of file1 (utf-8)))
|
||||
// Right[option.Option[string]](Some[string](content of file1 (utf-8)))
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ func Example_either_monad() {
|
||||
fmt.Println(makeUrl("8080"))
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](http://localhost:8080)
|
||||
// Right[string](http://localhost:8080)
|
||||
}
|
||||
|
||||
func Example_either_idiomatic() {
|
||||
|
@@ -64,7 +64,7 @@ func Example_io_flow() {
|
||||
fmt.Println(result())
|
||||
|
||||
// Output:
|
||||
// Right[<nil>, string](Text: Some data, Number: 10)
|
||||
// Right[string](Text: Some data, Number: 10)
|
||||
|
||||
}
|
||||
|
||||
|
3
scan.bat
Normal file
3
scan.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
|
||||
busybox find . -type f -name "*\.go" | busybox xargs gopls check
|
31
state/eq.go
Normal file
31
state/eq.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2023 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 state
|
||||
|
||||
import (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
G "github.com/IBM/fp-go/state/generic"
|
||||
)
|
||||
|
||||
// Constructs an equal predicate for a [State]
|
||||
func Eq[S, A any](w EQ.Eq[S], a EQ.Eq[A]) func(S) EQ.Eq[State[S, A]] {
|
||||
return G.Eq[State[S, A]](w, a)
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||
func FromStrictEquals[S, A comparable]() func(S) EQ.Eq[State[S, A]] {
|
||||
return G.FromStrictEquals[State[S, A]]()
|
||||
}
|
36
state/generic/eq.go
Normal file
36
state/generic/eq.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2023 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 (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
// Constructs an equal predicate for a [State]
|
||||
func Eq[GA ~func(S) P.Pair[A, S], S, A any](w EQ.Eq[S], a EQ.Eq[A]) func(S) EQ.Eq[GA] {
|
||||
eqp := P.Eq(a, w)
|
||||
return func(s S) EQ.Eq[GA] {
|
||||
return EQ.FromEquals(func(l, r GA) bool {
|
||||
return eqp.Equals(l(s), r(s))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||
func FromStrictEquals[GA ~func(S) P.Pair[A, S], S, A comparable]() func(S) EQ.Eq[GA] {
|
||||
return Eq[GA](EQ.FromStrictEquals[S](), EQ.FromStrictEquals[A]())
|
||||
}
|
88
state/generic/monad.go
Normal file
88
state/generic/monad.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// 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 (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
type statePointed[GA ~func(S) P.Pair[A, S], S, A any] struct{}
|
||||
|
||||
type stateFunctor[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], S, A, B any] struct{}
|
||||
|
||||
type stateApplicative[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any] struct{}
|
||||
|
||||
type stateMonad[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any] struct{}
|
||||
|
||||
func (o *statePointed[GA, S, A]) Of(a A) GA {
|
||||
return Of[GA](a)
|
||||
}
|
||||
|
||||
func (o *stateApplicative[GB, GAB, GA, S, A, B]) Of(a A) GA {
|
||||
return Of[GA](a)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Of(a A) GA {
|
||||
return Of[GA](a)
|
||||
}
|
||||
|
||||
func (o *stateFunctor[GB, GA, S, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateApplicative[GB, GAB, GA, S, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Chain(f func(A) GB) func(GA) GB {
|
||||
return Chain[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *stateApplicative[GB, GAB, GA, S, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](fa)
|
||||
}
|
||||
|
||||
func (o *stateMonad[GB, GAB, GA, S, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](fa)
|
||||
}
|
||||
|
||||
// Pointed implements the pointed operations for [Writer]
|
||||
func Pointed[GA ~func(S) P.Pair[A, S], S, A any]() pointed.Pointed[A, GA] {
|
||||
return &statePointed[GA, S, A]{}
|
||||
}
|
||||
|
||||
// Functor implements the functor operations for [Writer]
|
||||
func Functor[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], S, A, B any]() functor.Functor[A, B, GA, GB] {
|
||||
return &stateFunctor[GB, GA, S, A, B]{}
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [Writer]
|
||||
func Applicative[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any]() applicative.Applicative[A, B, GA, GB, GAB] {
|
||||
return &stateApplicative[GB, GAB, GA, S, A, B]{}
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [Writer]
|
||||
func Monad[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any]() monad.Monad[A, B, GA, GB, GAB] {
|
||||
return &stateMonad[GB, GAB, GA, S, A, B]{}
|
||||
}
|
131
state/generic/state.go
Normal file
131
state/generic/state.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// 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"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
var (
|
||||
undefined any = struct{}{}
|
||||
)
|
||||
|
||||
func Get[GA ~func(S) P.Pair[S, S], S any]() GA {
|
||||
return P.Of[S]
|
||||
}
|
||||
|
||||
func Gets[GA ~func(S) P.Pair[A, S], FCT ~func(S) A, A, S any](f FCT) GA {
|
||||
return func(s S) P.Pair[A, S] {
|
||||
return P.MakePair(f(s), s)
|
||||
}
|
||||
}
|
||||
|
||||
func Put[GA ~func(S) P.Pair[any, S], S any]() GA {
|
||||
return F.Bind1st(P.MakePair[any, S], undefined)
|
||||
}
|
||||
|
||||
func Modify[GA ~func(S) P.Pair[any, S], FCT ~func(S) S, S any](f FCT) GA {
|
||||
return F.Flow2(
|
||||
f,
|
||||
F.Bind1st(P.MakePair[any, S], undefined),
|
||||
)
|
||||
}
|
||||
|
||||
func Of[GA ~func(S) P.Pair[A, S], S, A any](a A) GA {
|
||||
return F.Bind1st(P.MakePair[A, S], a)
|
||||
}
|
||||
|
||||
func MonadMap[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) B, S, A, B any](fa GA, f FCT) GB {
|
||||
return func(s S) P.Pair[B, S] {
|
||||
p2 := fa(s)
|
||||
return P.MakePair(f(P.Head(p2)), P.Tail(p2))
|
||||
}
|
||||
}
|
||||
|
||||
func Map[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) B, S, A, B any](f FCT) func(GA) GB {
|
||||
return F.Bind2nd(MonadMap[GB, GA, FCT, S, A, B], f)
|
||||
}
|
||||
|
||||
func MonadChain[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](fa GA, f FCT) GB {
|
||||
return func(s S) P.Pair[B, S] {
|
||||
a := fa(s)
|
||||
return f(P.Head(a))(P.Tail(a))
|
||||
}
|
||||
}
|
||||
|
||||
func Chain[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](f FCT) func(GA) GB {
|
||||
return F.Bind2nd(MonadChain[GB, GA, FCT, S, A, B], f)
|
||||
}
|
||||
|
||||
func MonadAp[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any](fab GAB, fa GA) GB {
|
||||
return func(s S) P.Pair[B, S] {
|
||||
f := fab(s)
|
||||
a := fa(P.Tail(f))
|
||||
|
||||
return P.MakePair(P.Head(f)(P.Head(a)), P.Tail(a))
|
||||
}
|
||||
}
|
||||
|
||||
func Ap[GB ~func(S) P.Pair[B, S], GAB ~func(S) P.Pair[func(A) B, S], GA ~func(S) P.Pair[A, S], S, A, B any](ga GA) func(GAB) GB {
|
||||
return F.Bind2nd(MonadAp[GB, GAB, GA, S, A, B], ga)
|
||||
}
|
||||
|
||||
func MonadChainFirst[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](ma GA, f FCT) GA {
|
||||
return C.MonadChainFirst(
|
||||
MonadChain[GA, GA, func(A) GA],
|
||||
MonadMap[GA, GB, func(B) A],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainFirst[GB ~func(S) P.Pair[B, S], GA ~func(S) P.Pair[A, S], FCT ~func(A) GB, S, A, B any](f FCT) func(GA) GA {
|
||||
return C.ChainFirst(
|
||||
Chain[GA, GA, func(A) GA],
|
||||
Map[GA, GB, func(B) A],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func Flatten[GAA ~func(S) P.Pair[GA, S], GA ~func(S) P.Pair[A, S], S, A any](mma GAA) GA {
|
||||
return MonadChain[GA, GAA, func(GA) GA](mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func Execute[GA ~func(S) P.Pair[A, S], S, A any](s S) func(GA) S {
|
||||
return func(fa GA) S {
|
||||
return P.Tail(fa(s))
|
||||
}
|
||||
}
|
||||
|
||||
func Evaluate[GA ~func(S) P.Pair[A, S], S, A any](s S) func(GA) A {
|
||||
return func(fa GA) A {
|
||||
return P.Head(fa(s))
|
||||
}
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~func(S) P.Pair[FAB, S], GB ~func(S) P.Pair[B, S], S, A, B any](fab GFAB, a A) GB {
|
||||
return FC.MonadFlap(
|
||||
MonadMap[GB, GFAB, func(FAB) B],
|
||||
fab,
|
||||
a)
|
||||
}
|
||||
|
||||
func Flap[FAB ~func(A) B, GFAB ~func(S) P.Pair[FAB, S], GB ~func(S) P.Pair[B, S], S, A, B any](a A) func(GFAB) GB {
|
||||
return FC.Flap(Map[GB, GFAB, func(FAB) B], a)
|
||||
}
|
44
state/monad.go
Normal file
44
state/monad.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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 state
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
G "github.com/IBM/fp-go/state/generic"
|
||||
)
|
||||
|
||||
// Pointed implements the pointed operations for [State]
|
||||
func Pointed[S, A any]() pointed.Pointed[A, State[S, A]] {
|
||||
return G.Pointed[State[S, A], S, A]()
|
||||
}
|
||||
|
||||
// Functor implements the pointed operations for [State]
|
||||
func Functor[S, A, B any]() functor.Functor[A, B, State[S, A], State[S, B]] {
|
||||
return G.Functor[State[S, B], State[S, A], S, A, B]()
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [State]
|
||||
func Applicative[S, A, B any]() applicative.Applicative[A, B, State[S, A], State[S, B], State[S, func(A) B]] {
|
||||
return G.Applicative[State[S, B], State[S, func(A) B], State[S, A]]()
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [State]
|
||||
func Monad[S, A, B any]() monad.Monad[A, B, State[S, A], State[S, B], State[S, func(A) B]] {
|
||||
return G.Monad[State[S, B], State[S, func(A) B], State[S, A]]()
|
||||
}
|
97
state/state.go
Normal file
97
state/state.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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 state
|
||||
|
||||
import (
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
R "github.com/IBM/fp-go/reader"
|
||||
G "github.com/IBM/fp-go/state/generic"
|
||||
)
|
||||
|
||||
// State represents an operation on top of a current [State] that produces a value and a new [State]
|
||||
type State[S, A any] R.Reader[S, P.Pair[A, S]]
|
||||
|
||||
func Get[S any]() State[S, S] {
|
||||
return G.Get[State[S, S]]()
|
||||
}
|
||||
|
||||
func Gets[FCT ~func(S) A, A, S any](f FCT) State[S, A] {
|
||||
return G.Gets[State[S, A]](f)
|
||||
}
|
||||
|
||||
func Put[S any]() State[S, any] {
|
||||
return G.Put[State[S, any]]()
|
||||
}
|
||||
|
||||
func Modify[FCT ~func(S) S, S any](f FCT) State[S, any] {
|
||||
return G.Modify[State[S, any]](f)
|
||||
}
|
||||
|
||||
func Of[S, A any](a A) State[S, A] {
|
||||
return G.Of[State[S, A]](a)
|
||||
}
|
||||
|
||||
func MonadMap[S any, FCT ~func(A) B, A, B any](fa State[S, A], f FCT) State[S, B] {
|
||||
return G.MonadMap[State[S, B], State[S, A]](fa, f)
|
||||
}
|
||||
|
||||
func Map[S any, FCT ~func(A) B, A, B any](f FCT) func(State[S, A]) State[S, B] {
|
||||
return G.Map[State[S, B], State[S, A]](f)
|
||||
}
|
||||
|
||||
func MonadChain[S any, FCT ~func(A) State[S, B], A, B any](fa State[S, A], f FCT) State[S, B] {
|
||||
return G.MonadChain[State[S, B], State[S, A]](fa, f)
|
||||
}
|
||||
|
||||
func Chain[S any, FCT ~func(A) State[S, B], A, B any](f FCT) func(State[S, A]) State[S, B] {
|
||||
return G.Chain[State[S, B], State[S, A]](f)
|
||||
}
|
||||
|
||||
func MonadAp[S, A, B any](fab State[S, func(A) B], fa State[S, A]) State[S, B] {
|
||||
return G.MonadAp[State[S, B], State[S, func(A) B], State[S, A]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[S, A, B any](ga State[S, A]) func(State[S, func(A) B]) State[S, B] {
|
||||
return G.Ap[State[S, B], State[S, func(A) B], State[S, A]](ga)
|
||||
}
|
||||
|
||||
func MonadChainFirst[S any, FCT ~func(A) State[S, B], A, B any](ma State[S, A], f FCT) State[S, A] {
|
||||
return G.MonadChainFirst[State[S, B], State[S, A]](ma, f)
|
||||
}
|
||||
|
||||
func ChainFirst[S any, FCT ~func(A) State[S, B], A, B any](f FCT) func(State[S, A]) State[S, A] {
|
||||
return G.ChainFirst[State[S, B], State[S, A]](f)
|
||||
}
|
||||
|
||||
func Flatten[S, A any](mma State[S, State[S, A]]) State[S, A] {
|
||||
return G.Flatten[State[S, State[S, A]], State[S, A]](mma)
|
||||
}
|
||||
|
||||
func Execute[A, S any](s S) func(State[S, A]) S {
|
||||
return G.Execute[State[S, A]](s)
|
||||
}
|
||||
|
||||
func Evaluate[A, S any](s S) func(State[S, A]) A {
|
||||
return G.Evaluate[State[S, A]](s)
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, S, A, B any](fab State[S, FAB], a A) State[S, B] {
|
||||
return G.MonadFlap[FAB, State[S, FAB], State[S, B], S, A, B](fab, a)
|
||||
}
|
||||
|
||||
func Flap[S, A, B any](a A) func(State[S, func(A) B]) State[S, B] {
|
||||
return G.Flap[func(A) B, State[S, func(A) B], State[S, B]](a)
|
||||
}
|
78
state/testing/laws.go
Normal file
78
state/testing/laws.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2023 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 testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
L "github.com/IBM/fp-go/internal/monad/testing"
|
||||
ST "github.com/IBM/fp-go/state"
|
||||
)
|
||||
|
||||
// AssertLaws asserts the apply monad laws for the `Either` monad
|
||||
func AssertLaws[S, A, B, C any](t *testing.T,
|
||||
eqw EQ.Eq[S],
|
||||
eqa EQ.Eq[A],
|
||||
eqb EQ.Eq[B],
|
||||
eqc EQ.Eq[C],
|
||||
|
||||
ab func(A) B,
|
||||
bc func(B) C,
|
||||
|
||||
s S,
|
||||
) func(a A) bool {
|
||||
|
||||
fofc := ST.Pointed[S, C]()
|
||||
fofaa := ST.Pointed[S, func(A) A]()
|
||||
fofbc := ST.Pointed[S, func(B) C]()
|
||||
fofabb := ST.Pointed[S, func(func(A) B) B]()
|
||||
|
||||
fmap := ST.Functor[S, func(B) C, func(func(A) B) func(A) C]()
|
||||
|
||||
fapabb := ST.Applicative[S, func(A) B, B]()
|
||||
fapabac := ST.Applicative[S, func(A) B, func(A) C]()
|
||||
|
||||
maa := ST.Monad[S, A, A]()
|
||||
mab := ST.Monad[S, A, B]()
|
||||
mac := ST.Monad[S, A, C]()
|
||||
mbc := ST.Monad[S, B, C]()
|
||||
|
||||
return L.MonadAssertLaws(t,
|
||||
ST.Eq(eqw, eqa)(s),
|
||||
ST.Eq(eqw, eqb)(s),
|
||||
ST.Eq(eqw, eqc)(s),
|
||||
|
||||
fofc,
|
||||
fofaa,
|
||||
fofbc,
|
||||
fofabb,
|
||||
|
||||
fmap,
|
||||
|
||||
fapabb,
|
||||
fapabac,
|
||||
|
||||
maa,
|
||||
mab,
|
||||
mac,
|
||||
mbc,
|
||||
|
||||
ab,
|
||||
bc,
|
||||
)
|
||||
|
||||
}
|
49
state/testing/laws_test.go
Normal file
49
state/testing/laws_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2023 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 testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMonadLaws(t *testing.T) {
|
||||
// some comparison
|
||||
eqs := A.Eq[string](EQ.FromStrictEquals[string]())
|
||||
eqa := EQ.FromStrictEquals[bool]()
|
||||
eqb := EQ.FromStrictEquals[int]()
|
||||
eqc := EQ.FromStrictEquals[string]()
|
||||
|
||||
ab := func(a bool) int {
|
||||
if a {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
bc := func(b int) string {
|
||||
return fmt.Sprintf("value %d", b)
|
||||
}
|
||||
|
||||
laws := AssertLaws(t, eqs, eqa, eqb, eqc, ab, bc, A.Empty[string]())
|
||||
|
||||
assert.True(t, laws(true))
|
||||
assert.True(t, laws(false))
|
||||
}
|
389
tuple/gen.go
389
tuple/gen.go
@@ -1,12 +1,10 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-10-23 08:31:19.0449107 +0200 CEST m=+0.023307601
|
||||
// 2024-02-08 08:36:32.8883679 +0100 CET m=+0.008054801
|
||||
|
||||
package tuple
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/ord"
|
||||
)
|
||||
@@ -162,27 +160,17 @@ func Replicate1[T any](t T) Tuple1[T] {
|
||||
|
||||
// String prints some debug info for the [Tuple1]
|
||||
func (t Tuple1[T1]) String() string {
|
||||
return fmt.Sprintf("Tuple1[%T](%v)", t.F1, t.F1)
|
||||
return tupleString(t.F1)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple1] into a JSON array
|
||||
func (t Tuple1[T1]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1})
|
||||
return tupleMarshalJSON(t.F1)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple1]
|
||||
func (t *Tuple1[T1]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple1] into an array of type [R] using 1 transformation functions from [T] to [R]
|
||||
@@ -272,32 +260,17 @@ func Replicate2[T any](t T) Tuple2[T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple2]
|
||||
func (t Tuple2[T1, T2]) String() string {
|
||||
return fmt.Sprintf("Tuple2[%T, %T](%v, %v)", t.F1, t.F2, t.F1, t.F2)
|
||||
return tupleString(t.F1, t.F2)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple2] into a JSON array
|
||||
func (t Tuple2[T1, T2]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2})
|
||||
return tupleMarshalJSON(t.F1, t.F2)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple2]
|
||||
func (t *Tuple2[T1, T2]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple2] into an array of type [R] using 2 transformation functions from [T] to [R]
|
||||
@@ -393,37 +366,17 @@ func Replicate3[T any](t T) Tuple3[T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple3]
|
||||
func (t Tuple3[T1, T2, T3]) String() string {
|
||||
return fmt.Sprintf("Tuple3[%T, %T, %T](%v, %v, %v)", t.F1, t.F2, t.F3, t.F1, t.F2, t.F3)
|
||||
return tupleString(t.F1, t.F2, t.F3)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple3] into a JSON array
|
||||
func (t Tuple3[T1, T2, T3]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple3]
|
||||
func (t *Tuple3[T1, T2, T3]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple3] into an array of type [R] using 3 transformation functions from [T] to [R]
|
||||
@@ -525,42 +478,17 @@ func Replicate4[T any](t T) Tuple4[T, T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple4]
|
||||
func (t Tuple4[T1, T2, T3, T4]) String() string {
|
||||
return fmt.Sprintf("Tuple4[%T, %T, %T, %T](%v, %v, %v, %v)", t.F1, t.F2, t.F3, t.F4, t.F1, t.F2, t.F3, t.F4)
|
||||
return tupleString(t.F1, t.F2, t.F3, t.F4)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple4] into a JSON array
|
||||
func (t Tuple4[T1, T2, T3, T4]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3, t.F4})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3, t.F4)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple4]
|
||||
func (t *Tuple4[T1, T2, T3, T4]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 3 {
|
||||
if err := json.Unmarshal(tmp[3], &t.F4); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3, &t.F4)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple4] into an array of type [R] using 4 transformation functions from [T] to [R]
|
||||
@@ -668,47 +596,17 @@ func Replicate5[T any](t T) Tuple5[T, T, T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple5]
|
||||
func (t Tuple5[T1, T2, T3, T4, T5]) String() string {
|
||||
return fmt.Sprintf("Tuple5[%T, %T, %T, %T, %T](%v, %v, %v, %v, %v)", t.F1, t.F2, t.F3, t.F4, t.F5, t.F1, t.F2, t.F3, t.F4, t.F5)
|
||||
return tupleString(t.F1, t.F2, t.F3, t.F4, t.F5)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple5] into a JSON array
|
||||
func (t Tuple5[T1, T2, T3, T4, T5]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3, t.F4, t.F5})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3, t.F4, t.F5)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple5]
|
||||
func (t *Tuple5[T1, T2, T3, T4, T5]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 3 {
|
||||
if err := json.Unmarshal(tmp[3], &t.F4); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 4 {
|
||||
if err := json.Unmarshal(tmp[4], &t.F5); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3, &t.F4, &t.F5)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple5] into an array of type [R] using 5 transformation functions from [T] to [R]
|
||||
@@ -822,52 +720,17 @@ func Replicate6[T any](t T) Tuple6[T, T, T, T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple6]
|
||||
func (t Tuple6[T1, T2, T3, T4, T5, T6]) String() string {
|
||||
return fmt.Sprintf("Tuple6[%T, %T, %T, %T, %T, %T](%v, %v, %v, %v, %v, %v)", t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6)
|
||||
return tupleString(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple6] into a JSON array
|
||||
func (t Tuple6[T1, T2, T3, T4, T5, T6]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3, t.F4, t.F5, t.F6})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple6]
|
||||
func (t *Tuple6[T1, T2, T3, T4, T5, T6]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 3 {
|
||||
if err := json.Unmarshal(tmp[3], &t.F4); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 4 {
|
||||
if err := json.Unmarshal(tmp[4], &t.F5); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 5 {
|
||||
if err := json.Unmarshal(tmp[5], &t.F6); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3, &t.F4, &t.F5, &t.F6)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple6] into an array of type [R] using 6 transformation functions from [T] to [R]
|
||||
@@ -987,57 +850,17 @@ func Replicate7[T any](t T) Tuple7[T, T, T, T, T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple7]
|
||||
func (t Tuple7[T1, T2, T3, T4, T5, T6, T7]) String() string {
|
||||
return fmt.Sprintf("Tuple7[%T, %T, %T, %T, %T, %T, %T](%v, %v, %v, %v, %v, %v, %v)", t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7)
|
||||
return tupleString(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple7] into a JSON array
|
||||
func (t Tuple7[T1, T2, T3, T4, T5, T6, T7]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple7]
|
||||
func (t *Tuple7[T1, T2, T3, T4, T5, T6, T7]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 3 {
|
||||
if err := json.Unmarshal(tmp[3], &t.F4); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 4 {
|
||||
if err := json.Unmarshal(tmp[4], &t.F5); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 5 {
|
||||
if err := json.Unmarshal(tmp[5], &t.F6); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 6 {
|
||||
if err := json.Unmarshal(tmp[6], &t.F7); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3, &t.F4, &t.F5, &t.F6, &t.F7)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple7] into an array of type [R] using 7 transformation functions from [T] to [R]
|
||||
@@ -1163,62 +986,17 @@ func Replicate8[T any](t T) Tuple8[T, T, T, T, T, T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple8]
|
||||
func (t Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) String() string {
|
||||
return fmt.Sprintf("Tuple8[%T, %T, %T, %T, %T, %T, %T, %T](%v, %v, %v, %v, %v, %v, %v, %v)", t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8)
|
||||
return tupleString(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple8] into a JSON array
|
||||
func (t Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple8]
|
||||
func (t *Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 3 {
|
||||
if err := json.Unmarshal(tmp[3], &t.F4); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 4 {
|
||||
if err := json.Unmarshal(tmp[4], &t.F5); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 5 {
|
||||
if err := json.Unmarshal(tmp[5], &t.F6); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 6 {
|
||||
if err := json.Unmarshal(tmp[6], &t.F7); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 7 {
|
||||
if err := json.Unmarshal(tmp[7], &t.F8); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3, &t.F4, &t.F5, &t.F6, &t.F7, &t.F8)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple8] into an array of type [R] using 8 transformation functions from [T] to [R]
|
||||
@@ -1350,67 +1128,17 @@ func Replicate9[T any](t T) Tuple9[T, T, T, T, T, T, T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple9]
|
||||
func (t Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) String() string {
|
||||
return fmt.Sprintf("Tuple9[%T, %T, %T, %T, %T, %T, %T, %T, %T](%v, %v, %v, %v, %v, %v, %v, %v, %v)", t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9)
|
||||
return tupleString(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple9] into a JSON array
|
||||
func (t Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple9]
|
||||
func (t *Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 3 {
|
||||
if err := json.Unmarshal(tmp[3], &t.F4); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 4 {
|
||||
if err := json.Unmarshal(tmp[4], &t.F5); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 5 {
|
||||
if err := json.Unmarshal(tmp[5], &t.F6); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 6 {
|
||||
if err := json.Unmarshal(tmp[6], &t.F7); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 7 {
|
||||
if err := json.Unmarshal(tmp[7], &t.F8); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 8 {
|
||||
if err := json.Unmarshal(tmp[8], &t.F9); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3, &t.F4, &t.F5, &t.F6, &t.F7, &t.F8, &t.F9)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple9] into an array of type [R] using 9 transformation functions from [T] to [R]
|
||||
@@ -1548,72 +1276,17 @@ func Replicate10[T any](t T) Tuple10[T, T, T, T, T, T, T, T, T, T] {
|
||||
|
||||
// String prints some debug info for the [Tuple10]
|
||||
func (t Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) String() string {
|
||||
return fmt.Sprintf("Tuple10[%T, %T, %T, %T, %T, %T, %T, %T, %T, %T](%v, %v, %v, %v, %v, %v, %v, %v, %v, %v)", t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10)
|
||||
return tupleString(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the [Tuple10] into a JSON array
|
||||
func (t Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]any{t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10})
|
||||
return tupleMarshalJSON(t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON array into a [Tuple10]
|
||||
func (t *Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) UnmarshalJSON(data []byte) error {
|
||||
var tmp []json.RawMessage
|
||||
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||
return err
|
||||
}
|
||||
l := len(tmp)
|
||||
if l > 0 {
|
||||
if err := json.Unmarshal(tmp[0], &t.F1); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 1 {
|
||||
if err := json.Unmarshal(tmp[1], &t.F2); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 2 {
|
||||
if err := json.Unmarshal(tmp[2], &t.F3); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 3 {
|
||||
if err := json.Unmarshal(tmp[3], &t.F4); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 4 {
|
||||
if err := json.Unmarshal(tmp[4], &t.F5); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 5 {
|
||||
if err := json.Unmarshal(tmp[5], &t.F6); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 6 {
|
||||
if err := json.Unmarshal(tmp[6], &t.F7); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 7 {
|
||||
if err := json.Unmarshal(tmp[7], &t.F8); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 8 {
|
||||
if err := json.Unmarshal(tmp[8], &t.F9); err != nil {
|
||||
return err
|
||||
}
|
||||
if l > 9 {
|
||||
if err := json.Unmarshal(tmp[9], &t.F10); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return tupleUnmarshalJSON(data, &t.F1, &t.F2, &t.F3, &t.F4, &t.F5, &t.F6, &t.F7, &t.F8, &t.F9, &t.F10)
|
||||
}
|
||||
|
||||
// ToArray converts the [Tuple10] into an array of type [R] using 10 transformation functions from [T] to [R]
|
||||
|
@@ -17,6 +17,14 @@
|
||||
// consider to use arrays for simplicity
|
||||
package tuple
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
N "github.com/IBM/fp-go/number"
|
||||
)
|
||||
|
||||
func Of[T1 any](t T1) Tuple1[T1] {
|
||||
return MakeTuple1(t)
|
||||
}
|
||||
@@ -46,3 +54,31 @@ func BiMap[E, G, A, B any](mapSnd func(E) G, mapFst func(A) B) func(Tuple2[A, E]
|
||||
return MakeTuple2(mapFst(First(t)), mapSnd(Second(t)))
|
||||
}
|
||||
}
|
||||
|
||||
// marshalJSON marshals the tuple into a JSON array
|
||||
func tupleMarshalJSON(src ...any) ([]byte, error) {
|
||||
return json.Marshal(src)
|
||||
}
|
||||
|
||||
// tupleUnmarshalJSON unmarshals a JSON array into a tuple
|
||||
func tupleUnmarshalJSON(data []byte, dst ...any) error {
|
||||
var src []json.RawMessage
|
||||
if err := json.Unmarshal(data, &src); err != nil {
|
||||
return err
|
||||
}
|
||||
l := N.Min(len(src), len(dst))
|
||||
// unmarshal
|
||||
for i := 0; i < l; i++ {
|
||||
if err := json.Unmarshal(src[i], dst[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// successfully decoded the tuple
|
||||
return nil
|
||||
}
|
||||
|
||||
// tupleString converts a tuple to a string
|
||||
func tupleString(src ...any) string {
|
||||
l := len(src)
|
||||
return fmt.Sprintf("Tuple%d[%s](%s)", l, fmt.Sprintf(strings.Repeat(", %T", l)[2:], src...), fmt.Sprintf(strings.Repeat(", %v", l)[2:], src...))
|
||||
}
|
||||
|
@@ -17,20 +17,22 @@ package writer
|
||||
|
||||
import (
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
G "github.com/IBM/fp-go/writer/generic"
|
||||
)
|
||||
|
||||
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||
func Do[S, W any](m M.Monoid[W]) func(S) Writer[W, S] {
|
||||
return G.Do[Writer[W, S], W, S](m)
|
||||
func Do[S, W any](m M.Monoid[W], s S) Writer[W, S] {
|
||||
return G.Do[Writer[W, S], W, S](m, s)
|
||||
}
|
||||
|
||||
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
func Bind[S1, S2, T, W any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(T) func(S1) S2,
|
||||
f func(S1) Writer[W, T],
|
||||
) func(Writer[W, S1]) Writer[W, S2] {
|
||||
return G.Bind[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](setter, f)
|
||||
return G.Bind[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](s, setter, f)
|
||||
}
|
||||
|
||||
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
@@ -58,8 +60,9 @@ func BindTo[W, S1, T any](
|
||||
|
||||
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||
func ApS[S1, S2, T, W any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(T) func(S1) S2,
|
||||
fa Writer[W, T],
|
||||
) func(Writer[W, S1]) Writer[W, S2] {
|
||||
return G.ApS[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](setter, fa)
|
||||
return G.ApS[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](s, setter, fa)
|
||||
}
|
||||
|
@@ -34,33 +34,33 @@ var (
|
||||
)
|
||||
|
||||
func getLastName(s utils.Initial) Writer[[]string, string] {
|
||||
return Of[string](monoid)("Doe")
|
||||
return Of[string](monoid, "Doe")
|
||||
}
|
||||
|
||||
func getGivenName(s utils.WithLastName) Writer[[]string, string] {
|
||||
return Of[string](monoid)("John")
|
||||
return Of[string](monoid, "John")
|
||||
}
|
||||
|
||||
func TestBind(t *testing.T) {
|
||||
|
||||
res := F.Pipe3(
|
||||
Do[utils.Initial](monoid)(utils.Empty),
|
||||
Bind(utils.SetLastName, getLastName),
|
||||
Bind(utils.SetGivenName, getGivenName),
|
||||
Do[utils.Initial](monoid, utils.Empty),
|
||||
Bind(sg, utils.SetLastName, getLastName),
|
||||
Bind(sg, utils.SetGivenName, getGivenName),
|
||||
Map[[]string](utils.GetFullName),
|
||||
)
|
||||
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid)("John Doe")))
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid, "John Doe")))
|
||||
}
|
||||
|
||||
func TestApS(t *testing.T) {
|
||||
|
||||
res := F.Pipe3(
|
||||
Do[utils.Initial](monoid)(utils.Empty),
|
||||
ApS(utils.SetLastName, Of[string](monoid)("Doe")),
|
||||
ApS(utils.SetGivenName, Of[string](monoid)("John")),
|
||||
Do[utils.Initial](monoid, utils.Empty),
|
||||
ApS(sg, utils.SetLastName, Of[string](monoid, "Doe")),
|
||||
ApS(sg, utils.SetGivenName, Of[string](monoid, "John")),
|
||||
Map[[]string](utils.GetFullName),
|
||||
)
|
||||
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid)("John Doe")))
|
||||
assert.True(t, eq.Equals(res, Of[string](monoid, "John Doe")))
|
||||
}
|
||||
|
@@ -16,26 +16,28 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
FCT "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/apply"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
F "github.com/IBM/fp-go/internal/functor"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||
func Do[GS ~func() T.Tuple3[S, W, SG.Semigroup[W]], W, S any](m M.Monoid[W]) func(S) GS {
|
||||
return Of[GS, W, S](m)
|
||||
func Do[GS ~func() P.Pair[S, W], W, S any](m M.Monoid[W], s S) GS {
|
||||
return Of[GS, W, S](m, s)
|
||||
}
|
||||
|
||||
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
func Bind[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, S2, A any](
|
||||
func Bind[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], GT ~func() P.Pair[A, W], W, S1, S2, A any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(A) func(S1) S2,
|
||||
f func(S1) GT,
|
||||
) func(GS1) GS2 {
|
||||
return C.Bind(
|
||||
Chain[GS2, GS1, func(S1) GS2, W, S1, S2],
|
||||
FCT.Bind1st(Chain[GS2, GS1, func(S1) GS2, W, S1, S2], s),
|
||||
Map[GS2, GT, func(A) S2, W, A, S2],
|
||||
setter,
|
||||
f,
|
||||
@@ -43,7 +45,7 @@ func Bind[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2,
|
||||
}
|
||||
|
||||
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||
func Let[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], W, S1, S2, A any](
|
||||
func Let[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], W, S1, S2, A any](
|
||||
key func(A) func(S1) S2,
|
||||
f func(S1) A,
|
||||
) func(GS1) GS2 {
|
||||
@@ -55,7 +57,7 @@ func Let[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2,
|
||||
}
|
||||
|
||||
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||
func LetTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], W, S1, S2, B any](
|
||||
func LetTo[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], W, S1, S2, B any](
|
||||
key func(B) func(S1) S2,
|
||||
b B,
|
||||
) func(GS1) GS2 {
|
||||
@@ -67,7 +69,7 @@ func LetTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2
|
||||
}
|
||||
|
||||
// BindTo initializes a new state [S1] from a value [T]
|
||||
func BindTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, A any](
|
||||
func BindTo[GS1 ~func() P.Pair[S1, W], GT ~func() P.Pair[A, W], W, S1, A any](
|
||||
setter func(A) S1,
|
||||
) func(GT) GS1 {
|
||||
return C.BindTo(
|
||||
@@ -77,13 +79,14 @@ func BindTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A,
|
||||
}
|
||||
|
||||
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||
func ApS[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, S2, A any](
|
||||
func ApS[GS1 ~func() P.Pair[S1, W], GS2 ~func() P.Pair[S2, W], GT ~func() P.Pair[A, W], W, S1, S2, A any](
|
||||
s SG.Semigroup[W],
|
||||
setter func(A) func(S1) S2,
|
||||
fa GT,
|
||||
) func(GS1) GS2 {
|
||||
return apply.ApS(
|
||||
Ap[GS2, func() T.Tuple3[func(A) S2, W, SG.Semigroup[W]], GT, W, A, S2],
|
||||
Map[func() T.Tuple3[func(A) S2, W, SG.Semigroup[W]], GS1, func(S1) func(A) S2],
|
||||
FCT.Bind1st(Ap[GS2, func() P.Pair[func(A) S2, W], GT, W, A, S2], s),
|
||||
Map[func() P.Pair[func(A) S2, W], GS1, func(S1) func(A) S2],
|
||||
setter,
|
||||
fa,
|
||||
)
|
||||
|
@@ -17,21 +17,18 @@ package generic
|
||||
|
||||
import (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
)
|
||||
|
||||
// Constructs an equal predicate for a [Writer]
|
||||
func Eq[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[GA] {
|
||||
func Eq[GA ~func() P.Pair[A, W], W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[GA] {
|
||||
eqp := P.Eq(a, w)
|
||||
return EQ.FromEquals(func(l, r GA) bool {
|
||||
ll := l()
|
||||
rr := r()
|
||||
|
||||
return a.Equals(ll.F1, rr.F1) && w.Equals(ll.F2, rr.F2)
|
||||
return eqp.Equals(l(), r())
|
||||
})
|
||||
}
|
||||
|
||||
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||
func FromStrictEquals[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A comparable]() EQ.Eq[GA] {
|
||||
func FromStrictEquals[GA ~func() P.Pair[A, W], W, A comparable]() EQ.Eq[GA] {
|
||||
return Eq[GA](EQ.FromStrictEquals[W](), EQ.FromStrictEquals[A]())
|
||||
}
|
||||
|
106
writer/generic/monad.go
Normal file
106
writer/generic/monad.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// 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 (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
type writerPointed[GA ~func() P.Pair[A, W], W, A any] struct {
|
||||
m M.Monoid[W]
|
||||
}
|
||||
|
||||
type writerFunctor[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], W, A, B any] struct{}
|
||||
|
||||
type writerApplicative[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any] struct {
|
||||
s SG.Semigroup[W]
|
||||
m M.Monoid[W]
|
||||
}
|
||||
|
||||
type writerMonad[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any] struct {
|
||||
s SG.Semigroup[W]
|
||||
m M.Monoid[W]
|
||||
}
|
||||
|
||||
func (o *writerPointed[GA, W, A]) Of(a A) GA {
|
||||
return Of[GA](o.m, a)
|
||||
}
|
||||
|
||||
func (o *writerApplicative[GB, GAB, GA, W, A, B]) Of(a A) GA {
|
||||
return Of[GA](o.m, a)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Of(a A) GA {
|
||||
return Of[GA](o.m, a)
|
||||
}
|
||||
|
||||
func (o *writerFunctor[GB, GA, W, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *writerApplicative[GB, GAB, GA, W, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Map(f func(A) B) func(GA) GB {
|
||||
return Map[GB, GA](f)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Chain(f func(A) GB) func(GA) GB {
|
||||
return Chain[GB, GA](o.s, f)
|
||||
}
|
||||
|
||||
func (o *writerApplicative[GB, GAB, GA, W, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](o.s, fa)
|
||||
}
|
||||
|
||||
func (o *writerMonad[GB, GAB, GA, W, A, B]) Ap(fa GA) func(GAB) GB {
|
||||
return Ap[GB, GAB, GA](o.s, fa)
|
||||
}
|
||||
|
||||
// Pointed implements the pointed operations for [Writer]
|
||||
func Pointed[GA ~func() P.Pair[A, W], W, A any](m M.Monoid[W]) pointed.Pointed[A, GA] {
|
||||
return &writerPointed[GA, W, A]{
|
||||
m: m,
|
||||
}
|
||||
}
|
||||
|
||||
// Functor implements the functor operations for [Writer]
|
||||
func Functor[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], W, A, B any]() functor.Functor[A, B, GA, GB] {
|
||||
return &writerFunctor[GB, GA, W, A, B]{}
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [Writer]
|
||||
func Applicative[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](m M.Monoid[W]) applicative.Applicative[A, B, GA, GB, GAB] {
|
||||
return &writerApplicative[GB, GAB, GA, W, A, B]{
|
||||
s: M.ToSemigroup(m),
|
||||
m: m,
|
||||
}
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [Writer]
|
||||
func Monad[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](m M.Monoid[W]) monad.Monad[A, B, GA, GB, GAB] {
|
||||
return &writerMonad[GB, GAB, GA, W, A, B]{
|
||||
s: M.ToSemigroup(m),
|
||||
m: m,
|
||||
}
|
||||
}
|
@@ -21,133 +21,137 @@ import (
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
IO "github.com/IBM/fp-go/io/generic"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
P "github.com/IBM/fp-go/pair"
|
||||
SG "github.com/IBM/fp-go/semigroup"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
func Tell[GA ~func() T.Tuple3[any, W, SG.Semigroup[W]], W any](s SG.Semigroup[W]) func(W) GA {
|
||||
return F.Flow2(
|
||||
F.Bind13of3(T.MakeTuple3[any, W, SG.Semigroup[W]])(nil, s),
|
||||
IO.Of[GA],
|
||||
)
|
||||
var (
|
||||
undefined any = struct{}{}
|
||||
)
|
||||
|
||||
func Tell[GA ~func() P.Pair[any, W], W any](w W) GA {
|
||||
return IO.Of[GA](P.MakePair[any](undefined, w))
|
||||
}
|
||||
|
||||
func Of[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](m M.Monoid[W]) func(A) GA {
|
||||
return F.Flow2(
|
||||
F.Bind23of3(T.MakeTuple3[A, W, SG.Semigroup[W]])(m.Empty(), M.ToSemigroup(m)),
|
||||
IO.Of[GA],
|
||||
)
|
||||
func Of[GA ~func() P.Pair[A, W], W, A any](m M.Monoid[W], a A) GA {
|
||||
return IO.Of[GA](P.MakePair(a, m.Empty()))
|
||||
}
|
||||
|
||||
// Listen modifies the result to include the changes to the accumulator
|
||||
func Listen[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GTA ~func() T.Tuple3[T.Tuple2[A, W], W, SG.Semigroup[W]], W, A any](fa GA) GTA {
|
||||
return func() T.Tuple3[T.Tuple2[A, W], W, SG.Semigroup[W]] {
|
||||
func Listen[GA ~func() P.Pair[A, W], GTA ~func() P.Pair[P.Pair[A, W], W], W, A any](fa GA) GTA {
|
||||
return func() P.Pair[P.Pair[A, W], W] {
|
||||
t := fa()
|
||||
return T.MakeTuple3(T.MakeTuple2(t.F1, t.F2), t.F2, t.F3)
|
||||
return P.MakePair(t, P.Tail(t))
|
||||
}
|
||||
}
|
||||
|
||||
// Pass applies the returned function to the accumulator
|
||||
func Pass[GFA ~func() T.Tuple3[T.Tuple2[A, FCT], W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](fa GFA) GA {
|
||||
return func() T.Tuple3[A, W, SG.Semigroup[W]] {
|
||||
func Pass[GFA ~func() P.Pair[P.Pair[A, FCT], W], GA ~func() P.Pair[A, W], FCT ~func(W) W, W, A any](fa GFA) GA {
|
||||
return func() P.Pair[A, W] {
|
||||
t := fa()
|
||||
return T.MakeTuple3(t.F1.F1, t.F1.F2(t.F2), t.F3)
|
||||
a := P.Head(t)
|
||||
return P.MakePair(P.Head(a), P.Tail(a)(P.Tail(t)))
|
||||
}
|
||||
}
|
||||
|
||||
func MonadMap[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) B, W, A, B any](fa GA, f FCT) GB {
|
||||
return IO.MonadMap[GA, GB](fa, T.Map3(f, F.Identity[W], F.Identity[SG.Semigroup[W]]))
|
||||
func MonadMap[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) B, W, A, B any](fa GA, f FCT) GB {
|
||||
return IO.MonadMap[GA, GB](fa, P.Map[W](f))
|
||||
}
|
||||
|
||||
func Map[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) B, W, A, B any](f FCT) func(GA) GB {
|
||||
return IO.Map[GA, GB](T.Map3(f, F.Identity[W], F.Identity[SG.Semigroup[W]]))
|
||||
func Map[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) B, W, A, B any](f FCT) func(GA) GB {
|
||||
return IO.Map[GA, GB](P.Map[W](f))
|
||||
}
|
||||
|
||||
func MonadChain[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](fa GA, f FCT) GB {
|
||||
return func() T.Tuple3[B, W, SG.Semigroup[W]] {
|
||||
func MonadChain[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], fa GA, f FCT) GB {
|
||||
return func() P.Pair[B, W] {
|
||||
a := fa()
|
||||
b := f(a.F1)()
|
||||
b := f(P.Head(a))()
|
||||
|
||||
return T.MakeTuple3(b.F1, b.F3.Concat(a.F2, b.F2), b.F3)
|
||||
return P.MakePair(P.Head(b), s.Concat(P.Tail(a), P.Tail(b)))
|
||||
}
|
||||
}
|
||||
|
||||
func Chain[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](f FCT) func(GA) GB {
|
||||
return F.Bind2nd(MonadChain[GB, GA, FCT, W, A, B], f)
|
||||
func Chain[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], f FCT) func(GA) GB {
|
||||
return func(fa GA) GB {
|
||||
return MonadChain(s, fa, f)
|
||||
}
|
||||
}
|
||||
|
||||
func MonadAp[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[func(A) B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A, B any](fab GAB, fa GA) GB {
|
||||
return func() T.Tuple3[B, W, SG.Semigroup[W]] {
|
||||
func MonadAp[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](s SG.Semigroup[W], fab GAB, fa GA) GB {
|
||||
return func() P.Pair[B, W] {
|
||||
f := fab()
|
||||
a := fa()
|
||||
|
||||
return T.MakeTuple3(f.F1(a.F1), f.F3.Concat(f.F2, a.F2), f.F3)
|
||||
return P.MakePair(P.Head(f)(P.Head(a)), s.Concat(P.Tail(f), P.Tail(a)))
|
||||
}
|
||||
}
|
||||
|
||||
func Ap[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[func(A) B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A, B any](ga GA) func(GAB) GB {
|
||||
return F.Bind2nd(MonadAp[GB, GAB, GA], ga)
|
||||
func Ap[GB ~func() P.Pair[B, W], GAB ~func() P.Pair[func(A) B, W], GA ~func() P.Pair[A, W], W, A, B any](s SG.Semigroup[W], ga GA) func(GAB) GB {
|
||||
return func(fab GAB) GB {
|
||||
return MonadAp[GB](s, fab, ga)
|
||||
}
|
||||
}
|
||||
|
||||
func MonadChainFirst[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](ma GA, f FCT) GA {
|
||||
func MonadChainFirst[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], ma GA, f FCT) GA {
|
||||
return C.MonadChainFirst(
|
||||
MonadChain[GA, GA, func(A) GA],
|
||||
F.Bind1of3(MonadChain[GA, GA, func(A) GA])(s),
|
||||
MonadMap[GA, GB, func(B) A],
|
||||
ma,
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainFirst[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](f FCT) func(GA) GA {
|
||||
func ChainFirst[GB ~func() P.Pair[B, W], GA ~func() P.Pair[A, W], FCT ~func(A) GB, W, A, B any](s SG.Semigroup[W], f FCT) func(GA) GA {
|
||||
return C.ChainFirst(
|
||||
Chain[GA, GA, func(A) GA],
|
||||
F.Bind1st(Chain[GA, GA, func(A) GA], s),
|
||||
Map[GA, GB, func(B) A],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func Flatten[GAA ~func() T.Tuple3[GA, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](mma GAA) GA {
|
||||
return MonadChain[GA, GAA, func(GA) GA](mma, F.Identity[GA])
|
||||
func Flatten[GAA ~func() P.Pair[GA, W], GA ~func() P.Pair[A, W], W, A any](s SG.Semigroup[W], mma GAA) GA {
|
||||
return MonadChain[GA, GAA, func(GA) GA](s, mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func Execute[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](fa GA) W {
|
||||
return fa().F2
|
||||
func Execute[GA ~func() P.Pair[A, W], W, A any](fa GA) W {
|
||||
return P.Tail(fa())
|
||||
}
|
||||
|
||||
func Evaluate[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](fa GA) A {
|
||||
return fa().F1
|
||||
func Evaluate[GA ~func() P.Pair[A, W], W, A any](fa GA) A {
|
||||
return P.Head(fa())
|
||||
}
|
||||
|
||||
// MonadCensor modifies the final accumulator value by applying a function
|
||||
func MonadCensor[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](fa GA, f FCT) GA {
|
||||
return IO.MonadMap[GA, GA](fa, T.Map3(F.Identity[A], f, F.Identity[SG.Semigroup[W]]))
|
||||
func MonadCensor[GA ~func() P.Pair[A, W], FCT ~func(W) W, W, A any](fa GA, f FCT) GA {
|
||||
return IO.MonadMap[GA, GA](fa, P.MapTail[A](f))
|
||||
}
|
||||
|
||||
// Censor modifies the final accumulator value by applying a function
|
||||
func Censor[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](f FCT) func(GA) GA {
|
||||
return IO.Map[GA, GA](T.Map3(F.Identity[A], f, F.Identity[SG.Semigroup[W]]))
|
||||
func Censor[GA ~func() P.Pair[A, W], FCT ~func(W) W, W, A any](f FCT) func(GA) GA {
|
||||
return IO.Map[GA, GA](P.MapTail[A](f))
|
||||
}
|
||||
|
||||
// MonadListens projects a value from modifications made to the accumulator during an action
|
||||
func MonadListens[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]], FCT ~func(W) B, W, A, B any](fa GA, f FCT) GAB {
|
||||
return func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]] {
|
||||
func MonadListens[GA ~func() P.Pair[A, W], GAB ~func() P.Pair[P.Pair[A, B], W], FCT ~func(W) B, W, A, B any](fa GA, f FCT) GAB {
|
||||
return func() P.Pair[P.Pair[A, B], W] {
|
||||
a := fa()
|
||||
return T.MakeTuple3(T.MakeTuple2(a.F1, f(a.F2)), a.F2, a.F3)
|
||||
t := P.Tail(a)
|
||||
return P.MakePair(P.MakePair(P.Head(a), f(t)), t)
|
||||
}
|
||||
}
|
||||
|
||||
// Listens projects a value from modifications made to the accumulator during an action
|
||||
func Listens[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]], FCT ~func(W) B, W, A, B any](f FCT) func(GA) GAB {
|
||||
func Listens[GA ~func() P.Pair[A, W], GAB ~func() P.Pair[P.Pair[A, B], W], FCT ~func(W) B, W, A, B any](f FCT) func(GA) GAB {
|
||||
return F.Bind2nd(MonadListens[GA, GAB, FCT], f)
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~func() T.Tuple3[FAB, W, SG.Semigroup[W]], GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], W, A, B any](fab GFAB, a A) GB {
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~func() P.Pair[FAB, W], GB ~func() P.Pair[B, W], W, A, B any](fab GFAB, a A) GB {
|
||||
return FC.MonadFlap(
|
||||
MonadMap[GB, GFAB, func(FAB) B],
|
||||
fab,
|
||||
a)
|
||||
}
|
||||
|
||||
func Flap[FAB ~func(A) B, GFAB ~func() T.Tuple3[FAB, W, SG.Semigroup[W]], GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], W, A, B any](a A) func(GFAB) GB {
|
||||
func Flap[FAB ~func(A) B, GFAB ~func() P.Pair[FAB, W], GB ~func() P.Pair[B, W], W, A, B any](a A) func(GFAB) GB {
|
||||
return FC.Flap(Map[GB, GFAB, func(FAB) B], a)
|
||||
}
|
||||
|
45
writer/monad.go
Normal file
45
writer/monad.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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 writer
|
||||
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/applicative"
|
||||
"github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/monad"
|
||||
"github.com/IBM/fp-go/internal/pointed"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
G "github.com/IBM/fp-go/writer/generic"
|
||||
)
|
||||
|
||||
// Pointed implements the pointed operations for [Writer]
|
||||
func Pointed[W, A any](m M.Monoid[W]) pointed.Pointed[A, Writer[W, A]] {
|
||||
return G.Pointed[Writer[W, A], W, A](m)
|
||||
}
|
||||
|
||||
// Functor implements the pointed operations for [Writer]
|
||||
func Functor[W, A, B any]() functor.Functor[A, B, Writer[W, A], Writer[W, B]] {
|
||||
return G.Functor[Writer[W, B], Writer[W, A], W, A, B]()
|
||||
}
|
||||
|
||||
// Applicative implements the applicative operations for [Writer]
|
||||
func Applicative[W, A, B any](m M.Monoid[W]) applicative.Applicative[A, B, Writer[W, A], Writer[W, B], Writer[W, func(A) B]] {
|
||||
return G.Applicative[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](m)
|
||||
}
|
||||
|
||||
// Monad implements the monadic operations for [Writer]
|
||||
func Monad[W, A, B any](m M.Monoid[W]) monad.Monad[A, B, Writer[W, A], Writer[W, B], Writer[W, func(A) B]] {
|
||||
return G.Monad[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](m)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user