mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-26 19:38:58 +02:00
Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b434f1fbf4 | ||
|
756e1336dc | ||
|
c629d18bb3 | ||
|
1eefc28ba6 | ||
|
af2915d98a | ||
|
e9f9c2777f | ||
|
895862a67e | ||
|
caf0574742 | ||
|
bace6f01eb | ||
|
254c63a16f | ||
|
655c8a9b1d | ||
|
c6d6be66e0 | ||
|
e313f95865 | ||
|
5f25317f97 | ||
|
f5aa2d6c15 | ||
|
7262820624 | ||
|
c8fc10358b | ||
|
1cd167541d | ||
|
ebe94d71dc | ||
|
7ef6eb524b | ||
|
7b82e87bf3 | ||
|
e8fdbe9f87 | ||
|
226c7039de | ||
|
943ae8e009 | ||
|
44c8441b07 | ||
|
600aeae770 | ||
|
f74a407294 | ||
|
b15ab38861 | ||
|
6532a83e82 | ||
|
7c12b72db1 | ||
|
dc894ad643 | ||
|
c902058320 | ||
|
bf33f4fb66 | ||
|
b4d2a5c6be | ||
|
705b71d95c | ||
|
34844bcfc2 | ||
|
9a9d13b066 | ||
|
da1449e680 | ||
|
865d9fe064 | ||
|
c5b1bae65a | ||
|
0a395f63ff | ||
|
26a7066de0 | ||
|
52823e2c8e | ||
|
503021c65e | ||
|
a2a6a41993 | ||
|
7da9de6f41 | ||
|
ff1b6faf84 | ||
|
38120764e7 | ||
|
a83c2aec49 | ||
|
03debd37c8 | ||
|
4f04344cda | ||
|
cf1c886f48 | ||
|
3e0eb99b88 | ||
|
cb15a3d9fc | ||
|
16535605f5 | ||
|
53f4e5ebd7 | ||
|
fb91fd5dc8 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
|||||||
go-version: [ '1.20.x', '1.21.x' ]
|
go-version: [ '1.20.x', '1.21.x' ]
|
||||||
steps:
|
steps:
|
||||||
# full checkout for semantic-release
|
# full checkout for semantic-release
|
||||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up go ${{ matrix.go-version }}
|
- name: Set up go ${{ matrix.go-version }}
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# full checkout for semantic-release
|
# full checkout for semantic-release
|
||||||
- name: Full checkout
|
- name: Full checkout
|
||||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
13
README.md
13
README.md
@@ -14,6 +14,8 @@ go get github.com/IBM/fp-go
|
|||||||
|
|
||||||
Refer to the [samples](./samples/).
|
Refer to the [samples](./samples/).
|
||||||
|
|
||||||
|
Find API documentation [here](https://pkg.go.dev/github.com/IBM/fp-go)
|
||||||
|
|
||||||
## Design Goal
|
## Design Goal
|
||||||
|
|
||||||
This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in golang. It encourages the following patterns:
|
This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in golang. It encourages the following patterns:
|
||||||
@@ -192,3 +194,14 @@ this would be the completely generic method signature for all possible monads. I
|
|||||||
This FP library addresses this by introducing the HKTs as individual types, e.g. `HKT[A]` would be represented as a new generic type `HKTA`. This loses the correlation to the type `A` but allows to implement generic algorithms, at the price of readability.
|
This FP library addresses this by introducing the HKTs as individual types, e.g. `HKT[A]` would be represented as a new generic type `HKTA`. This loses the correlation to the type `A` but allows to implement generic algorithms, at the price of readability.
|
||||||
|
|
||||||
For that reason these implementations are kept in the `internal` package. These are meant to be used by the library itself or by extensions, not by end users.
|
For that reason these implementations are kept in the `internal` package. These are meant to be used by the library itself or by extensions, not by end users.
|
||||||
|
|
||||||
|
## Map/Ap/Flap
|
||||||
|
|
||||||
|
The following table lists the relationship between some selected operators
|
||||||
|
|
||||||
|
| Opertator | Parameter | Monad | Result |
|
||||||
|
| -------- | ---------------- | --------------- | -------- |
|
||||||
|
| Map | `func(A) B` | `HKT[A]` | `HKT[B]` |
|
||||||
|
| Chain | `func(A) HKT[B]` | `HKT[A]` | `HKT[B]` |
|
||||||
|
| Ap | `HKT[A]` | `HKT[func(A)B]` | `HKT[B]` |
|
||||||
|
| Flap | `A` | `HKT[func(A)B]` | `HKT[B]` |
|
||||||
|
@@ -308,3 +308,11 @@ func Fold[A any](m M.Monoid[A]) func([]A) A {
|
|||||||
func Push[A any](a A) func([]A) []A {
|
func Push[A any](a A) func([]A) []A {
|
||||||
return G.Push[[]A](a)
|
return G.Push[[]A](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
|
||||||
|
return G.MonadFlap[func(A) B, []func(A) B, []B, A, B](fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[B, A any](a A) func([]func(A) B) []B {
|
||||||
|
return G.Flap[func(A) B, []func(A) B, []B, A, B](a)
|
||||||
|
}
|
||||||
|
@@ -18,6 +18,7 @@ package generic
|
|||||||
import (
|
import (
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
"github.com/IBM/fp-go/internal/array"
|
"github.com/IBM/fp-go/internal/array"
|
||||||
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
M "github.com/IBM/fp-go/monoid"
|
M "github.com/IBM/fp-go/monoid"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
"github.com/IBM/fp-go/tuple"
|
"github.com/IBM/fp-go/tuple"
|
||||||
@@ -187,6 +188,14 @@ func IsEmpty[AS ~[]A, A any](as AS) bool {
|
|||||||
return array.IsEmpty(as)
|
return array.IsEmpty(as)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNil[GA ~[]A, A any](as GA) bool {
|
||||||
|
return array.IsNil(as)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsNonNil[GA ~[]A, A any](as GA) bool {
|
||||||
|
return array.IsNonNil(as)
|
||||||
|
}
|
||||||
|
|
||||||
func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B {
|
func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B {
|
||||||
return func(as AS) B {
|
return func(as AS) B {
|
||||||
if IsEmpty(as) {
|
if IsEmpty(as) {
|
||||||
@@ -242,3 +251,11 @@ func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
|
|||||||
func Push[GA ~[]A, A any](a A) func(GA) GA {
|
func Push[GA ~[]A, A any](a A) func(GA) GA {
|
||||||
return F.Bind2nd(array.Push[GA, A], a)
|
return F.Bind2nd(array.Push[GA, A], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB {
|
||||||
|
return FC.MonadFlap(MonadMap[GFAB, GB], fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
|
||||||
|
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
|
||||||
|
}
|
||||||
|
124
array/nonempty/array.go
Normal file
124
array/nonempty/array.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// 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 nonempty
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/array"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NonEmptyArray represents an array with at least one element
|
||||||
|
type NonEmptyArray[A any] []A
|
||||||
|
|
||||||
|
// Of constructs a single element array
|
||||||
|
func Of[A any](first A) NonEmptyArray[A] {
|
||||||
|
return G.Of[NonEmptyArray[A]](first)
|
||||||
|
}
|
||||||
|
|
||||||
|
// From constructs a [NonEmptyArray] from a set of variadic arguments
|
||||||
|
func From[A any](first A, data ...A) NonEmptyArray[A] {
|
||||||
|
count := len(data)
|
||||||
|
if count == 0 {
|
||||||
|
return Of(first)
|
||||||
|
}
|
||||||
|
// allocate the requested buffer
|
||||||
|
buffer := make(NonEmptyArray[A], count+1)
|
||||||
|
buffer[0] = first
|
||||||
|
copy(buffer[1:], data)
|
||||||
|
return buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsEmpty[A any](as NonEmptyArray[A]) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsNonEmpty[A any](as NonEmptyArray[A]) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadMap[A, B any](as NonEmptyArray[A], f func(a A) B) NonEmptyArray[B] {
|
||||||
|
return G.MonadMap[NonEmptyArray[A], NonEmptyArray[B]](as, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Map[A, B any](f func(a A) B) func(NonEmptyArray[A]) NonEmptyArray[B] {
|
||||||
|
return F.Bind2nd(MonadMap[A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Reduce[A, B any](f func(B, A) B, initial B) func(NonEmptyArray[A]) B {
|
||||||
|
return func(as NonEmptyArray[A]) B {
|
||||||
|
return array.Reduce(as, f, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Tail[A any](as NonEmptyArray[A]) []A {
|
||||||
|
return as[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func Head[A any](as NonEmptyArray[A]) A {
|
||||||
|
return as[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func First[A any](as NonEmptyArray[A]) A {
|
||||||
|
return as[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func Last[A any](as NonEmptyArray[A]) A {
|
||||||
|
return as[len(as)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func Size[A any](as NonEmptyArray[A]) int {
|
||||||
|
return G.Size(as)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flatten[A any](mma NonEmptyArray[NonEmptyArray[A]]) NonEmptyArray[A] {
|
||||||
|
return G.Flatten(mma)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadChain[A, B any](fa NonEmptyArray[A], f func(a A) NonEmptyArray[B]) NonEmptyArray[B] {
|
||||||
|
return G.MonadChain[NonEmptyArray[A], NonEmptyArray[B]](fa, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Chain[A, B any](f func(A) NonEmptyArray[B]) func(NonEmptyArray[A]) NonEmptyArray[B] {
|
||||||
|
return G.Chain[NonEmptyArray[A], NonEmptyArray[B]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadAp[B, A any](fab NonEmptyArray[func(A) B], fa NonEmptyArray[A]) NonEmptyArray[B] {
|
||||||
|
return G.MonadAp[NonEmptyArray[B]](fab, fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ap[B, A any](fa NonEmptyArray[A]) func(NonEmptyArray[func(A) B]) NonEmptyArray[B] {
|
||||||
|
return G.Ap[NonEmptyArray[B], NonEmptyArray[func(A) B]](fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FoldMap maps and folds a [NonEmptyArray]. Map the [NonEmptyArray] passing each value to the iterating function. Then fold the results using the provided [Semigroup].
|
||||||
|
func FoldMap[A, B any](s S.Semigroup[B]) func(func(A) B) func(NonEmptyArray[A]) B {
|
||||||
|
return func(f func(A) B) func(NonEmptyArray[A]) B {
|
||||||
|
return func(as NonEmptyArray[A]) B {
|
||||||
|
return array.Reduce(Tail(as), func(cur B, a A) B {
|
||||||
|
return s.Concat(cur, f(a))
|
||||||
|
}, f(Head(as)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fold folds the [NonEmptyArray] using the provided [Semigroup].
|
||||||
|
func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
|
||||||
|
return func(as NonEmptyArray[A]) A {
|
||||||
|
return array.Reduce(Tail(as), s.Concat, Head(as))
|
||||||
|
}
|
||||||
|
}
|
42
cli/pipe.go
42
cli/pipe.go
@@ -25,6 +25,40 @@ import (
|
|||||||
C "github.com/urfave/cli/v2"
|
C "github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func generateUnsliced(f *os.File, i int) {
|
||||||
|
// Create the optionize version
|
||||||
|
fmt.Fprintf(f, "\n// Unsliced%d converts a function taking a slice parameter into a function with %d parameters\n", i, i)
|
||||||
|
fmt.Fprintf(f, "func Unsliced%d[F ~func([]T) R, T, R any](f F) func(", i)
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "T")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, ") R {\n")
|
||||||
|
fmt.Fprintf(f, " return func(")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "t%d", j+1)
|
||||||
|
}
|
||||||
|
if i > 0 {
|
||||||
|
fmt.Fprintf(f, " T")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, ") R {\n")
|
||||||
|
fmt.Fprintf(f, " return f([]T{")
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if j > 0 {
|
||||||
|
fmt.Fprintf(f, ", ")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "t%d", j+1)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(f, "})")
|
||||||
|
fmt.Fprintln(f, " }")
|
||||||
|
fmt.Fprintln(f, "}")
|
||||||
|
}
|
||||||
|
|
||||||
func generateVariadic(f *os.File, i int) {
|
func generateVariadic(f *os.File, i int) {
|
||||||
// Create the nullary version
|
// Create the nullary version
|
||||||
fmt.Fprintf(f, "\n// Variadic%d converts a function taking %d parameters and a final slice into a function with %d parameters but a final variadic argument\n", i, i, i)
|
fmt.Fprintf(f, "\n// Variadic%d converts a function taking %d parameters and a final slice into a function with %d parameters but a final variadic argument\n", i, i, i)
|
||||||
@@ -83,7 +117,7 @@ func generateVariadic(f *os.File, i int) {
|
|||||||
fmt.Fprintf(f, "v)\n")
|
fmt.Fprintf(f, "v)\n")
|
||||||
fmt.Fprintf(f, " }\n")
|
fmt.Fprintf(f, " }\n")
|
||||||
|
|
||||||
fmt.Fprintf(f, "}")
|
fmt.Fprintf(f, "}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateUnvariadic(f *os.File, i int) {
|
func generateUnvariadic(f *os.File, i int) {
|
||||||
@@ -144,7 +178,7 @@ func generateUnvariadic(f *os.File, i int) {
|
|||||||
fmt.Fprintf(f, "v...)\n")
|
fmt.Fprintf(f, "v...)\n")
|
||||||
fmt.Fprintf(f, " }\n")
|
fmt.Fprintf(f, " }\n")
|
||||||
|
|
||||||
fmt.Fprintf(f, "}")
|
fmt.Fprintf(f, "}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateNullary(f *os.File, i int) {
|
func generateNullary(f *os.File, i int) {
|
||||||
@@ -347,6 +381,8 @@ func generatePipeHelpers(filename string, count int) error {
|
|||||||
generateVariadic(f, 0)
|
generateVariadic(f, 0)
|
||||||
// unvariadic
|
// unvariadic
|
||||||
generateUnvariadic(f, 0)
|
generateUnvariadic(f, 0)
|
||||||
|
// unsliced
|
||||||
|
generateUnsliced(f, 0)
|
||||||
|
|
||||||
for i := 1; i <= count; i++ {
|
for i := 1; i <= count; i++ {
|
||||||
|
|
||||||
@@ -364,6 +400,8 @@ func generatePipeHelpers(filename string, count int) error {
|
|||||||
generateVariadic(f, i)
|
generateVariadic(f, i)
|
||||||
// unvariadic
|
// unvariadic
|
||||||
generateUnvariadic(f, i)
|
generateUnvariadic(f, i)
|
||||||
|
// unsliced
|
||||||
|
generateUnsliced(f, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@@ -338,7 +338,7 @@ func generateUntupled(f *os.File, i int) {
|
|||||||
|
|
||||||
func generateTupled(f *os.File, i int) {
|
func generateTupled(f *os.File, i int) {
|
||||||
// Create the optionize version
|
// Create the optionize version
|
||||||
fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters returning into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i)
|
fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i)
|
||||||
fmt.Fprintf(f, "func Tupled%d[F ~func(", i)
|
fmt.Fprintf(f, "func Tupled%d[F ~func(", i)
|
||||||
for j := 0; j < i; j++ {
|
for j := 0; j < i; j++ {
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
|
@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) Reader[B]) func([]A) Reader[[]B] {
|
|||||||
return R.TraverseArray[Reader[B], Reader[[]B], []A](f)
|
return R.TraverseArray[Reader[B], Reader[[]B], []A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[A, B any](f func(int, A) Reader[B]) func([]A) Reader[[]B] {
|
||||||
|
return R.TraverseArrayWithIndex[Reader[B], Reader[[]B], []A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[A any](ma []Reader[A]) Reader[[]A] {
|
func SequenceArray[A any](ma []Reader[A]) Reader[[]A] {
|
||||||
return R.SequenceArray[Reader[A], Reader[[]A]](ma)
|
return R.SequenceArray[Reader[A], Reader[[]A]](ma)
|
||||||
|
@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) ReaderEither[B]) func([]A) ReaderEither[[
|
|||||||
return RE.TraverseArray[ReaderEither[B], ReaderEither[[]B], []A](f)
|
return RE.TraverseArray[ReaderEither[B], ReaderEither[[]B], []A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
|
||||||
|
return RE.TraverseArrayWithIndex[ReaderEither[B], ReaderEither[[]B], []A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
|
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
|
||||||
return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma)
|
return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma)
|
||||||
|
@@ -25,6 +25,11 @@ func TraverseArray[A, B any](f func(A) ReaderIO[B]) func([]A) ReaderIO[[]B] {
|
|||||||
return R.TraverseArray[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f)
|
return R.TraverseArray[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderIO[B]) func([]A) ReaderIO[[]B] {
|
||||||
|
return R.TraverseArrayWithIndex[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[A any](ma []ReaderIO[A]) ReaderIO[[]A] {
|
func SequenceArray[A any](ma []ReaderIO[A]) ReaderIO[[]A] {
|
||||||
return R.SequenceArray[ReaderIO[A], ReaderIO[[]A]](ma)
|
return R.SequenceArray[ReaderIO[A], ReaderIO[[]A]](ma)
|
||||||
|
@@ -18,6 +18,8 @@ package readerio
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
R "github.com/IBM/fp-go/readerio/generic"
|
R "github.com/IBM/fp-go/readerio/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,6 +39,22 @@ func Chain[A, B any](f func(A) ReaderIO[B]) func(ReaderIO[A]) ReaderIO[B] {
|
|||||||
return R.Chain[ReaderIO[A]](f)
|
return R.Chain[ReaderIO[A]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadChainIOK[A, B any](fa ReaderIO[A], f func(A) IO.IO[B]) ReaderIO[B] {
|
||||||
|
return R.MonadChainIOK[ReaderIO[A], ReaderIO[B]](fa, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChainIOK[A, B any](f func(A) IO.IO[B]) func(ReaderIO[A]) ReaderIO[B] {
|
||||||
|
return R.ChainIOK[ReaderIO[A], ReaderIO[B]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadChainFirstIOK[A, B any](fa ReaderIO[A], f func(A) IO.IO[B]) ReaderIO[A] {
|
||||||
|
return R.MonadChainFirstIOK[ReaderIO[A], ReaderIO[B]](fa, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChainFirstIOK[A, B any](f func(A) IO.IO[B]) func(ReaderIO[A]) ReaderIO[A] {
|
||||||
|
return R.ChainFirstIOK[ReaderIO[A], ReaderIO[B]](f)
|
||||||
|
}
|
||||||
|
|
||||||
func Of[A any](a A) ReaderIO[A] {
|
func Of[A any](a A) ReaderIO[A] {
|
||||||
return R.Of[ReaderIO[A]](a)
|
return R.Of[ReaderIO[A]](a)
|
||||||
}
|
}
|
||||||
@@ -54,6 +72,18 @@ func Ask() ReaderIO[context.Context] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||||
func Defer[A any](gen func() ReaderIO[A]) ReaderIO[A] {
|
func Defer[A any](gen L.Lazy[ReaderIO[A]]) ReaderIO[A] {
|
||||||
return R.Defer[ReaderIO[A]](gen)
|
return R.Defer[ReaderIO[A]](gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Memoize computes the value of the provided [ReaderIO] monad lazily but exactly once
|
||||||
|
// The context used to compute the value is the context of the first call, so do not use this
|
||||||
|
// method if the value has a functional dependency on the content of the context
|
||||||
|
func Memoize[A any](rdr ReaderIO[A]) ReaderIO[A] {
|
||||||
|
return R.Memoize[ReaderIO[A]](rdr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten converts a nested [ReaderIO] into a [ReaderIO]
|
||||||
|
func Flatten[A any](mma ReaderIO[ReaderIO[A]]) ReaderIO[A] {
|
||||||
|
return R.Flatten[ReaderIO[A]](mma)
|
||||||
|
}
|
||||||
|
@@ -25,25 +25,31 @@ import (
|
|||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
"github.com/IBM/fp-go/internal/file"
|
"github.com/IBM/fp-go/internal/file"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
IOEF "github.com/IBM/fp-go/ioeither/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
openIOE = IOE.Eitherize1(os.Open)
|
|
||||||
// Open opens a file for reading within the given context
|
// Open opens a file for reading within the given context
|
||||||
Open = F.Flow3(
|
Open = F.Flow3(
|
||||||
openIOE,
|
IOEF.Open,
|
||||||
RIOE.FromIOEither[*os.File],
|
RIOE.FromIOEither[*os.File],
|
||||||
RIOE.WithContext[*os.File],
|
RIOE.WithContext[*os.File],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Remove removes a file by name
|
||||||
|
Remove = F.Flow2(
|
||||||
|
IOEF.Remove,
|
||||||
|
RIOE.FromIOEither[string],
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Close closes an object
|
// Close closes an object
|
||||||
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
|
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
|
||||||
return RIOE.FromIOEither(func() ET.Either[error, any] {
|
return F.Pipe2(
|
||||||
return ET.TryCatchError(func() (any, error) {
|
c,
|
||||||
return c, c.Close()
|
IOEF.Close[C],
|
||||||
})
|
RIOE.FromIOEither[any],
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFile reads a file in the scope of a context
|
// ReadFile reads a file in the scope of a context
|
||||||
|
52
context/readerioeither/file/tempfile.go
Normal file
52
context/readerioeither/file/tempfile.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// 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 file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
|
IOF "github.com/IBM/fp-go/io/file"
|
||||||
|
IOEF "github.com/IBM/fp-go/ioeither/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// onCreateTempFile creates a temp file with sensible defaults
|
||||||
|
onCreateTempFile = CreateTemp("", "*")
|
||||||
|
// destroy handler
|
||||||
|
onReleaseTempFile = F.Flow4(
|
||||||
|
IOF.Close[*os.File],
|
||||||
|
IO.Map((*os.File).Name),
|
||||||
|
RIOE.FromIO[string],
|
||||||
|
RIOE.Chain(Remove),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateTemp created a temp file with proper parametrization
|
||||||
|
func CreateTemp(dir, pattern string) RIOE.ReaderIOEither[*os.File] {
|
||||||
|
return F.Pipe2(
|
||||||
|
IOEF.CreateTemp(dir, pattern),
|
||||||
|
RIOE.FromIOEither[*os.File],
|
||||||
|
RIOE.WithContext[*os.File],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTempFile creates a temporary file, then invokes a callback to create a resource based on the file, then close and remove the temp file
|
||||||
|
func WithTempFile[A any](f func(*os.File) RIOE.ReaderIOEither[A]) RIOE.ReaderIOEither[A] {
|
||||||
|
return RIOE.WithResource[A](onCreateTempFile, onReleaseTempFile)(f)
|
||||||
|
}
|
47
context/readerioeither/file/tempfile_test.go
Normal file
47
context/readerioeither/file/tempfile_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 file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithTempFile(t *testing.T) {
|
||||||
|
|
||||||
|
res := WithTempFile(onWriteAll[*os.File]([]byte("Carsten")))
|
||||||
|
|
||||||
|
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithTempFileOnClosedFile(t *testing.T) {
|
||||||
|
|
||||||
|
res := WithTempFile(func(f *os.File) RIOE.ReaderIOEither[[]byte] {
|
||||||
|
return F.Pipe2(
|
||||||
|
f,
|
||||||
|
onWriteAll[*os.File]([]byte("Carsten")),
|
||||||
|
RIOE.ChainFirst(F.Constant1[[]byte](Close(f))),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
|
||||||
|
}
|
57
context/readerioeither/file/write.go
Normal file
57
context/readerioeither/file/write.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// 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 file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
return func() ([]byte, error) {
|
||||||
|
_, err := w.Write(data)
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
RIOE.WithContext[[]byte],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAll uses a generator function to create a stream, writes data to it and closes it
|
||||||
|
func WriteAll[W io.WriteCloser](data []byte) func(acquire RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
|
||||||
|
onWrite := onWriteAll[W](data)
|
||||||
|
return func(onCreate RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
|
||||||
|
return RIOE.WithResource[[]byte](
|
||||||
|
onCreate,
|
||||||
|
Close[W])(
|
||||||
|
onWrite,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write uses a generator function to create a stream, writes data to it and closes it
|
||||||
|
func Write[R any, W io.WriteCloser](acquire RIOE.ReaderIOEither[W]) func(use func(W) RIOE.ReaderIOEither[R]) RIOE.ReaderIOEither[R] {
|
||||||
|
return RIOE.WithResource[R](
|
||||||
|
acquire,
|
||||||
|
Close[W])
|
||||||
|
}
|
@@ -2,7 +2,7 @@ package readerioeither
|
|||||||
|
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101
|
// 2023-09-12 13:44:14.1022311 +0200 CEST m=+0.017763401
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@@ -2,7 +2,7 @@ package generic
|
|||||||
|
|
||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101
|
// 2023-09-12 13:44:14.1036885 +0200 CEST m=+0.019220801
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
56
context/readerioeither/generic/monoid.go
Normal file
56
context/readerioeither/generic/monoid.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// 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 (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ApplicativeMonoid[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[GRA] {
|
||||||
|
return M.ApplicativeMonoid(
|
||||||
|
Of[GRA],
|
||||||
|
MonadMap[GRA, GRFA],
|
||||||
|
MonadAp[GRA, GRA, GRFA],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplicativeMonoidSeq[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[GRA] {
|
||||||
|
return M.ApplicativeMonoid(
|
||||||
|
Of[GRA],
|
||||||
|
MonadMap[GRA, GRFA],
|
||||||
|
MonadApSeq[GRA, GRA, GRFA],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplicativeMonoidPar[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[GRA] {
|
||||||
|
return M.ApplicativeMonoid(
|
||||||
|
Of[GRA],
|
||||||
|
MonadMap[GRA, GRFA],
|
||||||
|
MonadApPar[GRA, GRA, GRFA],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
@@ -100,6 +100,28 @@ func Map[
|
|||||||
return RIE.Map[GRA, GRB](f)
|
return RIE.Map[GRA, GRB](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadMapTo[
|
||||||
|
GRA ~func(context.Context) GIOA,
|
||||||
|
GRB ~func(context.Context) GIOB,
|
||||||
|
|
||||||
|
GIOA ~func() E.Either[error, A],
|
||||||
|
GIOB ~func() E.Either[error, B],
|
||||||
|
|
||||||
|
A, B any](fa GRA, b B) GRB {
|
||||||
|
return RIE.MonadMapTo[GRA, GRB](fa, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapTo[
|
||||||
|
GRA ~func(context.Context) GIOA,
|
||||||
|
GRB ~func(context.Context) GIOB,
|
||||||
|
|
||||||
|
GIOA ~func() E.Either[error, A],
|
||||||
|
GIOB ~func() E.Either[error, B],
|
||||||
|
|
||||||
|
A, B any](b B) func(GRA) GRB {
|
||||||
|
return RIE.MapTo[GRA, GRB](b)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadChain[
|
func MonadChain[
|
||||||
GRA ~func(context.Context) GIOA,
|
GRA ~func(context.Context) GIOA,
|
||||||
GRB ~func(context.Context) GIOB,
|
GRB ~func(context.Context) GIOB,
|
||||||
@@ -458,6 +480,34 @@ func ChainIOK[
|
|||||||
return RIE.ChainIOK[GRA, GRB](f)
|
return RIE.ChainIOK[GRA, GRB](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadChainReaderIOK[
|
||||||
|
GRB ~func(context.Context) GIOB,
|
||||||
|
GRA ~func(context.Context) GIOA,
|
||||||
|
GRIO ~func(context.Context) GIO,
|
||||||
|
|
||||||
|
GIOA ~func() E.Either[error, A],
|
||||||
|
GIOB ~func() E.Either[error, B],
|
||||||
|
|
||||||
|
GIO ~func() B,
|
||||||
|
|
||||||
|
A, B any](ma GRA, f func(A) GRIO) GRB {
|
||||||
|
return RIE.MonadChainReaderIOK[GRA, GRB](ma, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChainReaderIOK[
|
||||||
|
GRB ~func(context.Context) GIOB,
|
||||||
|
GRA ~func(context.Context) GIOA,
|
||||||
|
GRIO ~func(context.Context) GIO,
|
||||||
|
|
||||||
|
GIOA ~func() E.Either[error, A],
|
||||||
|
GIOB ~func() E.Either[error, B],
|
||||||
|
|
||||||
|
GIO ~func() B,
|
||||||
|
|
||||||
|
A, B any](f func(A) GRIO) func(ma GRA) GRB {
|
||||||
|
return RIE.ChainReaderIOK[GRA, GRB](f)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadChainFirstIOK[
|
func MonadChainFirstIOK[
|
||||||
GRA ~func(context.Context) GIOA,
|
GRA ~func(context.Context) GIOA,
|
||||||
GIOA ~func() E.Either[error, A],
|
GIOA ~func() E.Either[error, A],
|
||||||
@@ -543,3 +593,82 @@ func TryCatch[
|
|||||||
A any](f func(context.Context) func() (A, error)) GRA {
|
A any](f func(context.Context) func() (A, error)) GRA {
|
||||||
return RIE.TryCatch[GRA](f, ER.IdentityError)
|
return RIE.TryCatch[GRA](f, ER.IdentityError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadAlt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](first GEA, second LAZY) GEA {
|
||||||
|
return RIE.MonadAlt(first, second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Alt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](second LAZY) func(GEA) GEA {
|
||||||
|
return RIE.Alt(second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memoize computes the value of the provided monad lazily but exactly once
|
||||||
|
// The context used to compute the value is the context of the first call, so do not use this
|
||||||
|
// method if the value has a functional dependency on the content of the context
|
||||||
|
func Memoize[
|
||||||
|
GRA ~func(context.Context) GIOA,
|
||||||
|
GIOA ~func() E.Either[error, A],
|
||||||
|
A any](rdr GRA) GRA {
|
||||||
|
return RIE.Memoize[GRA](rdr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flatten[
|
||||||
|
GGRA ~func(context.Context) GGIOA,
|
||||||
|
GGIOA ~func() E.Either[error, GRA],
|
||||||
|
GRA ~func(context.Context) GIOA,
|
||||||
|
GIOA ~func() E.Either[error, A],
|
||||||
|
A any](rdr GGRA) GRA {
|
||||||
|
return RIE.Flatten[GRA](rdr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadFromReaderIO[
|
||||||
|
GRIOEA ~func(context.Context) GIOEA,
|
||||||
|
GIOEA ~func() E.Either[error, A],
|
||||||
|
|
||||||
|
GRIOA ~func(context.Context) GIOA,
|
||||||
|
GIOA ~func() A,
|
||||||
|
|
||||||
|
A any](a A, f func(A) GRIOA) GRIOEA {
|
||||||
|
return RIE.MonadFromReaderIO[GRIOEA](a, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromReaderIO[
|
||||||
|
GRIOEA ~func(context.Context) GIOEA,
|
||||||
|
GIOEA ~func() E.Either[error, A],
|
||||||
|
|
||||||
|
GRIOA ~func(context.Context) GIOA,
|
||||||
|
GIOA ~func() A,
|
||||||
|
|
||||||
|
A any](f func(A) GRIOA) func(A) GRIOEA {
|
||||||
|
return RIE.FromReaderIO[GRIOEA](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RightReaderIO[
|
||||||
|
GRIOEA ~func(context.Context) GIOEA,
|
||||||
|
GIOEA ~func() E.Either[error, A],
|
||||||
|
|
||||||
|
GRIOA ~func(context.Context) GIOA,
|
||||||
|
GIOA ~func() A,
|
||||||
|
|
||||||
|
A any](ma GRIOA) GRIOEA {
|
||||||
|
return RIE.RightReaderIO[GRIOEA](ma)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LeftReaderIO[
|
||||||
|
GRIOEA ~func(context.Context) GIOEA,
|
||||||
|
GIOEA ~func() E.Either[error, A],
|
||||||
|
|
||||||
|
GRIOE ~func(context.Context) GIOE,
|
||||||
|
GIOE ~func() error,
|
||||||
|
|
||||||
|
A any](ma GRIOE) GRIOEA {
|
||||||
|
return RIE.LeftReaderIO[GRIOEA](ma)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadFlap[GREAB ~func(context.Context) GEAB, GREB ~func(context.Context) GEB, GEAB ~func() E.Either[error, func(A) B], GEB ~func() E.Either[error, B], B, A any](fab GREAB, a A) GREB {
|
||||||
|
return RIE.MonadFlap[GREAB, GREB](fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[GREAB ~func(context.Context) GEAB, GREB ~func(context.Context) GEB, GEAB ~func() E.Either[error, func(A) B], GEB ~func() E.Either[error, B], B, A any](a A) func(GREAB) GREB {
|
||||||
|
return RIE.Flap[GREAB, GREB](a)
|
||||||
|
}
|
||||||
|
29
context/readerioeither/generic/semigroup.go
Normal file
29
context/readerioeither/generic/semigroup.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// 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 (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AltSemigroup[GRA ~func(context.Context) GIOA, GIOA ~func() ET.Either[error, A], A any]() S.Semigroup[GRA] {
|
||||||
|
return S.AltSemigroup(
|
||||||
|
MonadAlt[func() GRA],
|
||||||
|
)
|
||||||
|
}
|
@@ -62,6 +62,25 @@ func TraverseArray[
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[
|
||||||
|
AS ~[]A,
|
||||||
|
GRBS ~func(context.Context) GIOBS,
|
||||||
|
GRB ~func(context.Context) GIOB,
|
||||||
|
GIOBS ~func() E.Either[error, BS],
|
||||||
|
GIOB ~func() E.Either[error, B],
|
||||||
|
BS ~[]B,
|
||||||
|
A, B any](f func(int, A) GRB) func(AS) GRBS {
|
||||||
|
|
||||||
|
return RA.TraverseWithIndex[AS](
|
||||||
|
Of[GRBS, GIOBS, BS],
|
||||||
|
Map[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GIOBS, func() E.Either[error, func(B) BS], BS, func(B) BS],
|
||||||
|
Ap[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||||
|
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[
|
func SequenceArray[
|
||||||
AS ~[]A,
|
AS ~[]A,
|
||||||
@@ -115,6 +134,26 @@ func TraverseRecord[K comparable,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndex transforms a record
|
||||||
|
func TraverseRecordWithIndex[K comparable,
|
||||||
|
AS ~map[K]A,
|
||||||
|
GRBS ~func(context.Context) GIOBS,
|
||||||
|
GRB ~func(context.Context) GIOB,
|
||||||
|
GIOBS ~func() E.Either[error, BS],
|
||||||
|
GIOB ~func() E.Either[error, B],
|
||||||
|
BS ~map[K]B,
|
||||||
|
|
||||||
|
A, B any](f func(K, A) GRB) func(AS) GRBS {
|
||||||
|
|
||||||
|
return RR.TraverseWithIndex[AS](
|
||||||
|
Of[GRBS, GIOBS, BS],
|
||||||
|
Map[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GIOBS, func() E.Either[error, func(B) BS], BS, func(B) BS],
|
||||||
|
Ap[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||||
|
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceRecord[K comparable,
|
func SequenceRecord[K comparable,
|
||||||
AS ~map[K]A,
|
AS ~map[K]A,
|
||||||
|
56
context/readerioeither/monoid.go
Normal file
56
context/readerioeither/monoid.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// 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 readerioeither
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApplicativeMonoid returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
|
||||||
|
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
|
||||||
|
return G.ApplicativeMonoid[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicativeMonoidSeq returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
|
||||||
|
func ApplicativeMonoidSeq[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
|
||||||
|
return G.ApplicativeMonoidSeq[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicativeMonoidPar returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
|
||||||
|
func ApplicativeMonoidPar[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
|
||||||
|
return G.ApplicativeMonoidPar[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlternativeMonoid is the alternative [Monoid] for [ReaderIOEither]
|
||||||
|
func AlternativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
|
||||||
|
return M.AlternativeMonoid(
|
||||||
|
Of[A],
|
||||||
|
MonadMap[A, func(A) A],
|
||||||
|
MonadAp[A, A],
|
||||||
|
MonadAlt[A],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AltMonoid is the alternative [Monoid] for an [ReaderIOEither]
|
||||||
|
func AltMonoid[A any](zero L.Lazy[ReaderIOEither[A]]) M.Monoid[ReaderIOEither[A]] {
|
||||||
|
return M.AltMonoid(
|
||||||
|
zero,
|
||||||
|
MonadAlt[A],
|
||||||
|
)
|
||||||
|
}
|
@@ -25,6 +25,7 @@ import (
|
|||||||
ET "github.com/IBM/fp-go/either"
|
ET "github.com/IBM/fp-go/either"
|
||||||
IO "github.com/IBM/fp-go/io"
|
IO "github.com/IBM/fp-go/io"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,6 +61,14 @@ func Map[A, B any](f func(A) B) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
|||||||
return G.Map[ReaderIOEither[A], ReaderIOEither[B]](f)
|
return G.Map[ReaderIOEither[A], ReaderIOEither[B]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadMapTo[A, B any](fa ReaderIOEither[A], b B) ReaderIOEither[B] {
|
||||||
|
return G.MonadMapTo[ReaderIOEither[A], ReaderIOEither[B]](fa, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MapTo[A, B any](b B) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
||||||
|
return G.MapTo[ReaderIOEither[A], ReaderIOEither[B]](b)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadChain[A, B any](ma ReaderIOEither[A], f func(A) ReaderIOEither[B]) ReaderIOEither[B] {
|
func MonadChain[A, B any](ma ReaderIOEither[A], f func(A) ReaderIOEither[B]) ReaderIOEither[B] {
|
||||||
return G.MonadChain(ma, f)
|
return G.MonadChain(ma, f)
|
||||||
}
|
}
|
||||||
@@ -146,11 +155,23 @@ func FromIO[A any](t IO.IO[A]) ReaderIOEither[A] {
|
|||||||
return G.FromIO[ReaderIOEither[A]](t)
|
return G.FromIO[ReaderIOEither[A]](t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FromLazy[A any](t L.Lazy[A]) ReaderIOEither[A] {
|
||||||
|
return G.FromIO[ReaderIOEither[A]](t)
|
||||||
|
}
|
||||||
|
|
||||||
// Never returns a 'ReaderIOEither' that never returns, except if its context gets canceled
|
// Never returns a 'ReaderIOEither' that never returns, except if its context gets canceled
|
||||||
func Never[A any]() ReaderIOEither[A] {
|
func Never[A any]() ReaderIOEither[A] {
|
||||||
return G.Never[ReaderIOEither[A]]()
|
return G.Never[ReaderIOEither[A]]()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadChainReaderIOK[A, B any](ma ReaderIOEither[A], f func(A) RIO.ReaderIO[B]) ReaderIOEither[B] {
|
||||||
|
return G.MonadChainReaderIOK[ReaderIOEither[B], ReaderIOEither[A]](ma, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChainReaderIOK[A, B any](f func(A) RIO.ReaderIO[B]) func(ma ReaderIOEither[A]) ReaderIOEither[B] {
|
||||||
|
return G.ChainReaderIOK[ReaderIOEither[B], ReaderIOEither[A]](f)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadChainIOK[A, B any](ma ReaderIOEither[A], f func(A) IO.IO[B]) ReaderIOEither[B] {
|
func MonadChainIOK[A, B any](ma ReaderIOEither[A], f func(A) IO.IO[B]) ReaderIOEither[B] {
|
||||||
return G.MonadChainIOK[ReaderIOEither[B], ReaderIOEither[A]](ma, f)
|
return G.MonadChainIOK[ReaderIOEither[B], ReaderIOEither[A]](ma, f)
|
||||||
}
|
}
|
||||||
@@ -182,7 +203,7 @@ func Timer(delay time.Duration) ReaderIOEither[time.Time] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||||
func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] {
|
func Defer[A any](gen L.Lazy[ReaderIOEither[A]]) ReaderIOEither[A] {
|
||||||
return G.Defer[ReaderIOEither[A]](gen)
|
return G.Defer[ReaderIOEither[A]](gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,3 +211,50 @@ func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] {
|
|||||||
func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] {
|
func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] {
|
||||||
return G.TryCatch[ReaderIOEither[A]](f)
|
return G.TryCatch[ReaderIOEither[A]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonadAlt identifies an associative operation on a type constructor
|
||||||
|
func MonadAlt[A any](first ReaderIOEither[A], second L.Lazy[ReaderIOEither[A]]) ReaderIOEither[A] {
|
||||||
|
return G.MonadAlt(first, second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alt identifies an associative operation on a type constructor
|
||||||
|
func Alt[A any](second L.Lazy[ReaderIOEither[A]]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||||
|
return G.Alt(second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memoize computes the value of the provided [ReaderIOEither] monad lazily but exactly once
|
||||||
|
// The context used to compute the value is the context of the first call, so do not use this
|
||||||
|
// method if the value has a functional dependency on the content of the context
|
||||||
|
func Memoize[A any](rdr ReaderIOEither[A]) ReaderIOEither[A] {
|
||||||
|
return G.Memoize[ReaderIOEither[A]](rdr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten converts a nested [ReaderIOEither] into a [ReaderIOEither]
|
||||||
|
func Flatten[
|
||||||
|
A any](rdr ReaderIOEither[ReaderIOEither[A]]) ReaderIOEither[A] {
|
||||||
|
return G.Flatten[ReaderIOEither[ReaderIOEither[A]]](rdr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadFromReaderIO[A any](a A, f func(A) RIO.ReaderIO[A]) ReaderIOEither[A] {
|
||||||
|
return G.MonadFromReaderIO[ReaderIOEither[A]](a, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromReaderIO[A any](f func(A) RIO.ReaderIO[A]) func(A) ReaderIOEither[A] {
|
||||||
|
return G.FromReaderIO[ReaderIOEither[A]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RightReaderIO[A any](ma RIO.ReaderIO[A]) ReaderIOEither[A] {
|
||||||
|
return G.RightReaderIO[ReaderIOEither[A]](ma)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LeftReaderIO[A any](ma RIO.ReaderIO[error]) ReaderIOEither[A] {
|
||||||
|
return G.LeftReaderIO[ReaderIOEither[A]](ma)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadFlap[B, A any](fab ReaderIOEither[func(A) B], a A) ReaderIOEither[B] {
|
||||||
|
return G.MonadFlap[ReaderIOEither[func(A) B], ReaderIOEither[B]](fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[B, A any](a A) func(ReaderIOEither[func(A) B]) ReaderIOEither[B] {
|
||||||
|
return G.Flap[ReaderIOEither[func(A) B], ReaderIOEither[B]](a)
|
||||||
|
}
|
||||||
|
@@ -162,3 +162,125 @@ func TestRegularApply(t *testing.T) {
|
|||||||
res := applied(context.Background())()
|
res := applied(context.Background())()
|
||||||
assert.Equal(t, E.Of[error]("CARSTEN"), res)
|
assert.Equal(t, E.Of[error]("CARSTEN"), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWithResourceNoErrors(t *testing.T) {
|
||||||
|
var countAcquire, countBody, countRelease int
|
||||||
|
|
||||||
|
acquire := FromLazy(func() int {
|
||||||
|
countAcquire++
|
||||||
|
return countAcquire
|
||||||
|
})
|
||||||
|
|
||||||
|
release := func(int) ReaderIOEither[int] {
|
||||||
|
return FromLazy(func() int {
|
||||||
|
countRelease++
|
||||||
|
return countRelease
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
body := func(int) ReaderIOEither[int] {
|
||||||
|
return FromLazy(func() int {
|
||||||
|
countBody++
|
||||||
|
return countBody
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resRIOE := WithResource[int](acquire, release)(body)
|
||||||
|
|
||||||
|
res := resRIOE(context.Background())()
|
||||||
|
|
||||||
|
assert.Equal(t, 1, countAcquire)
|
||||||
|
assert.Equal(t, 1, countBody)
|
||||||
|
assert.Equal(t, 1, countRelease)
|
||||||
|
assert.Equal(t, E.Of[error](1), res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithResourceErrorInBody(t *testing.T) {
|
||||||
|
var countAcquire, countBody, countRelease int
|
||||||
|
|
||||||
|
acquire := FromLazy(func() int {
|
||||||
|
countAcquire++
|
||||||
|
return countAcquire
|
||||||
|
})
|
||||||
|
|
||||||
|
release := func(int) ReaderIOEither[int] {
|
||||||
|
return FromLazy(func() int {
|
||||||
|
countRelease++
|
||||||
|
return countRelease
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err := fmt.Errorf("error in body")
|
||||||
|
body := func(int) ReaderIOEither[int] {
|
||||||
|
return Left[int](err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resRIOE := WithResource[int](acquire, release)(body)
|
||||||
|
|
||||||
|
res := resRIOE(context.Background())()
|
||||||
|
|
||||||
|
assert.Equal(t, 1, countAcquire)
|
||||||
|
assert.Equal(t, 0, countBody)
|
||||||
|
assert.Equal(t, 1, countRelease)
|
||||||
|
assert.Equal(t, E.Left[int](err), res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithResourceErrorInAcquire(t *testing.T) {
|
||||||
|
var countAcquire, countBody, countRelease int
|
||||||
|
|
||||||
|
err := fmt.Errorf("error in acquire")
|
||||||
|
acquire := Left[int](err)
|
||||||
|
|
||||||
|
release := func(int) ReaderIOEither[int] {
|
||||||
|
return FromLazy(func() int {
|
||||||
|
countRelease++
|
||||||
|
return countRelease
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
body := func(int) ReaderIOEither[int] {
|
||||||
|
return FromLazy(func() int {
|
||||||
|
countBody++
|
||||||
|
return countBody
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resRIOE := WithResource[int](acquire, release)(body)
|
||||||
|
|
||||||
|
res := resRIOE(context.Background())()
|
||||||
|
|
||||||
|
assert.Equal(t, 0, countAcquire)
|
||||||
|
assert.Equal(t, 0, countBody)
|
||||||
|
assert.Equal(t, 0, countRelease)
|
||||||
|
assert.Equal(t, E.Left[int](err), res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithResourceErrorInRelease(t *testing.T) {
|
||||||
|
var countAcquire, countBody, countRelease int
|
||||||
|
|
||||||
|
acquire := FromLazy(func() int {
|
||||||
|
countAcquire++
|
||||||
|
return countAcquire
|
||||||
|
})
|
||||||
|
|
||||||
|
err := fmt.Errorf("error in release")
|
||||||
|
release := func(int) ReaderIOEither[int] {
|
||||||
|
return Left[int](err)
|
||||||
|
}
|
||||||
|
|
||||||
|
body := func(int) ReaderIOEither[int] {
|
||||||
|
return FromLazy(func() int {
|
||||||
|
countBody++
|
||||||
|
return countBody
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resRIOE := WithResource[int](acquire, release)(body)
|
||||||
|
|
||||||
|
res := resRIOE(context.Background())()
|
||||||
|
|
||||||
|
assert.Equal(t, 1, countAcquire)
|
||||||
|
assert.Equal(t, 1, countBody)
|
||||||
|
assert.Equal(t, 0, countRelease)
|
||||||
|
assert.Equal(t, E.Left[int](err), res)
|
||||||
|
}
|
||||||
|
26
context/readerioeither/semigroup.go
Normal file
26
context/readerioeither/semigroup.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// 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 readerioeither
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AltSemigroup is a [Semigroup] that tries the first item and then the second one using an alternative
|
||||||
|
func AltSemigroup[A any]() S.Semigroup[ReaderIOEither[A]] {
|
||||||
|
return G.AltSemigroup[ReaderIOEither[A]]()
|
||||||
|
}
|
@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) ReaderIOEither[B]) func([]A) ReaderIOEith
|
|||||||
return G.TraverseArray[[]A, ReaderIOEither[[]B]](f)
|
return G.TraverseArray[[]A, ReaderIOEither[[]B]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex uses transforms an array [[]A] into [[]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[[]B]]
|
||||||
|
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
|
||||||
|
return G.TraverseArrayWithIndex[[]A, ReaderIOEither[[]B]](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
|
func SequenceArray[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
|
||||||
return G.SequenceArray[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma)
|
return G.SequenceArray[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma)
|
||||||
@@ -34,6 +39,11 @@ func TraverseRecord[K comparable, A, B any](f func(A) ReaderIOEither[B]) func(ma
|
|||||||
return G.TraverseRecord[K, map[K]A, ReaderIOEither[map[K]B]](f)
|
return G.TraverseRecord[K, map[K]A, ReaderIOEither[map[K]B]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndex uses transforms a record [map[K]A] into [map[K]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[map[K]B]]
|
||||||
|
func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
|
||||||
|
return G.TraverseRecordWithIndex[K, map[K]A, ReaderIOEither[map[K]B]](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceRecord[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] {
|
func SequenceRecord[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] {
|
||||||
return G.SequenceRecord[K, map[K]A, map[K]ReaderIOEither[A], ReaderIOEither[map[K]A]](ma)
|
return G.SequenceRecord[K, map[K]A, map[K]ReaderIOEither[A], ReaderIOEither[map[K]A]](ma)
|
||||||
|
2
coverage.bat
Normal file
2
coverage.bat
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@echo off
|
||||||
|
go tool cover -html=build/cover.out -o build/cover.html
|
@@ -24,6 +24,7 @@ func ApplySemigroup[E, A any](s S.Semigroup[A]) S.Semigroup[Either[E, A]] {
|
|||||||
return S.ApplySemigroup(MonadMap[E, A, func(A) A], MonadAp[A, E, A], s)
|
return S.ApplySemigroup(MonadMap[E, A, func(A) A], MonadAp[A, E, A], s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplicativeMonoid returns a [Monoid] that concatenates [Either] instances via their applicative
|
||||||
func ApplicativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
|
func ApplicativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
|
||||||
return M.ApplicativeMonoid(Of[E, A], MonadMap[E, A, func(A) A], MonadAp[A, E, A], m)
|
return M.ApplicativeMonoid(Of[E, A], MonadMap[E, A, func(A) A], MonadAp[A, E, A], m)
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@ import (
|
|||||||
RA "github.com/IBM/fp-go/internal/array"
|
RA "github.com/IBM/fp-go/internal/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TraverseArray transforms an array
|
// TraverseArrayG transforms an array
|
||||||
func TraverseArrayG[GA ~[]A, GB ~[]B, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
|
func TraverseArrayG[GA ~[]A, GB ~[]B, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
|
||||||
return RA.Traverse[GA](
|
return RA.Traverse[GA](
|
||||||
Of[E, GB],
|
Of[E, GB],
|
||||||
@@ -36,6 +36,22 @@ func TraverseArray[E, A, B any](f func(A) Either[E, B]) func([]A) Either[E, []B]
|
|||||||
return TraverseArrayG[[]A, []B](f)
|
return TraverseArrayG[[]A, []B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndexG transforms an array
|
||||||
|
func TraverseArrayWithIndexG[GA ~[]A, GB ~[]B, E, A, B any](f func(int, A) Either[E, B]) func(GA) Either[E, GB] {
|
||||||
|
return RA.TraverseWithIndex[GA](
|
||||||
|
Of[E, GB],
|
||||||
|
Map[E, GB, func(B) GB],
|
||||||
|
Ap[GB, E, B],
|
||||||
|
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[E, A, B any](f func(int, A) Either[E, B]) func([]A) Either[E, []B] {
|
||||||
|
return TraverseArrayWithIndexG[[]A, []B](f)
|
||||||
|
}
|
||||||
|
|
||||||
func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA] {
|
func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA] {
|
||||||
return TraverseArrayG[GOA, GA](F.Identity[Either[E, A]])(ma)
|
return TraverseArrayG[GOA, GA](F.Identity[Either[E, A]])(ma)
|
||||||
}
|
}
|
||||||
@@ -44,3 +60,15 @@ func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA
|
|||||||
func SequenceArray[E, A any](ma []Either[E, A]) Either[E, []A] {
|
func SequenceArray[E, A any](ma []Either[E, A]) Either[E, []A] {
|
||||||
return SequenceArrayG[[]A](ma)
|
return SequenceArrayG[[]A](ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CompactArrayG discards the none values and keeps the some values
|
||||||
|
func CompactArrayG[A1 ~[]Either[E, A], A2 ~[]A, E, A any](fa A1) A2 {
|
||||||
|
return RA.Reduce(fa, func(out A2, value Either[E, A]) A2 {
|
||||||
|
return MonadFold(value, F.Constant1[E](out), F.Bind1st(RA.Append[A2, A], out))
|
||||||
|
}, make(A2, len(fa)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompactArray discards the none values and keeps the some values
|
||||||
|
func CompactArray[E, A any](fa []Either[E, A]) []A {
|
||||||
|
return CompactArrayG[[]Either[E, A], []A](fa)
|
||||||
|
}
|
||||||
|
@@ -22,6 +22,8 @@ package either
|
|||||||
import (
|
import (
|
||||||
E "github.com/IBM/fp-go/errors"
|
E "github.com/IBM/fp-go/errors"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,12 +93,12 @@ func MonadChainTo[E, A, B any](ma Either[E, A], mb Either[E, B]) Either[E, B] {
|
|||||||
return mb
|
return mb
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainOptionK[E, A, B any](onNone func() E, ma Either[E, A], f func(A) O.Option[B]) Either[E, B] {
|
func MonadChainOptionK[A, B, E any](onNone func() E, ma Either[E, A], f func(A) O.Option[B]) Either[E, B] {
|
||||||
return MonadChain(ma, F.Flow2(f, FromOption[E, B](onNone)))
|
return MonadChain(ma, F.Flow2(f, FromOption[B](onNone)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChainOptionK[E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
|
func ChainOptionK[A, B, E any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
|
||||||
from := FromOption[E, B](onNone)
|
from := FromOption[B](onNone)
|
||||||
return func(f func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
|
return func(f func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
|
||||||
return Chain(F.Flow2(f, from))
|
return Chain(F.Flow2(f, from))
|
||||||
}
|
}
|
||||||
@@ -142,7 +144,7 @@ func Sequence3[E, T1, T2, T3, R any](f func(T1, T2, T3) Either[E, R]) func(Eithe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromOption[E, A any](onNone func() E) func(O.Option[A]) Either[E, A] {
|
func FromOption[A, E any](onNone func() E) func(O.Option[A]) Either[E, A] {
|
||||||
return O.Fold(F.Nullary2(onNone, Left[A, E]), Right[E, A])
|
return O.Fold(F.Nullary2(onNone, Left[A, E]), Right[E, A])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,11 +199,11 @@ func Reduce[E, A, B any](f func(B, A) B, initial B) func(Either[E, A]) B {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AltW[E, E1, A any](that func() Either[E1, A]) func(Either[E, A]) Either[E1, A] {
|
func AltW[E, E1, A any](that L.Lazy[Either[E1, A]]) func(Either[E, A]) Either[E1, A] {
|
||||||
return Fold(F.Ignore1of1[E](that), Right[E1, A])
|
return Fold(F.Ignore1of1[E](that), Right[E1, A])
|
||||||
}
|
}
|
||||||
|
|
||||||
func Alt[E, A any](that func() Either[E, A]) func(Either[E, A]) Either[E, A] {
|
func Alt[E, A any](that L.Lazy[Either[E, A]]) func(Either[E, A]) Either[E, A] {
|
||||||
return AltW[E](that)
|
return AltW[E](that)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +211,7 @@ func OrElse[E, A any](onLeft func(e E) Either[E, A]) func(Either[E, A]) Either[E
|
|||||||
return Fold(onLeft, Of[E, A])
|
return Fold(onLeft, Of[E, A])
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToType[E, A any](onError func(any) E) func(any) Either[E, A] {
|
func ToType[A, E any](onError func(any) E) func(any) Either[E, A] {
|
||||||
return func(value any) Either[E, A] {
|
return func(value any) Either[E, A] {
|
||||||
return F.Pipe2(
|
return F.Pipe2(
|
||||||
value,
|
value,
|
||||||
@@ -245,3 +247,15 @@ func MonadSequence3[E, T1, T2, T3, R any](e1 Either[E, T1], e2 Either[E, T2], e3
|
|||||||
func Swap[E, A any](val Either[E, A]) Either[A, E] {
|
func Swap[E, A any](val Either[E, A]) Either[A, E] {
|
||||||
return MonadFold(val, Right[A, E], Left[E, A])
|
return MonadFold(val, Right[A, E], Left[E, A])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFlap[E, B, A any](fab Either[E, func(A) B], a A) Either[E, B] {
|
||||||
|
return FC.MonadFlap(MonadMap[E, func(A) B, B], fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[E, B, A any](a A) func(Either[E, func(A) B]) Either[E, B] {
|
||||||
|
return F.Bind2nd(MonadFlap[E, B, A], a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] {
|
||||||
|
return MonadFold(fa, F.Ignore1of1[E](that), Of[E, A])
|
||||||
|
}
|
||||||
|
@@ -100,7 +100,7 @@ func TestChainFirst(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestChainOptionK(t *testing.T) {
|
func TestChainOptionK(t *testing.T) {
|
||||||
f := ChainOptionK[string, int, int](F.Constant("a"))(func(n int) O.Option[int] {
|
f := ChainOptionK[int, int](F.Constant("a"))(func(n int) O.Option[int] {
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
return O.Some(n)
|
return O.Some(n)
|
||||||
}
|
}
|
||||||
@@ -112,6 +112,6 @@ func TestChainOptionK(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFromOption(t *testing.T) {
|
func TestFromOption(t *testing.T) {
|
||||||
assert.Equal(t, Left[int]("none"), FromOption[string, int](F.Constant("none"))(O.None[int]()))
|
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
|
||||||
assert.Equal(t, Right[string](1), FromOption[string, int](F.Constant("none"))(O.Some(1)))
|
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
// Command executes a command
|
// Command executes a command
|
||||||
// use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input
|
// use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input
|
||||||
// typically you'd rather use the IOEither version of the command
|
// typically you'd rather use the [IOEither] version of the command
|
||||||
Command = F.Curry3(command)
|
Command = F.Curry3(command)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:58:57.9925506 +0200 CEST m=+0.033401101
|
// 2023-09-12 13:44:15.6356542 +0200 CEST m=+0.009418901
|
||||||
|
|
||||||
package either
|
package either
|
||||||
|
|
||||||
|
40
either/monoid.go
Normal file
40
either/monoid.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// 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 either
|
||||||
|
|
||||||
|
import (
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AlternativeMonoid is the alternative [Monoid] for an [Either]
|
||||||
|
func AlternativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
|
||||||
|
return M.AlternativeMonoid(
|
||||||
|
Of[E, A],
|
||||||
|
MonadMap[E, A, func(A) A],
|
||||||
|
MonadAp[A, E, A],
|
||||||
|
MonadAlt[E, A],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AltMonoid is the alternative [Monoid] for an [Either]
|
||||||
|
func AltMonoid[E, A any](zero L.Lazy[Either[E, A]]) M.Monoid[Either[E, A]] {
|
||||||
|
return M.AltMonoid(
|
||||||
|
zero,
|
||||||
|
MonadAlt[E, A],
|
||||||
|
)
|
||||||
|
}
|
@@ -20,7 +20,7 @@ import (
|
|||||||
RR "github.com/IBM/fp-go/internal/record"
|
RR "github.com/IBM/fp-go/internal/record"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TraverseRecord transforms a record of options into an option of a record
|
// TraverseRecordG transforms a record of options into an option of a record
|
||||||
func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
|
func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
|
||||||
return RR.Traverse[GA](
|
return RR.Traverse[GA](
|
||||||
Of[E, GB],
|
Of[E, GB],
|
||||||
@@ -35,6 +35,21 @@ func TraverseRecord[K comparable, E, A, B any](f func(A) Either[E, B]) func(map[
|
|||||||
return TraverseRecordG[map[K]A, map[K]B](f)
|
return TraverseRecordG[map[K]A, map[K]B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndexG transforms a record of options into an option of a record
|
||||||
|
func TraverseRecordWithIndexG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(K, A) Either[E, B]) func(GA) Either[E, GB] {
|
||||||
|
return RR.TraverseWithIndex[GA](
|
||||||
|
Of[E, GB],
|
||||||
|
Map[E, GB, func(B) GB],
|
||||||
|
Ap[GB, E, B],
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndex transforms a record of eithers into an either of a record
|
||||||
|
func TraverseRecordWithIndex[K comparable, E, A, B any](f func(K, A) Either[E, B]) func(map[K]A) Either[E, map[K]B] {
|
||||||
|
return TraverseRecordWithIndexG[map[K]A, map[K]B](f)
|
||||||
|
}
|
||||||
|
|
||||||
func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A any](ma GOA) Either[E, GA] {
|
func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A any](ma GOA) Either[E, GA] {
|
||||||
return TraverseRecordG[GOA, GA](F.Identity[Either[E, A]])(ma)
|
return TraverseRecordG[GOA, GA](F.Identity[Either[E, A]])(ma)
|
||||||
}
|
}
|
||||||
@@ -43,3 +58,24 @@ func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A an
|
|||||||
func SequenceRecord[K comparable, E, A any](ma map[K]Either[E, A]) Either[E, map[K]A] {
|
func SequenceRecord[K comparable, E, A any](ma map[K]Either[E, A]) Either[E, map[K]A] {
|
||||||
return SequenceRecordG[map[K]A](ma)
|
return SequenceRecordG[map[K]A](ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func upsertAtReadWrite[M ~map[K]V, K comparable, V any](r M, k K, v V) M {
|
||||||
|
r[k] = v
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompactRecordG discards the noe values and keeps the some values
|
||||||
|
func CompactRecordG[M1 ~map[K]Either[E, A], M2 ~map[K]A, K comparable, E, A any](m M1) M2 {
|
||||||
|
out := make(M2)
|
||||||
|
onLeft := F.Constant1[E](out)
|
||||||
|
return RR.ReduceWithIndex(m, func(key K, _ M2, value Either[E, A]) M2 {
|
||||||
|
return MonadFold(value, onLeft, func(v A) M2 {
|
||||||
|
return upsertAtReadWrite(out, key, v)
|
||||||
|
})
|
||||||
|
}, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompactRecord discards all none values and keeps the somes
|
||||||
|
func CompactRecord[K comparable, E, A any](m map[K]Either[E, A]) map[K]A {
|
||||||
|
return CompactRecordG[map[K]Either[E, A], map[K]A](m)
|
||||||
|
}
|
||||||
|
37
either/record_test.go
Normal file
37
either/record_test.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 either
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompactRecord(t *testing.T) {
|
||||||
|
// make the map
|
||||||
|
m := make(map[string]Either[string, int])
|
||||||
|
m["foo"] = Left[int]("error")
|
||||||
|
m["bar"] = Right[string](1)
|
||||||
|
// compact it
|
||||||
|
m1 := CompactRecord(m)
|
||||||
|
// check expected
|
||||||
|
exp := map[string]int{
|
||||||
|
"bar": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, exp, m1)
|
||||||
|
}
|
@@ -13,17 +13,15 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package file
|
package either
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// onClose closes a closeable resource
|
// AltSemigroup is the alternative [Semigroup] for an [Either]
|
||||||
func onClose[R io.Closer](r R) IOE.IOEither[error, R] {
|
func AltSemigroup[E, A any]() S.Semigroup[Either[E, A]] {
|
||||||
return IOE.TryCatchError(func() (R, error) {
|
return S.AltSemigroup(
|
||||||
return r, r.Close()
|
MonadAlt[E, A],
|
||||||
})
|
)
|
||||||
}
|
}
|
@@ -27,13 +27,13 @@ HKTRB = HKT<Either[B]>
|
|||||||
HKTA = HKT<A>
|
HKTA = HKT<A>
|
||||||
HKTB = HKT<B>
|
HKTB = HKT<B>
|
||||||
*/
|
*/
|
||||||
func traverse[E, A, B, HKTA, HKTB, HKTRB any](
|
func traverse[E, A, B, HKTB, HKTRB any](
|
||||||
_of func(Either[E, B]) HKTRB,
|
mof func(Either[E, B]) HKTRB,
|
||||||
_map func(HKTB, func(B) Either[E, B]) HKTRB,
|
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
|
||||||
) func(Either[E, A], func(A) HKTB) HKTRB {
|
) func(Either[E, A], func(A) HKTB) HKTRB {
|
||||||
|
|
||||||
left := F.Flow2(Left[B, E], _of)
|
left := F.Flow2(Left[B, E], mof)
|
||||||
right := F.Bind2nd(_map, Right[E, B])
|
right := mmap(Right[E, B])
|
||||||
|
|
||||||
return func(ta Either[E, A], f func(A) HKTB) HKTRB {
|
return func(ta Either[E, A], f func(A) HKTB) HKTRB {
|
||||||
return MonadFold(ta,
|
return MonadFold(ta,
|
||||||
@@ -43,27 +43,21 @@ func traverse[E, A, B, HKTA, HKTB, HKTRB any](
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Traverse[E, A, B, HKTA, HKTB, HKTRB any](
|
// Traverse converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
|
||||||
_of func(Either[E, B]) HKTRB,
|
func Traverse[A, E, B, HKTB, HKTRB any](
|
||||||
_map func(HKTB, func(B) Either[E, B]) HKTRB,
|
mof func(Either[E, B]) HKTRB,
|
||||||
|
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
|
||||||
) func(func(A) HKTB) func(Either[E, A]) HKTRB {
|
) func(func(A) HKTB) func(Either[E, A]) HKTRB {
|
||||||
delegate := traverse[E, A, B, HKTA](_of, _map)
|
delegate := traverse[E, A, B](mof, mmap)
|
||||||
return func(f func(A) HKTB) func(Either[E, A]) HKTRB {
|
return func(f func(A) HKTB) func(Either[E, A]) HKTRB {
|
||||||
return F.Bind2nd(delegate, f)
|
return F.Bind2nd(delegate, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Sequence converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
|
||||||
*
|
|
||||||
We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
|
|
||||||
|
|
||||||
HKTRA = HKT<Either[A]>
|
|
||||||
HKTA = HKT<A>
|
|
||||||
HKTB = HKT<B>
|
|
||||||
*/
|
|
||||||
func Sequence[E, A, HKTA, HKTRA any](
|
func Sequence[E, A, HKTA, HKTRA any](
|
||||||
_of func(Either[E, A]) HKTRA,
|
mof func(Either[E, A]) HKTRA,
|
||||||
_map func(HKTA, func(A) Either[E, A]) HKTRA,
|
mmap func(func(A) Either[E, A]) func(HKTA) HKTRA,
|
||||||
) func(Either[E, HKTA]) HKTRA {
|
) func(Either[E, HKTA]) HKTRA {
|
||||||
return Fold(F.Flow2(Left[A, E], _of), F.Bind2nd(_map, Right[E, A]))
|
return Fold(F.Flow2(Left[A, E], mof), mmap(Right[E, A]))
|
||||||
}
|
}
|
||||||
|
@@ -30,9 +30,9 @@ func TestTraverse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return O.None[int]()
|
return O.None[int]()
|
||||||
}
|
}
|
||||||
trav := Traverse[string, int, int, O.Option[Either[string, int]]](
|
trav := Traverse[int](
|
||||||
O.Of[Either[string, int]],
|
O.Of[Either[string, int]],
|
||||||
O.MonadMap[int, Either[string, int]],
|
O.Map[int, Either[string, int]],
|
||||||
)(f)
|
)(f)
|
||||||
|
|
||||||
assert.Equal(t, O.Of(Left[int]("a")), F.Pipe1(Left[int]("a"), trav))
|
assert.Equal(t, O.Of(Left[int]("a")), F.Pipe1(Left[int]("a"), trav))
|
||||||
@@ -44,7 +44,7 @@ func TestSequence(t *testing.T) {
|
|||||||
|
|
||||||
seq := Sequence(
|
seq := Sequence(
|
||||||
O.Of[Either[string, int]],
|
O.Of[Either[string, int]],
|
||||||
O.MonadMap[int, Either[string, int]],
|
O.Map[int, Either[string, int]],
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, O.Of(Right[string](1)), seq(Right[string](O.Of(1))))
|
assert.Equal(t, O.Of(Right[string](1)), seq(Right[string](O.Of(1))))
|
||||||
|
@@ -20,11 +20,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// command output
|
// 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 = T.Tuple2[[]byte, []byte]
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// StdOut returns the field of a [CommandOutput] representing `stdout`
|
||||||
StdOut = T.First[[]byte, []byte]
|
StdOut = T.First[[]byte, []byte]
|
||||||
|
// StdErr returns the field of a [CommandOutput] representing `stderr`
|
||||||
StdErr = T.Second[[]byte, []byte]
|
StdErr = T.Second[[]byte, []byte]
|
||||||
)
|
)
|
||||||
|
@@ -15,9 +15,11 @@
|
|||||||
|
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import "os"
|
import "path/filepath"
|
||||||
|
|
||||||
// GetName is the getter for the `Name` property of [os.File]
|
// Join appends a filename to a root path
|
||||||
func GetName(f *os.File) string {
|
func Join(name string) func(root string) string {
|
||||||
return f.Name()
|
return func(root string) string {
|
||||||
|
return filepath.Join(root, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@ func Bind2nd[T1, T2, R any](f func(T1, T2) R, t2 T2) func(T1) R {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SK function (SKI combinator calculus).
|
||||||
func SK[T1, T2 any](_ T1, t2 T2) T2 {
|
func SK[T1, T2 any](_ T1, t2 T2) T2 {
|
||||||
return t2
|
return t2
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:01.9404821 +0200 CEST m=+0.161366801
|
// 2023-09-12 13:44:23.4226437 +0200 CEST m=+0.011841001
|
||||||
|
|
||||||
package function
|
package function
|
||||||
|
|
||||||
|
@@ -19,12 +19,12 @@ import (
|
|||||||
G "github.com/IBM/fp-go/function/generic"
|
G "github.com/IBM/fp-go/function/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cache converts a unary function into a unary function that caches the value depending on the parameter
|
// Memoize converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func Cache[K comparable, T any](f func(K) T) func(K) T {
|
func Memoize[K comparable, T any](f func(K) T) func(K) T {
|
||||||
return G.Cache(f)
|
return G.Memoize(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter
|
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func ContramapCache[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
|
func ContramapMemoize[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
|
||||||
return G.ContramapCache[func(A) T](kf)
|
return G.ContramapMemoize[func(A) T](kf)
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,7 @@ func TestCache(t *testing.T) {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
cached := Cache(withSideEffect)
|
cached := Memoize(withSideEffect)
|
||||||
|
|
||||||
assert.Equal(t, 0, count)
|
assert.Equal(t, 0, count)
|
||||||
|
|
||||||
|
@@ -62,6 +62,7 @@ func First[T1, T2 any](t1 T1, _ T2) T1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Second returns the second out of two input values
|
// Second returns the second out of two input values
|
||||||
|
// Identical to [SK]
|
||||||
func Second[T1, T2 any](_ T1, t2 T2) T2 {
|
func Second[T1, T2 any](_ T1, t2 T2) T2 {
|
||||||
return t2
|
return t2
|
||||||
}
|
}
|
||||||
|
149
function/gen.go
149
function/gen.go
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:58:59.8663985 +0200 CEST m=+0.103744101
|
// 2023-09-12 13:44:17.0002767 +0200 CEST m=+0.008233101
|
||||||
|
|
||||||
package function
|
package function
|
||||||
|
|
||||||
@@ -24,6 +24,13 @@ func Unvariadic0[V, R any](f func(...V) R) func([]V) R {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced0 converts a function taking a slice parameter into a function with 0 parameters
|
||||||
|
func Unsliced0[F ~func([]T) R, T, R any](f F) func() R {
|
||||||
|
return func() R {
|
||||||
|
return f([]T{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe1 takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
|
// Pipe1 takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe1[F1 ~func(T0) T1, T0, T1 any](t0 T0, f1 F1) T1 {
|
func Pipe1[F1 ~func(T0) T1, T0, T1 any](t0 T0, f1 F1) T1 {
|
||||||
@@ -76,6 +83,13 @@ func Unvariadic1[T1, V, R any](f func(T1, ...V) R) func(T1, []V) R {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced1 converts a function taking a slice parameter into a function with 1 parameters
|
||||||
|
func Unsliced1[F ~func([]T) R, T, R any](f F) func(T) R {
|
||||||
|
return func(t1 T) R {
|
||||||
|
return f([]T{t1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe2 takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
|
// Pipe2 takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe2[F1 ~func(T0) T1, F2 ~func(T1) T2, T0, T1, T2 any](t0 T0, f1 F1, f2 F2) T2 {
|
func Pipe2[F1 ~func(T0) T1, F2 ~func(T1) T2, T0, T1, T2 any](t0 T0, f1 F1, f2 F2) T2 {
|
||||||
@@ -131,6 +145,13 @@ func Unvariadic2[T1, T2, V, R any](f func(T1, T2, ...V) R) func(T1, T2, []V) R {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced2 converts a function taking a slice parameter into a function with 2 parameters
|
||||||
|
func Unsliced2[F ~func([]T) R, T, R any](f F) func(T, T) R {
|
||||||
|
return func(t1, t2 T) R {
|
||||||
|
return f([]T{t1, t2})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe3 takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
|
// Pipe3 takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe3[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T0, T1, T2, T3 any](t0 T0, f1 F1, f2 F2, f3 F3) T3 {
|
func Pipe3[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T0, T1, T2, T3 any](t0 T0, f1 F1, f2 F2, f3 F3) T3 {
|
||||||
@@ -189,6 +210,13 @@ func Unvariadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, ...V) R) func(T1, T2,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced3 converts a function taking a slice parameter into a function with 3 parameters
|
||||||
|
func Unsliced3[F ~func([]T) R, T, R any](f F) func(T, T, T) R {
|
||||||
|
return func(t1, t2, t3 T) R {
|
||||||
|
return f([]T{t1, t2, t3})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe4 takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
|
// Pipe4 takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe4[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, T0, T1, T2, T3, T4 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4) T4 {
|
func Pipe4[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, T0, T1, T2, T3, T4 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4) T4 {
|
||||||
@@ -250,6 +278,13 @@ func Unvariadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, ...V) R) func(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced4 converts a function taking a slice parameter into a function with 4 parameters
|
||||||
|
func Unsliced4[F ~func([]T) R, T, R any](f F) func(T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe5 takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
|
// Pipe5 takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe5[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, T0, T1, T2, T3, T4, T5 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) T5 {
|
func Pipe5[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, T0, T1, T2, T3, T4, T5 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) T5 {
|
||||||
@@ -314,6 +349,13 @@ func Unvariadic5[T1, T2, T3, T4, T5, V, R any](f func(T1, T2, T3, T4, T5, ...V)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced5 converts a function taking a slice parameter into a function with 5 parameters
|
||||||
|
func Unsliced5[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe6 takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
|
// Pipe6 takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe6[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) T6 {
|
func Pipe6[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) T6 {
|
||||||
@@ -381,6 +423,13 @@ func Unvariadic6[T1, T2, T3, T4, T5, T6, V, R any](f func(T1, T2, T3, T4, T5, T6
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced6 converts a function taking a slice parameter into a function with 6 parameters
|
||||||
|
func Unsliced6[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe7 takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
|
// Pipe7 takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe7[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) T7 {
|
func Pipe7[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) T7 {
|
||||||
@@ -451,6 +500,13 @@ func Unvariadic7[T1, T2, T3, T4, T5, T6, T7, V, R any](f func(T1, T2, T3, T4, T5
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced7 converts a function taking a slice parameter into a function with 7 parameters
|
||||||
|
func Unsliced7[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe8 takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
|
// Pipe8 takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe8[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) T8 {
|
func Pipe8[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) T8 {
|
||||||
@@ -524,6 +580,13 @@ func Unvariadic8[T1, T2, T3, T4, T5, T6, T7, T8, V, R any](f func(T1, T2, T3, T4
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced8 converts a function taking a slice parameter into a function with 8 parameters
|
||||||
|
func Unsliced8[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe9 takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
|
// Pipe9 takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe9[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) T9 {
|
func Pipe9[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) T9 {
|
||||||
@@ -600,6 +663,13 @@ func Unvariadic9[T1, T2, T3, T4, T5, T6, T7, T8, T9, V, R any](f func(T1, T2, T3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced9 converts a function taking a slice parameter into a function with 9 parameters
|
||||||
|
func Unsliced9[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe10 takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
|
// Pipe10 takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe10[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) T10 {
|
func Pipe10[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) T10 {
|
||||||
@@ -679,6 +749,13 @@ func Unvariadic10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, V, R any](f func(T1,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced10 converts a function taking a slice parameter into a function with 10 parameters
|
||||||
|
func Unsliced10[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe11 takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
|
// Pipe11 takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe11[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) T11 {
|
func Pipe11[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) T11 {
|
||||||
@@ -761,6 +838,13 @@ func Unvariadic11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, V, R any](f func
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced11 converts a function taking a slice parameter into a function with 11 parameters
|
||||||
|
func Unsliced11[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe12 takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
|
// Pipe12 takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe12[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) T12 {
|
func Pipe12[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) T12 {
|
||||||
@@ -846,6 +930,13 @@ func Unvariadic12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, V, R any](f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced12 converts a function taking a slice parameter into a function with 12 parameters
|
||||||
|
func Unsliced12[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe13 takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
|
// Pipe13 takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe13[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) T13 {
|
func Pipe13[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) T13 {
|
||||||
@@ -934,6 +1025,13 @@ func Unvariadic13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, V, R a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced13 converts a function taking a slice parameter into a function with 13 parameters
|
||||||
|
func Unsliced13[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe14 takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
|
// Pipe14 takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe14[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) T14 {
|
func Pipe14[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) T14 {
|
||||||
@@ -1025,6 +1123,13 @@ func Unvariadic14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, V
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced14 converts a function taking a slice parameter into a function with 14 parameters
|
||||||
|
func Unsliced14[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe15 takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
|
// Pipe15 takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe15[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) T15 {
|
func Pipe15[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) T15 {
|
||||||
@@ -1119,6 +1224,13 @@ func Unvariadic15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced15 converts a function taking a slice parameter into a function with 15 parameters
|
||||||
|
func Unsliced15[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe16 takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
|
// Pipe16 takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe16[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16) T16 {
|
func Pipe16[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16) T16 {
|
||||||
@@ -1216,6 +1328,13 @@ func Unvariadic16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced16 converts a function taking a slice parameter into a function with 16 parameters
|
||||||
|
func Unsliced16[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe17 takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
|
// Pipe17 takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe17[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17) T17 {
|
func Pipe17[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17) T17 {
|
||||||
@@ -1316,6 +1435,13 @@ func Unvariadic17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced17 converts a function taking a slice parameter into a function with 17 parameters
|
||||||
|
func Unsliced17[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe18 takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
|
// Pipe18 takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe18[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18) T18 {
|
func Pipe18[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18) T18 {
|
||||||
@@ -1419,6 +1545,13 @@ func Unvariadic18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced18 converts a function taking a slice parameter into a function with 18 parameters
|
||||||
|
func Unsliced18[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe19 takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
|
// Pipe19 takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe19[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19) T19 {
|
func Pipe19[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19) T19 {
|
||||||
@@ -1525,6 +1658,13 @@ func Unvariadic19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced19 converts a function taking a slice parameter into a function with 19 parameters
|
||||||
|
func Unsliced19[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pipe20 takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
|
// Pipe20 takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe20[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, F20 ~func(T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19, f20 F20) T20 {
|
func Pipe20[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, F20 ~func(T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19, f20 F20) T20 {
|
||||||
@@ -1633,3 +1773,10 @@ func Unvariadic20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
|
|||||||
return f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, v...)
|
return f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, v...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unsliced20 converts a function taking a slice parameter into a function with 20 parameters
|
||||||
|
func Unsliced20[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
|
||||||
|
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20 T) R {
|
||||||
|
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -21,13 +21,13 @@ import (
|
|||||||
L "github.com/IBM/fp-go/internal/lazy"
|
L "github.com/IBM/fp-go/internal/lazy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cache converts a unary function into a unary function that caches the value depending on the parameter
|
// Memoize converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func Cache[F ~func(K) T, K comparable, T any](f F) F {
|
func Memoize[F ~func(K) T, K comparable, T any](f F) F {
|
||||||
return ContramapCache[F](func(k K) K { return k })(f)
|
return ContramapMemoize[F](func(k K) K { return k })(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter
|
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func ContramapCache[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
|
func ContramapMemoize[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
|
||||||
return CacheCallback[F](kf, getOrCreate[K, T]())
|
return CacheCallback[F](kf, getOrCreate[K, T]())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
45
function/unvariadic_test.go
Normal file
45
function/unvariadic_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// 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 function
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fromLibrary(data ...string) string {
|
||||||
|
return strings.Join(data, "-")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnvariadic(t *testing.T) {
|
||||||
|
|
||||||
|
res := Pipe1(
|
||||||
|
[]string{"A", "B"},
|
||||||
|
Unvariadic0(fromLibrary),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, "A-B", res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVariadicArity(t *testing.T) {
|
||||||
|
|
||||||
|
f := Unsliced2(Unvariadic0(fromLibrary))
|
||||||
|
|
||||||
|
res := f("A", "B")
|
||||||
|
assert.Equal(t, "A-B", res)
|
||||||
|
}
|
@@ -57,7 +57,7 @@ var (
|
|||||||
GetHeader,
|
GetHeader,
|
||||||
R.Lookup[H.Header](HeaderContentType),
|
R.Lookup[H.Header](HeaderContentType),
|
||||||
O.Chain(A.First[string]),
|
O.Chain(A.First[string]),
|
||||||
E.FromOption[error, string](errors.OnNone("unable to access the [%s] header", HeaderContentType)),
|
E.FromOption[string](errors.OnNone("unable to access the [%s] header", HeaderContentType)),
|
||||||
E.ChainFirst(validateJsonContentTypeString),
|
E.ChainFirst(validateJsonContentTypeString),
|
||||||
)))
|
)))
|
||||||
)
|
)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:06.2987136 +0200 CEST m=+0.049156901
|
// 2023-09-12 13:44:24.9409324 +0200 CEST m=+0.008573601
|
||||||
|
|
||||||
package identity
|
package identity
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ package generic
|
|||||||
import (
|
import (
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
C "github.com/IBM/fp-go/internal/chain"
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MonadAp[GAB ~func(A) B, B, A any](fab GAB, fa A) B {
|
func MonadAp[GAB ~func(A) B, B, A any](fab GAB, fa A) B {
|
||||||
@@ -51,3 +52,11 @@ func MonadChainFirst[GAB ~func(A) B, A, B any](fa A, f GAB) A {
|
|||||||
func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A {
|
func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A {
|
||||||
return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f)
|
return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
|
||||||
|
return FC.MonadFlap(MonadMap[func(GAB) B, GAB, B], fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[GAB ~func(A) B, A, B any](a A) func(GAB) B {
|
||||||
|
return F.Bind2nd(MonadFlap[GAB, A, B], a)
|
||||||
|
}
|
||||||
|
@@ -63,3 +63,11 @@ func MonadChainFirst[A, B any](fa A, f func(A) B) A {
|
|||||||
func ChainFirst[A, B any](f func(A) B) func(A) A {
|
func ChainFirst[A, B any](f func(A) B) func(A) A {
|
||||||
return G.ChainFirst(f)
|
return G.ChainFirst(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFlap[B, A any](fab func(A) B, a A) B {
|
||||||
|
return G.MonadFlap[func(A) B](fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[B, A any](a A) func(func(A) B) B {
|
||||||
|
return G.Flap[func(A) B](a)
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:08.1313362 +0200 CEST m=+0.111171801
|
// 2023-09-12 13:44:26.2499883 +0200 CEST m=+0.007601301
|
||||||
|
|
||||||
package apply
|
package apply
|
||||||
|
|
||||||
|
@@ -37,6 +37,24 @@ func MonadTraverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
|
|||||||
return MonadTraverseReduce(fof, fmap, fap, ta, f, Append[GB, B], Empty[GB]())
|
return MonadTraverseReduce(fof, fmap, fap, ta, f, Append[GB, B], Empty[GB]())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
|
||||||
|
|
||||||
|
HKTRB = HKT<GB>
|
||||||
|
HKTB = HKT<B>
|
||||||
|
HKTAB = HKT<func(A)B>
|
||||||
|
*/
|
||||||
|
func MonadTraverseWithIndex[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
|
||||||
|
fof func(GB) HKTRB,
|
||||||
|
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
||||||
|
fap func(HKTB) func(HKTAB) HKTRB,
|
||||||
|
|
||||||
|
ta GA,
|
||||||
|
f func(int, A) HKTB) HKTRB {
|
||||||
|
return MonadTraverseReduceWithIndex(fof, fmap, fap, ta, f, Append[GB, B], Empty[GB]())
|
||||||
|
}
|
||||||
|
|
||||||
func Traverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
|
func Traverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
|
||||||
fof func(GB) HKTRB,
|
fof func(GB) HKTRB,
|
||||||
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
||||||
@@ -49,6 +67,18 @@ func Traverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TraverseWithIndex[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
|
||||||
|
fof func(GB) HKTRB,
|
||||||
|
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
||||||
|
fap func(HKTB) func(HKTAB) HKTRB,
|
||||||
|
|
||||||
|
f func(int, A) HKTB) func(GA) HKTRB {
|
||||||
|
|
||||||
|
return func(ma GA) HKTRB {
|
||||||
|
return MonadTraverseWithIndex(fof, fmap, fap, ma, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
||||||
fof func(GB) HKTRB,
|
fof func(GB) HKTRB,
|
||||||
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
||||||
@@ -71,6 +101,28 @@ func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
|||||||
}, fof(initial))
|
}, fof(initial))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadTraverseReduceWithIndex[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
||||||
|
fof func(GB) HKTRB,
|
||||||
|
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
||||||
|
fap func(HKTB) func(HKTAB) HKTRB,
|
||||||
|
|
||||||
|
ta GA,
|
||||||
|
|
||||||
|
transform func(int, A) HKTB,
|
||||||
|
reduce func(GB, B) GB,
|
||||||
|
initial GB,
|
||||||
|
) HKTRB {
|
||||||
|
mmap := fmap(F.Curry2(reduce))
|
||||||
|
|
||||||
|
return ReduceWithIndex(ta, func(idx int, r HKTRB, a A) HKTRB {
|
||||||
|
return F.Pipe2(
|
||||||
|
r,
|
||||||
|
mmap,
|
||||||
|
fap(transform(idx, a)),
|
||||||
|
)
|
||||||
|
}, fof(initial))
|
||||||
|
}
|
||||||
|
|
||||||
func TraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
func TraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
||||||
fof func(GB) HKTRB,
|
fof func(GB) HKTRB,
|
||||||
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
||||||
@@ -84,3 +136,17 @@ func TraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
|||||||
return MonadTraverseReduce(fof, fmap, fap, ta, transform, reduce, initial)
|
return MonadTraverseReduce(fof, fmap, fap, ta, transform, reduce, initial)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TraverseReduceWithIndex[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
|
||||||
|
fof func(GB) HKTRB,
|
||||||
|
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
|
||||||
|
fap func(HKTB) func(HKTAB) HKTRB,
|
||||||
|
|
||||||
|
transform func(int, A) HKTB,
|
||||||
|
reduce func(GB, B) GB,
|
||||||
|
initial GB,
|
||||||
|
) func(GA) HKTRB {
|
||||||
|
return func(ta GA) HKTRB {
|
||||||
|
return MonadTraverseReduceWithIndex(fof, fmap, fap, ta, transform, reduce, initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -22,6 +22,16 @@ import (
|
|||||||
FC "github.com/IBM/fp-go/internal/functor"
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func MonadAlt[LAZY ~func() HKTFA, E, A, HKTFA any](
|
||||||
|
fof func(ET.Either[E, A]) HKTFA,
|
||||||
|
fchain func(HKTFA, func(ET.Either[E, A]) HKTFA) HKTFA,
|
||||||
|
|
||||||
|
first HKTFA,
|
||||||
|
second LAZY) HKTFA {
|
||||||
|
|
||||||
|
return fchain(first, ET.Fold(F.Ignore1of1[E](second), F.Flow2(ET.Of[E, A], fof)))
|
||||||
|
}
|
||||||
|
|
||||||
// HKTFA = HKT<F, Either<E, A>>
|
// HKTFA = HKT<F, Either<E, A>>
|
||||||
// HKTFB = HKT<F, Either<E, B>>
|
// HKTFB = HKT<F, Either<E, B>>
|
||||||
func MonadMap[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[E, B]) HKTFB, fa HKTFA, f func(A) B) HKTFB {
|
func MonadMap[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[E, B]) HKTFB, fa HKTFA, f func(A) B) HKTFB {
|
||||||
|
@@ -22,8 +22,8 @@ import (
|
|||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FromOption[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, onNone func() E) func(ma O.Option[A]) HKTEA {
|
func FromOption[A, HKTEA, E any](fromEither func(ET.Either[E, A]) HKTEA, onNone func() E) func(ma O.Option[A]) HKTEA {
|
||||||
return F.Flow2(ET.FromOption[E, A](onNone), fromEither)
|
return F.Flow2(ET.FromOption[A](onNone), fromEither)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromPredicate[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, pred func(A) bool, onFalse func(A) E) func(A) HKTEA {
|
func FromPredicate[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, pred func(A) bool, onFalse func(A) E) func(A) HKTEA {
|
||||||
@@ -45,7 +45,7 @@ func MonadFromOption[E, A, HKTEA any](
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromOptionK[E, A, B, HKTEB any](
|
func FromOptionK[A, E, B, HKTEB any](
|
||||||
fromEither func(ET.Either[E, B]) HKTEB,
|
fromEither func(ET.Either[E, B]) HKTEB,
|
||||||
onNone func() E) func(f func(A) O.Option[B]) func(A) HKTEB {
|
onNone func() E) func(f func(A) O.Option[B]) func(A) HKTEB {
|
||||||
// helper
|
// helper
|
||||||
@@ -65,7 +65,7 @@ func ChainOptionK[A, E, B, HKTEA, HKTEB any](
|
|||||||
fromEither func(ET.Either[E, B]) HKTEB,
|
fromEither func(ET.Either[E, B]) HKTEB,
|
||||||
onNone func() E,
|
onNone func() E,
|
||||||
) func(f func(A) O.Option[B]) func(ma HKTEA) HKTEB {
|
) func(f func(A) O.Option[B]) func(ma HKTEA) HKTEB {
|
||||||
return F.Flow2(FromOptionK[E, A](fromEither, onNone), F.Bind1st(F.Bind2nd[HKTEA, func(A) HKTEB, HKTEB], mchain))
|
return F.Flow2(FromOptionK[A](fromEither, onNone), F.Bind1st(F.Bind2nd[HKTEA, func(A) HKTEB, HKTEB], mchain))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainFirstEitherK[A, E, B, HKTEA, HKTEB any](
|
func MonadChainFirstEitherK[A, E, B, HKTEA, HKTEB any](
|
||||||
|
37
internal/functor/flap.go
Normal file
37
internal/functor/flap.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 functor
|
||||||
|
|
||||||
|
func MonadFlap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
||||||
|
fmap func(HKTFAB, func(FAB) B) HKTB,
|
||||||
|
|
||||||
|
fab HKTFAB,
|
||||||
|
a A,
|
||||||
|
) HKTB {
|
||||||
|
return fmap(fab, func(f FAB) B {
|
||||||
|
return f(a)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
||||||
|
fmap func(HKTFAB, func(FAB) B) HKTB,
|
||||||
|
|
||||||
|
a A,
|
||||||
|
) func(HKTFAB) HKTB {
|
||||||
|
return func(fab HKTFAB) HKTB {
|
||||||
|
return MonadFlap(fmap, fab, a)
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:10.1040409 +0200 CEST m=+0.089470201
|
// 2023-09-12 13:44:27.9813739 +0200 CEST m=+0.011088001
|
||||||
|
|
||||||
package io
|
package io
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:10.1132645 +0200 CEST m=+0.098693801
|
// 2023-09-12 13:44:27.9813739 +0200 CEST m=+0.011088001
|
||||||
package generic
|
package generic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
C "github.com/IBM/fp-go/internal/chain"
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
L "github.com/IBM/fp-go/internal/lazy"
|
L "github.com/IBM/fp-go/internal/lazy"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -143,3 +144,11 @@ func Defer[GA ~func() A, A any](gen func() GA) GA {
|
|||||||
return gen()()
|
return gen()()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFlap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](fab GFAB, a A) GB {
|
||||||
|
return FC.MonadFlap(MonadMap[GFAB, GB, FAB, B], fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(GFAB) GB {
|
||||||
|
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
|
||||||
|
}
|
||||||
|
@@ -42,6 +42,16 @@ func TraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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],
|
||||||
|
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
|
||||||
|
Ap[GBS, func() func(B) BBS, GB],
|
||||||
|
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func SequenceArray[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
|
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])
|
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
|
||||||
}
|
}
|
||||||
@@ -66,6 +76,16 @@ func TraverseRecord[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K co
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndex transforms a record using an IO transform an IO of a record
|
||||||
|
func TraverseRecordWithIndex[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],
|
||||||
|
Ap[GBS, func() func(B) MB, GB],
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
|
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[GA, GAS](tas, F.Identity[GA])
|
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])
|
||||||
}
|
}
|
||||||
|
10
io/io.go
10
io/io.go
@@ -84,7 +84,7 @@ func Flatten[A any](mma IO[IO[A]]) IO[A] {
|
|||||||
return G.Flatten(mma)
|
return G.Flatten(mma)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memoize computes the value of the provided IO monad lazily but exactly once
|
// Memoize computes the value of the provided [IO] monad lazily but exactly once
|
||||||
func Memoize[A any](ma IO[A]) IO[A] {
|
func Memoize[A any](ma IO[A]) IO[A] {
|
||||||
return G.Memoize(ma)
|
return G.Memoize(ma)
|
||||||
}
|
}
|
||||||
@@ -138,3 +138,11 @@ var Now = G.Now[IO[time.Time]]()
|
|||||||
func Defer[A any](gen func() IO[A]) IO[A] {
|
func Defer[A any](gen func() IO[A]) IO[A] {
|
||||||
return G.Defer[IO[A]](gen)
|
return G.Defer[IO[A]](gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadFlap[B, A any](fab IO[func(A) B], a A) IO[B] {
|
||||||
|
return G.MonadFlap[func(A) B, IO[func(A) B], IO[B], A, B](fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(IO[func(A) B]) IO[B] {
|
||||||
|
return G.Flap[func(A) B, IO[func(A) B], IO[B], A, B](a)
|
||||||
|
}
|
||||||
|
@@ -29,6 +29,12 @@ func TraverseArray[A, B any](f func(A) IO[B]) func([]A) IO[[]B] {
|
|||||||
return G.TraverseArray[IO[B], IO[[]B], []A](f)
|
return G.TraverseArray[IO[B], IO[[]B], []A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex applies a function returning an [IO] to all elements in an array and the
|
||||||
|
// transforms this into an [IO] of that array
|
||||||
|
func TraverseArrayWithIndex[A, B any](f func(int, A) IO[B]) func([]A) IO[[]B] {
|
||||||
|
return G.TraverseArrayWithIndex[IO[B], IO[[]B], []A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts an array of [IO] to an [IO] of an array
|
// SequenceArray converts an array of [IO] to an [IO] of an array
|
||||||
func SequenceArray[A any](tas []IO[A]) IO[[]A] {
|
func SequenceArray[A any](tas []IO[A]) IO[[]A] {
|
||||||
return G.SequenceArray[IO[A], IO[[]A]](tas)
|
return G.SequenceArray[IO[A], IO[[]A]](tas)
|
||||||
@@ -38,12 +44,18 @@ func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) IO[B]) I
|
|||||||
return G.MonadTraverseRecord[IO[B], IO[map[K]B]](tas, f)
|
return G.MonadTraverseRecord[IO[B], IO[map[K]B]](tas, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TraverseArray applies a function returning an [IO] to all elements in a record and the
|
// TraverseRecord applies a function returning an [IO] to all elements in a record and the
|
||||||
// transforms this into an [IO] of that record
|
// transforms this into an [IO] of that record
|
||||||
func TraverseRecord[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] {
|
func TraverseRecord[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] {
|
||||||
return G.TraverseRecord[IO[B], IO[map[K]B], map[K]A](f)
|
return G.TraverseRecord[IO[B], IO[map[K]B], map[K]A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndex applies a function returning an [IO] to all elements in a record and the
|
||||||
|
// transforms this into an [IO] of that record
|
||||||
|
func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) IO[B]) func(map[K]A) IO[map[K]B] {
|
||||||
|
return G.TraverseRecordWithIndex[IO[B], IO[map[K]B], map[K]A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceRecord converts a record of [IO] to an [IO] of a record
|
// SequenceRecord converts a record of [IO] to an [IO] of a record
|
||||||
func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] {
|
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)
|
return G.SequenceRecord[IO[A], IO[map[K]A]](tas)
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
@@ -45,3 +46,10 @@ func Remove(name string) IOE.IOEither[error, string] {
|
|||||||
return name, os.Remove(name)
|
return name, os.Remove(name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close closes an object
|
||||||
|
func Close[C io.Closer](c C) IOE.IOEither[error, any] {
|
||||||
|
return IOE.TryCatchError(func() (any, error) {
|
||||||
|
return c, c.Close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -31,7 +31,7 @@ func onReadAll[R io.Reader](r R) IOE.IOEither[error, []byte] {
|
|||||||
func ReadAll[R io.ReadCloser](acquire IOE.IOEither[error, R]) IOE.IOEither[error, []byte] {
|
func ReadAll[R io.ReadCloser](acquire IOE.IOEither[error, R]) IOE.IOEither[error, []byte] {
|
||||||
return IOE.WithResource[[]byte](
|
return IOE.WithResource[[]byte](
|
||||||
acquire,
|
acquire,
|
||||||
onClose[R])(
|
Close[R])(
|
||||||
onReadAll[R],
|
onReadAll[R],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,6 @@ package file
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
FL "github.com/IBM/fp-go/file"
|
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
IO "github.com/IBM/fp-go/io"
|
IO "github.com/IBM/fp-go/io"
|
||||||
IOF "github.com/IBM/fp-go/io/file"
|
IOF "github.com/IBM/fp-go/io/file"
|
||||||
@@ -33,7 +32,7 @@ var (
|
|||||||
// destroy handler
|
// destroy handler
|
||||||
onReleaseTempFile = F.Flow4(
|
onReleaseTempFile = F.Flow4(
|
||||||
IOF.Close[*os.File],
|
IOF.Close[*os.File],
|
||||||
IO.Map(FL.GetName),
|
IO.Map((*os.File).Name),
|
||||||
IOE.FromIO[error, string],
|
IOE.FromIO[error, string],
|
||||||
IOE.Chain(Remove),
|
IOE.Chain(Remove),
|
||||||
)
|
)
|
||||||
|
@@ -38,7 +38,7 @@ func TestWithTempFileOnClosedFile(t *testing.T) {
|
|||||||
return F.Pipe2(
|
return F.Pipe2(
|
||||||
f,
|
f,
|
||||||
onWriteAll[*os.File]([]byte("Carsten")),
|
onWriteAll[*os.File]([]byte("Carsten")),
|
||||||
IOE.ChainFirst(F.Constant1[[]byte](onClose(f))),
|
IOE.ChainFirst(F.Constant1[[]byte](Close(f))),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -36,7 +36,7 @@ func WriteAll[W io.WriteCloser](data []byte) func(acquire IOE.IOEither[error, W]
|
|||||||
return func(onCreate IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
|
return func(onCreate IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
|
||||||
return IOE.WithResource[[]byte](
|
return IOE.WithResource[[]byte](
|
||||||
onCreate,
|
onCreate,
|
||||||
onClose[W])(
|
Close[W])(
|
||||||
onWrite,
|
onWrite,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -46,5 +46,5 @@ func WriteAll[W io.WriteCloser](data []byte) func(acquire IOE.IOEither[error, W]
|
|||||||
func Write[R any, W io.WriteCloser](acquire IOE.IOEither[error, W]) func(use func(W) IOE.IOEither[error, R]) IOE.IOEither[error, R] {
|
func Write[R any, W io.WriteCloser](acquire IOE.IOEither[error, W]) func(use func(W) IOE.IOEither[error, R]) IOE.IOEither[error, R] {
|
||||||
return IOE.WithResource[R](
|
return IOE.WithResource[R](
|
||||||
acquire,
|
acquire,
|
||||||
onClose[W])
|
Close[W])
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:12.0033119 +0200 CEST m=+0.096740401
|
// 2023-09-12 13:44:29.4935658 +0200 CEST m=+0.015377401
|
||||||
|
|
||||||
package ioeither
|
package ioeither
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:12.0246635 +0200 CEST m=+0.118092001
|
// 2023-09-12 13:44:29.4935658 +0200 CEST m=+0.015377401
|
||||||
package generic
|
package generic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/IBM/fp-go/internal/eithert"
|
"github.com/IBM/fp-go/internal/eithert"
|
||||||
FE "github.com/IBM/fp-go/internal/fromeither"
|
FE "github.com/IBM/fp-go/internal/fromeither"
|
||||||
FI "github.com/IBM/fp-go/internal/fromio"
|
FI "github.com/IBM/fp-go/internal/fromio"
|
||||||
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
IO "github.com/IBM/fp-go/io/generic"
|
IO "github.com/IBM/fp-go/io/generic"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
@@ -290,3 +291,25 @@ func FromImpure[GA ~func() ET.Either[E, any], IMP ~func(), E any](f IMP) GA {
|
|||||||
func Defer[GEA ~func() ET.Either[E, A], E, A any](gen func() GEA) GEA {
|
func Defer[GEA ~func() ET.Either[E, A], E, A any](gen func() GEA) GEA {
|
||||||
return IO.Defer[GEA](gen)
|
return IO.Defer[GEA](gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadAlt[LAZY ~func() GIOA, GIOA ~func() ET.Either[E, A], E, A any](first GIOA, second LAZY) GIOA {
|
||||||
|
return eithert.MonadAlt(
|
||||||
|
IO.Of[GIOA],
|
||||||
|
IO.MonadChain[GIOA, GIOA],
|
||||||
|
|
||||||
|
first,
|
||||||
|
second,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Alt[LAZY ~func() GIOA, GIOA ~func() ET.Either[E, A], E, A any](second LAZY) func(GIOA) GIOA {
|
||||||
|
return F.Bind2nd(MonadAlt[LAZY], second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadFlap[GEAB ~func() ET.Either[E, func(A) B], GEB ~func() ET.Either[E, B], E, B, A any](fab GEAB, a A) GEB {
|
||||||
|
return FC.MonadFlap(MonadMap[GEAB, GEB], fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[GEAB ~func() ET.Either[E, func(A) B], GEB ~func() ET.Either[E, B], E, B, A any](a A) func(GEAB) GEB {
|
||||||
|
return FC.Flap(MonadMap[GEAB, GEB], a)
|
||||||
|
}
|
||||||
|
54
ioeither/generic/monoid.go
Normal file
54
ioeither/generic/monoid.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// 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 (
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ApplicativeMonoid[GEA ~func() ET.Either[E, A], GEFA ~func() ET.Either[E, func(A) A], E, A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[GEA] {
|
||||||
|
return M.ApplicativeMonoid(
|
||||||
|
MonadOf[GEA],
|
||||||
|
MonadMap[GEA, GEFA],
|
||||||
|
MonadAp[GEA, GEFA, GEA],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplicativeMonoidSeq[GEA ~func() ET.Either[E, A], GEFA ~func() ET.Either[E, func(A) A], E, A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[GEA] {
|
||||||
|
return M.ApplicativeMonoid(
|
||||||
|
MonadOf[GEA],
|
||||||
|
MonadMap[GEA, GEFA],
|
||||||
|
MonadApSeq[GEA, GEFA, GEA],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplicativeMonoidPar[GEA ~func() ET.Either[E, A], GEFA ~func() ET.Either[E, func(A) A], E, A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[GEA] {
|
||||||
|
return M.ApplicativeMonoid(
|
||||||
|
MonadOf[GEA],
|
||||||
|
MonadMap[GEA, GEFA],
|
||||||
|
MonadApPar[GEA, GEFA, GEA],
|
||||||
|
m,
|
||||||
|
)
|
||||||
|
}
|
27
ioeither/generic/semigroup.go
Normal file
27
ioeither/generic/semigroup.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// 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 (
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AltSemigroup[GIOA ~func() ET.Either[E, A], E, A any]() S.Semigroup[GIOA] {
|
||||||
|
return S.AltSemigroup(
|
||||||
|
MonadAlt[func() GIOA],
|
||||||
|
)
|
||||||
|
}
|
@@ -45,6 +45,29 @@ func TraverseArray[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AA
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonadTraverseArrayWithIndex transforms an array
|
||||||
|
func MonadTraverseArrayWithIndex[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~[]A, BBS ~[]B, E, A, B any](tas AAS, f func(int, A) GB) GBS {
|
||||||
|
return RA.MonadTraverseWithIndex[AAS](
|
||||||
|
Of[GBS, E, BBS],
|
||||||
|
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
|
||||||
|
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
|
||||||
|
|
||||||
|
tas,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~[]A, BBS ~[]B, E, A, B any](f func(int, A) GB) func(AAS) GBS {
|
||||||
|
return RA.TraverseWithIndex[AAS](
|
||||||
|
Of[GBS, E, BBS],
|
||||||
|
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
|
||||||
|
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
|
||||||
|
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~[]A, GAAS ~[]GA, E, A any](tas GAAS) GAS {
|
func SequenceArray[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~[]A, GAAS ~[]GA, E, A any](tas GAAS) GAS {
|
||||||
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
|
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
|
||||||
@@ -73,6 +96,17 @@ func TraverseRecord[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], A
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndex transforms an array
|
||||||
|
func TraverseRecordWithIndex[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~map[K]A, BBS ~map[K]B, K comparable, E, A, B any](f func(K, A) GB) func(AAS) GBS {
|
||||||
|
return RR.TraverseWithIndex[AAS](
|
||||||
|
Of[GBS, E, BBS],
|
||||||
|
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
|
||||||
|
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
|
||||||
|
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceRecord[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~map[K]A, GAAS ~map[K]GA, K comparable, E, A any](tas GAAS) GAS {
|
func SequenceRecord[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~map[K]A, GAAS ~map[K]GA, K comparable, E, A any](tas GAAS) GAS {
|
||||||
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])
|
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])
|
||||||
|
@@ -19,6 +19,7 @@ import (
|
|||||||
ET "github.com/IBM/fp-go/either"
|
ET "github.com/IBM/fp-go/either"
|
||||||
I "github.com/IBM/fp-go/io"
|
I "github.com/IBM/fp-go/io"
|
||||||
G "github.com/IBM/fp-go/ioeither/generic"
|
G "github.com/IBM/fp-go/ioeither/generic"
|
||||||
|
L "github.com/IBM/fp-go/lazy"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,10 +75,20 @@ func ChainIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, B
|
|||||||
return G.ChainIOK[IOEither[E, A], IOEither[E, B]](f)
|
return G.ChainIOK[IOEither[E, A], IOEither[E, B]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ChainLazyK[E, A, B any](f func(A) L.Lazy[B]) func(IOEither[E, A]) IOEither[E, B] {
|
||||||
|
return G.ChainIOK[IOEither[E, A], IOEither[E, B]](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromIO creates an [IOEither] from an [IO] instance, invoking [IO] for each invocation of [IOEither]
|
||||||
func FromIO[E, A any](mr I.IO[A]) IOEither[E, A] {
|
func FromIO[E, A any](mr I.IO[A]) IOEither[E, A] {
|
||||||
return G.FromIO[IOEither[E, A]](mr)
|
return G.FromIO[IOEither[E, A]](mr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromLazy creates an [IOEither] from a [Lazy] instance, invoking [Lazy] for each invocation of [IOEither]
|
||||||
|
func FromLazy[E, A any](mr L.Lazy[A]) IOEither[E, A] {
|
||||||
|
return G.FromIO[IOEither[E, A]](mr)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadMap[E, A, B any](fa IOEither[E, A], f func(A) B) IOEither[E, B] {
|
func MonadMap[E, A, B any](fa IOEither[E, A], f func(A) B) IOEither[E, B] {
|
||||||
return G.MonadMap[IOEither[E, A], IOEither[E, B]](fa, f)
|
return G.MonadMap[IOEither[E, A], IOEither[E, B]](fa, f)
|
||||||
}
|
}
|
||||||
@@ -166,27 +177,27 @@ func MonadChainTo[E, A, B any](fa IOEither[E, A], fb IOEither[E, B]) IOEither[E,
|
|||||||
return G.MonadChainTo(fa, fb)
|
return G.MonadChainTo(fa, fb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainTo composes to the second monad ignoring the return value of the first
|
// ChainTo composes to the second [IOEither] monad ignoring the return value of the first
|
||||||
func ChainTo[E, A, B any](fb IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
|
func ChainTo[E, A, B any](fb IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
|
||||||
return G.ChainTo[IOEither[E, A]](fb)
|
return G.ChainTo[IOEither[E, A]](fb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonadChainFirst runs the monad returned by the function but returns the result of the original monad
|
// MonadChainFirst runs the [IOEither] monad returned by the function but returns the result of the original monad
|
||||||
func MonadChainFirst[E, A, B any](ma IOEither[E, A], f func(A) IOEither[E, B]) IOEither[E, A] {
|
func MonadChainFirst[E, A, B any](ma IOEither[E, A], f func(A) IOEither[E, B]) IOEither[E, A] {
|
||||||
return G.MonadChainFirst(ma, f)
|
return G.MonadChainFirst(ma, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainFirst runs the monad returned by the function but returns the result of the original monad
|
// ChainFirst runs the [IOEither] monad returned by the function but returns the result of the original monad
|
||||||
func ChainFirst[E, A, B any](f func(A) IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] {
|
func ChainFirst[E, A, B any](f func(A) IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] {
|
||||||
return G.ChainFirst[IOEither[E, A]](f)
|
return G.ChainFirst[IOEither[E, A]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
// MonadChainFirstIOK runs [IO] the monad returned by the function but returns the result of the original monad
|
||||||
func MonadChainFirstIOK[E, A, B any](ma IOEither[E, A], f func(A) I.IO[B]) IOEither[E, A] {
|
func MonadChainFirstIOK[E, A, B any](ma IOEither[E, A], f func(A) I.IO[B]) IOEither[E, A] {
|
||||||
return G.MonadChainFirstIOK(ma, f)
|
return G.MonadChainFirstIOK(ma, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainFirsIOKt runs the monad returned by the function but returns the result of the original monad
|
// ChainFirstIOK runs the [IO] monad returned by the function but returns the result of the original monad
|
||||||
func ChainFirstIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, A] {
|
func ChainFirstIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, A] {
|
||||||
return G.ChainFirstIOK[IOEither[E, A]](f)
|
return G.ChainFirstIOK[IOEither[E, A]](f)
|
||||||
}
|
}
|
||||||
@@ -207,6 +218,24 @@ func FromImpure[E any](f func()) IOEither[E, any] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||||
func Defer[E, A any](gen func() IOEither[E, A]) IOEither[E, A] {
|
func Defer[E, A any](gen L.Lazy[IOEither[E, A]]) IOEither[E, A] {
|
||||||
return G.Defer[IOEither[E, A]](gen)
|
return G.Defer[IOEither[E, A]](gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonadAlt identifies an associative operation on a type constructor
|
||||||
|
func MonadAlt[E, A any](first IOEither[E, A], second L.Lazy[IOEither[E, A]]) IOEither[E, A] {
|
||||||
|
return G.MonadAlt(first, second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alt identifies an associative operation on a type constructor
|
||||||
|
func Alt[E, A any](second L.Lazy[IOEither[E, A]]) func(IOEither[E, A]) IOEither[E, A] {
|
||||||
|
return G.Alt(second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadFlap[E, B, A any](fab IOEither[E, func(A) B], a A) IOEither[E, B] {
|
||||||
|
return G.MonadFlap[IOEither[E, func(A) B], IOEither[E, B]](fab, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Flap[E, B, A any](a A) func(IOEither[E, func(A) B]) IOEither[E, B] {
|
||||||
|
return G.Flap[IOEither[E, func(A) B], IOEither[E, B]](a)
|
||||||
|
}
|
||||||
|
42
ioeither/monoid.go
Normal file
42
ioeither/monoid.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// 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 (
|
||||||
|
G "github.com/IBM/fp-go/ioeither/generic"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ApplicativeMonoid returns a [Monoid] that concatenates [IOEither] instances via their applicative
|
||||||
|
func ApplicativeMonoid[E, A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[IOEither[E, A]] {
|
||||||
|
return G.ApplicativeMonoid[IOEither[E, A], IOEither[E, func(A) A]](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicativeMonoid returns a [Monoid] that concatenates [IOEither] instances via their applicative
|
||||||
|
func ApplicativeMonoidSeq[E, A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[IOEither[E, A]] {
|
||||||
|
return G.ApplicativeMonoidSeq[IOEither[E, A], IOEither[E, func(A) A]](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplicativeMonoid returns a [Monoid] that concatenates [IOEither] instances via their applicative
|
||||||
|
func ApplicativeMonoidPar[E, A any](
|
||||||
|
m M.Monoid[A],
|
||||||
|
) M.Monoid[IOEither[E, A]] {
|
||||||
|
return G.ApplicativeMonoid[IOEither[E, A], IOEither[E, func(A) A]](m)
|
||||||
|
}
|
42
ioeither/monoid_test.go
Normal file
42
ioeither/monoid_test.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// 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 (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
S "github.com/IBM/fp-go/string"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplicativeMonoid(t *testing.T) {
|
||||||
|
m := ApplicativeMonoid[error](S.Monoid)
|
||||||
|
|
||||||
|
// good cases
|
||||||
|
assert.Equal(t, E.Of[error]("ab"), m.Concat(Of[error]("a"), Of[error]("b"))())
|
||||||
|
assert.Equal(t, E.Of[error]("a"), m.Concat(Of[error]("a"), m.Empty())())
|
||||||
|
assert.Equal(t, E.Of[error]("b"), m.Concat(m.Empty(), Of[error]("b"))())
|
||||||
|
|
||||||
|
// bad cases
|
||||||
|
e1 := fmt.Errorf("e1")
|
||||||
|
e2 := fmt.Errorf("e1")
|
||||||
|
|
||||||
|
assert.Equal(t, E.Left[string](e1), m.Concat(Left[string](e1), Of[error]("b"))())
|
||||||
|
assert.Equal(t, E.Left[string](e1), m.Concat(Left[string](e1), Left[string](e2))())
|
||||||
|
assert.Equal(t, E.Left[string](e2), m.Concat(Of[error]("a"), Left[string](e2))())
|
||||||
|
}
|
26
ioeither/semigroup.go
Normal file
26
ioeither/semigroup.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// 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 (
|
||||||
|
G "github.com/IBM/fp-go/ioeither/generic"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AltSemigroup is a [Semigroup] that tries the first item and then the second one using an alternative
|
||||||
|
func AltSemigroup[E, A any]() S.Semigroup[IOEither[E, A]] {
|
||||||
|
return G.AltSemigroup[IOEither[E, A]]()
|
||||||
|
}
|
@@ -24,6 +24,11 @@ func TraverseArray[E, A, B any](f func(A) IOEither[E, B]) func([]A) IOEither[E,
|
|||||||
return G.TraverseArray[IOEither[E, B], IOEither[E, []B], []A](f)
|
return G.TraverseArray[IOEither[E, B], IOEither[E, []B], []A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[E, A, B any](f func(int, A) IOEither[E, B]) func([]A) IOEither[E, []B] {
|
||||||
|
return G.TraverseArrayWithIndex[IOEither[E, B], IOEither[E, []B], []A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[E, A any](ma []IOEither[E, A]) IOEither[E, []A] {
|
func SequenceArray[E, A any](ma []IOEither[E, A]) IOEither[E, []A] {
|
||||||
return G.SequenceArray[IOEither[E, A], IOEither[E, []A]](ma)
|
return G.SequenceArray[IOEither[E, A], IOEither[E, []A]](ma)
|
||||||
@@ -34,6 +39,11 @@ func TraverseRecord[K comparable, E, A, B any](f func(A) IOEither[E, B]) func(ma
|
|||||||
return G.TraverseRecord[IOEither[E, B], IOEither[E, map[K]B], map[K]A](f)
|
return G.TraverseRecord[IOEither[E, B], IOEither[E, map[K]B], map[K]A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseRecordWithIndex transforms a record
|
||||||
|
func TraverseRecordWithIndex[K comparable, E, A, B any](f func(K, A) IOEither[E, B]) func(map[K]A) IOEither[E, map[K]B] {
|
||||||
|
return G.TraverseRecordWithIndex[IOEither[E, B], IOEither[E, map[K]B], map[K]A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceRecord[K comparable, E, A any](ma map[K]IOEither[E, A]) IOEither[E, map[K]A] {
|
func SequenceRecord[K comparable, E, A any](ma map[K]IOEither[E, A]) IOEither[E, map[K]A] {
|
||||||
return G.SequenceRecord[IOEither[E, A], IOEither[E, map[K]A]](ma)
|
return G.SequenceRecord[IOEither[E, A], IOEither[E, map[K]A]](ma)
|
||||||
|
37
ioeither/traverse_test.go
Normal file
37
ioeither/traverse_test.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// 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 (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTraverseArray(t *testing.T) {
|
||||||
|
|
||||||
|
src := A.From("A", "B")
|
||||||
|
|
||||||
|
trfrm := TraverseArrayWithIndex(func(idx int, data string) IOEither[error, string] {
|
||||||
|
return Of[error](fmt.Sprintf("idx: %d, data: %s", idx, data))
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, E.Of[error](A.From("idx: 0, data: A", "idx: 1, data: B")), trfrm(src)())
|
||||||
|
|
||||||
|
}
|
@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) IOOption[B]) func([]A) IOOption[[]B] {
|
|||||||
return G.TraverseArray[IOOption[B], IOOption[[]B], []A](f)
|
return G.TraverseArray[IOOption[B], IOOption[[]B], []A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex transforms an array
|
||||||
|
func TraverseArrayWithIndex[A, B any](f func(int, A) IOOption[B]) func([]A) IOOption[[]B] {
|
||||||
|
return G.TraverseArrayWithIndex[IOOption[B], IOOption[[]B], []A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||||
func SequenceArray[A any](ma []IOOption[A]) IOOption[[]A] {
|
func SequenceArray[A any](ma []IOOption[A]) IOOption[[]A] {
|
||||||
return G.SequenceArray[IOOption[A], IOOption[[]A], []IOOption[A], []A, A](ma)
|
return G.SequenceArray[IOOption[A], IOOption[[]A], []IOOption[A], []A, A](ma)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:14.0582736 +0200 CEST m=+0.248503201
|
// 2023-09-12 13:44:32.1514823 +0200 CEST m=+0.098931001
|
||||||
|
|
||||||
package iooption
|
package iooption
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-08-17 22:59:14.0642289 +0200 CEST m=+0.254458501
|
// 2023-09-12 13:44:32.1546277 +0200 CEST m=+0.102076401
|
||||||
package generic
|
package generic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@@ -18,6 +18,7 @@ package generic
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
FI "github.com/IBM/fp-go/internal/fromio"
|
FI "github.com/IBM/fp-go/internal/fromio"
|
||||||
"github.com/IBM/fp-go/internal/optiont"
|
"github.com/IBM/fp-go/internal/optiont"
|
||||||
@@ -55,6 +56,21 @@ func FromOption[GA ~func() O.Option[A], A any](o O.Option[A]) GA {
|
|||||||
return IO.Of[GA](o)
|
return IO.Of[GA](o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FromEither[GA ~func() O.Option[A], E, A any](e ET.Either[E, A]) GA {
|
||||||
|
return F.Pipe2(
|
||||||
|
e,
|
||||||
|
ET.ToOption[E, A],
|
||||||
|
FromOption[GA],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromIOEither[GA ~func() O.Option[A], GEA ~func() ET.Either[E, A], E, A any](ioe GEA) GA {
|
||||||
|
return F.Pipe1(
|
||||||
|
ioe,
|
||||||
|
IO.Map[GEA, GA](ET.ToOption[E, A]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadMap[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](fa GA, f func(A) B) GB {
|
func MonadMap[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](fa GA, f func(A) B) GB {
|
||||||
return optiont.MonadMap(IO.MonadMap[GA, GB, O.Option[A], O.Option[B]], fa, f)
|
return optiont.MonadMap(IO.MonadMap[GA, GB, O.Option[A], O.Option[B]], fa, f)
|
||||||
}
|
}
|
||||||
|
@@ -28,6 +28,13 @@ func TraverseArray[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]A, GB
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TraverseArrayWithIndex[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]A, GB ~[]B, A, B any](f func(int, A) TB) func(GA) TBS {
|
||||||
|
return F.Flow2(
|
||||||
|
I.TraverseArrayWithIndex[TB, func() []O.Option[B], GA](f),
|
||||||
|
I.Map[func() []O.Option[B], TBS](O.SequenceArrayG[GB, []O.Option[B], B]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func SequenceArray[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]TB, GB ~[]B, A, B any](ma GA) TBS {
|
func SequenceArray[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]TB, GB ~[]B, A, B any](ma GA) TBS {
|
||||||
return TraverseArray[TB, TBS, GA](F.Identity[TB])(ma)
|
return TraverseArray[TB, TBS, GA](F.Identity[TB])(ma)
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,9 @@
|
|||||||
package iooption
|
package iooption
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
I "github.com/IBM/fp-go/io"
|
I "github.com/IBM/fp-go/io"
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
G "github.com/IBM/fp-go/iooption/generic"
|
G "github.com/IBM/fp-go/iooption/generic"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
@@ -117,7 +119,7 @@ func Memoize[A any](ma IOOption[A]) IOOption[A] {
|
|||||||
return G.Memoize(ma)
|
return G.Memoize(ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fold convers an IOOption into an IO
|
// Fold convers an [IOOption] into an [IO]
|
||||||
func Fold[A, B any](onNone func() I.IO[B], onSome func(A) I.IO[B]) func(IOOption[A]) I.IO[B] {
|
func Fold[A, B any](onNone func() I.IO[B], onSome func(A) I.IO[B]) func(IOOption[A]) I.IO[B] {
|
||||||
return G.Fold[IOOption[A]](onNone, onSome)
|
return G.Fold[IOOption[A]](onNone, onSome)
|
||||||
}
|
}
|
||||||
@@ -126,3 +128,13 @@ func Fold[A, B any](onNone func() I.IO[B], onSome func(A) I.IO[B]) func(IOOption
|
|||||||
func Defer[A any](gen func() IOOption[A]) IOOption[A] {
|
func Defer[A any](gen func() IOOption[A]) IOOption[A] {
|
||||||
return G.Defer[IOOption[A]](gen)
|
return G.Defer[IOOption[A]](gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromIOEither converts an [IOEither] into an [IOOption]
|
||||||
|
func FromIOEither[E, A any](ioe IOE.IOEither[E, A]) IOOption[A] {
|
||||||
|
return G.FromIOEither[IOOption[A]](ioe)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromEither converts an [Either] into an [IOOption]
|
||||||
|
func FromEither[E, A any](e ET.Either[E, A]) IOOption[A] {
|
||||||
|
return G.FromEither[IOOption[A]](e)
|
||||||
|
}
|
||||||
|
65
iterator/stateless/benchmark_test.go
Normal file
65
iterator/stateless/benchmark_test.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// 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 stateless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkMulti(b *testing.B) {
|
||||||
|
// run the Fib function b.N times
|
||||||
|
for n := 0; n < b.N; n++ {
|
||||||
|
single()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func single() int64 {
|
||||||
|
|
||||||
|
length := 10000
|
||||||
|
nums := make([]int, 0, length)
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
nums = append(nums, i+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return F.Pipe6(
|
||||||
|
nums,
|
||||||
|
FromArray[int],
|
||||||
|
Filter(func(n int) bool {
|
||||||
|
return n%2 == 0
|
||||||
|
}),
|
||||||
|
Map(func(t int) int64 {
|
||||||
|
return int64(t)
|
||||||
|
}),
|
||||||
|
Filter(func(t int64) bool {
|
||||||
|
n := t
|
||||||
|
for n/10 != 0 {
|
||||||
|
if n%10 == 4 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n = n / 10
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}),
|
||||||
|
Map(func(t int64) int {
|
||||||
|
return int(t)
|
||||||
|
}),
|
||||||
|
Reduce(func(n int64, r int) int64 {
|
||||||
|
return n + int64(r)
|
||||||
|
}, int64(0)),
|
||||||
|
)
|
||||||
|
}
|
@@ -82,6 +82,7 @@ func Map[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU,
|
|||||||
m,
|
m,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
m = O.Map(T.Map2(recurse, f))
|
m = O.Map(T.Map2(recurse, f))
|
||||||
|
|
||||||
return recurse
|
return recurse
|
||||||
|
@@ -29,6 +29,12 @@ func TraverseArray[A, B any](f func(A) Lazy[B]) func([]A) Lazy[[]B] {
|
|||||||
return G.TraverseArray[Lazy[B], Lazy[[]B], []A](f)
|
return G.TraverseArray[Lazy[B], Lazy[[]B], []A](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraverseArrayWithIndex applies a function returning an [IO] to all elements in an array and the
|
||||||
|
// transforms this into an [IO] of that array
|
||||||
|
func TraverseArrayWithIndex[A, B any](f func(int, A) Lazy[B]) func([]A) Lazy[[]B] {
|
||||||
|
return G.TraverseArrayWithIndex[Lazy[B], Lazy[[]B], []A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceArray converts an array of [IO] to an [IO] of an array
|
// SequenceArray converts an array of [IO] to an [IO] of an array
|
||||||
func SequenceArray[A any](tas []Lazy[A]) Lazy[[]A] {
|
func SequenceArray[A any](tas []Lazy[A]) Lazy[[]A] {
|
||||||
return G.SequenceArray[Lazy[A], Lazy[[]A]](tas)
|
return G.SequenceArray[Lazy[A], Lazy[[]A]](tas)
|
||||||
@@ -38,12 +44,18 @@ func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) Lazy[B])
|
|||||||
return G.MonadTraverseRecord[Lazy[B], Lazy[map[K]B]](tas, f)
|
return G.MonadTraverseRecord[Lazy[B], Lazy[map[K]B]](tas, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TraverseArray applies a function returning an [IO] to all elements in a record and the
|
// TraverseRecord applies a function returning an [IO] to all elements in a record and the
|
||||||
// transforms this into an [IO] of that record
|
// transforms this into an [IO] of that record
|
||||||
func TraverseRecord[K comparable, A, B any](f func(A) Lazy[B]) func(map[K]A) Lazy[map[K]B] {
|
func TraverseRecord[K comparable, A, B any](f func(A) Lazy[B]) func(map[K]A) Lazy[map[K]B] {
|
||||||
return G.TraverseRecord[Lazy[B], Lazy[map[K]B], map[K]A](f)
|
return G.TraverseRecord[Lazy[B], Lazy[map[K]B], map[K]A](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 TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) Lazy[B]) func(map[K]A) Lazy[map[K]B] {
|
||||||
|
return G.TraverseRecordWithIndex[Lazy[B], Lazy[map[K]B], map[K]A](f)
|
||||||
|
}
|
||||||
|
|
||||||
// SequenceRecord converts a record of [IO] to an [IO] of a record
|
// SequenceRecord converts a record of [IO] to an [IO] of a record
|
||||||
func SequenceRecord[K comparable, A any](tas map[K]Lazy[A]) Lazy[map[K]A] {
|
func SequenceRecord[K comparable, A any](tas map[K]Lazy[A]) Lazy[map[K]A] {
|
||||||
return G.SequenceRecord[Lazy[A], Lazy[map[K]A]](tas)
|
return G.SequenceRecord[Lazy[A], Lazy[map[K]A]](tas)
|
||||||
|
58
monoid/alt.go
Normal file
58
monoid/alt.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// 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 monoid
|
||||||
|
|
||||||
|
import (
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AlternativeMonoid[A, HKTA, HKTFA any, LAZYHKTA ~func() HKTA](
|
||||||
|
fof func(A) HKTA,
|
||||||
|
|
||||||
|
fmap func(HKTA, func(A) func(A) A) HKTFA,
|
||||||
|
fap func(HKTFA, HKTA) HKTA,
|
||||||
|
|
||||||
|
falt func(HKTA, LAZYHKTA) HKTA,
|
||||||
|
|
||||||
|
m Monoid[A],
|
||||||
|
|
||||||
|
) Monoid[HKTA] {
|
||||||
|
|
||||||
|
sg := ApplicativeMonoid(fof, fmap, fap, m)
|
||||||
|
|
||||||
|
return MakeMonoid(
|
||||||
|
func(first, second HKTA) HKTA {
|
||||||
|
snd := func() HKTA { return second }
|
||||||
|
|
||||||
|
return falt(sg.Concat(first, second), func() HKTA {
|
||||||
|
return falt(first, snd)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
sg.Empty(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AltMonoid[HKTA any, LAZYHKTA ~func() HKTA](
|
||||||
|
fzero LAZYHKTA,
|
||||||
|
falt func(HKTA, LAZYHKTA) HKTA,
|
||||||
|
|
||||||
|
) Monoid[HKTA] {
|
||||||
|
|
||||||
|
return MakeMonoid(
|
||||||
|
S.AltSemigroup(falt).Concat,
|
||||||
|
fzero(),
|
||||||
|
)
|
||||||
|
}
|
@@ -20,15 +20,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ApplicativeMonoid[A, HKTA, HKTFA any](
|
func ApplicativeMonoid[A, HKTA, HKTFA any](
|
||||||
_of func(A) HKTA,
|
fof func(A) HKTA,
|
||||||
_map func(HKTA, func(A) func(A) A) HKTFA,
|
fmap func(HKTA, func(A) func(A) A) HKTFA,
|
||||||
_ap func(HKTFA, HKTA) HKTA,
|
fap func(HKTFA, HKTA) HKTA,
|
||||||
|
|
||||||
m Monoid[A],
|
m Monoid[A],
|
||||||
) Monoid[HKTA] {
|
) Monoid[HKTA] {
|
||||||
|
|
||||||
return MakeMonoid(
|
return MakeMonoid(
|
||||||
S.ApplySemigroup[A](_map, _ap, m).Concat,
|
S.ApplySemigroup[A](fmap, fap, m).Concat,
|
||||||
_of(m.Empty()),
|
fof(m.Empty()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -67,7 +67,7 @@ func Modify[S, A any](f func(A) A) func(Iso[S, A]) func(S) S {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wrap wraps the value
|
// Wrap wraps the value
|
||||||
func Unwrap[S, A any](s S) func(Iso[S, A]) A {
|
func Unwrap[A, S any](s S) func(Iso[S, A]) A {
|
||||||
return func(sa Iso[S, A]) A {
|
return func(sa Iso[S, A]) A {
|
||||||
return sa.Get(s)
|
return sa.Get(s)
|
||||||
}
|
}
|
||||||
@@ -81,8 +81,8 @@ func Wrap[S, A any](a A) func(Iso[S, A]) S {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From wraps the value
|
// From wraps the value
|
||||||
func To[S, A any](s S) func(Iso[S, A]) A {
|
func To[A, S any](s S) func(Iso[S, A]) A {
|
||||||
return Unwrap[S, A](s)
|
return Unwrap[A, S](s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// To unwraps the value
|
// To unwraps the value
|
||||||
|
@@ -121,7 +121,7 @@ func Compose[S, A, B any](ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] {
|
|||||||
// the getter returns an `Option[B]` because the container `A` could already be an option
|
// the getter returns an `Option[B]` because the container `A` could already be an option
|
||||||
// if the setter is invoked with `Some[B]` then the value of `B` will be set, potentially on a default value of `A` if `A` did not exist
|
// if the setter is invoked with `Some[B]` then the value of `B` will be set, potentially on a default value of `A` if `A` did not exist
|
||||||
// if the setter is invoked with `None[B]` then the container `A` is reset to `None[A]` because this is the only way to remove `B`
|
// if the setter is invoked with `None[B]` then the container `A` is reset to `None[A]` because this is the only way to remove `B`
|
||||||
func ComposeOption[S, A, B any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
||||||
defa := F.Constant(defaultA)
|
defa := F.Constant(defaultA)
|
||||||
return func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
return func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
||||||
foldab := O.Fold(O.None[B], F.Flow2(ab.Get, O.Some[B]))
|
foldab := O.Fold(O.None[B], F.Flow2(ab.Get, O.Some[B]))
|
||||||
@@ -172,7 +172,7 @@ func ComposeOption[S, A, B any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O
|
|||||||
// if the setter is called with `Some[B]` and `A` does not exist, the default of 'A' is updated with `B`
|
// if the setter is called with `Some[B]` and `A` does not exist, the default of 'A' is updated with `B`
|
||||||
// if the setter is called with `None[B]` and `A` does not exist this is the identity operation on 'S'
|
// if the setter is called with `None[B]` and `A` does not exist this is the identity operation on 'S'
|
||||||
// if the setter is called with `None[B]` and `A` does exist, 'B' is removed from 'A'
|
// if the setter is called with `None[B]` and `A` does exist, 'B' is removed from 'A'
|
||||||
func ComposeOptions[S, A, B any](defaultA A) func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
|
||||||
defa := F.Constant(defaultA)
|
defa := F.Constant(defaultA)
|
||||||
noops := F.Constant(F.Identity[S])
|
noops := F.Constant(F.Identity[S])
|
||||||
noneb := O.None[B]()
|
noneb := O.None[B]()
|
||||||
|
@@ -209,7 +209,7 @@ func TestComposeOption(t *testing.T) {
|
|||||||
// compose lenses
|
// compose lenses
|
||||||
lens := F.Pipe1(
|
lens := F.Pipe1(
|
||||||
inner,
|
inner,
|
||||||
ComposeOption[Outer, *Inner, int](defaultInner)(value),
|
ComposeOption[Outer, int](defaultInner)(value),
|
||||||
)
|
)
|
||||||
outer1 := Outer{inner: &Inner{Value: 1, Foo: "a"}}
|
outer1 := Outer{inner: &Inner{Value: 1, Foo: "a"}}
|
||||||
// the checks
|
// the checks
|
||||||
@@ -235,7 +235,7 @@ func TestComposeOptions(t *testing.T) {
|
|||||||
// compose lenses
|
// compose lenses
|
||||||
lens := F.Pipe1(
|
lens := F.Pipe1(
|
||||||
inner,
|
inner,
|
||||||
ComposeOptions[OuterOpt, *InnerOpt, *int](defaultInner)(value),
|
ComposeOptions[OuterOpt, *int](defaultInner)(value),
|
||||||
)
|
)
|
||||||
// additional settings
|
// additional settings
|
||||||
defaultValue2 := 2
|
defaultValue2 := 2
|
||||||
|
@@ -24,7 +24,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// AtRecord returns a lens that focusses on a value in a record
|
// AtRecord returns a lens that focusses on a value in a record
|
||||||
func AtRecord[M ~map[K]V, K comparable, V any](key K) L.Lens[M, O.Option[V]] {
|
func AtRecord[M ~map[K]V, V any, K comparable](key K) L.Lens[M, O.Option[V]] {
|
||||||
addKey := F.Bind1of2(RR.UpsertAt[M, K, V])(key)
|
addKey := F.Bind1of2(RR.UpsertAt[M, K, V])(key)
|
||||||
delKey := F.Bind1of1(RR.DeleteAt[M, K, V])(key)
|
delKey := F.Bind1of1(RR.DeleteAt[M, K, V])(key)
|
||||||
fold := O.Fold(
|
fold := O.Fold(
|
||||||
@@ -44,6 +44,6 @@ func AtRecord[M ~map[K]V, K comparable, V any](key K) L.Lens[M, O.Option[V]] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord`
|
// AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord`
|
||||||
func AtKey[M ~map[K]V, S any, K comparable, V any](key K) func(sa L.Lens[S, M]) L.Lens[S, O.Option[V]] {
|
func AtKey[M ~map[K]V, S any, V any, K comparable](key K) func(sa L.Lens[S, M]) L.Lens[S, O.Option[V]] {
|
||||||
return L.Compose[S](AtRecord[M](key))
|
return L.Compose[S](AtRecord[M](key))
|
||||||
}
|
}
|
||||||
|
@@ -22,11 +22,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// AtRecord returns a lens that focusses on a value in a record
|
// AtRecord returns a lens that focusses on a value in a record
|
||||||
func AtRecord[K comparable, V any](key K) L.Lens[map[K]V, O.Option[V]] {
|
func AtRecord[V any, K comparable](key K) L.Lens[map[K]V, O.Option[V]] {
|
||||||
return G.AtRecord[map[K]V](key)
|
return G.AtRecord[map[K]V](key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord`
|
// AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord`
|
||||||
func AtKey[S any, K comparable, V any](key K) func(sa L.Lens[S, map[K]V]) L.Lens[S, O.Option[V]] {
|
func AtKey[S any, V any, K comparable](key K) func(sa L.Lens[S, map[K]V]) L.Lens[S, O.Option[V]] {
|
||||||
return G.AtKey[map[K]V, S](key)
|
return G.AtKey[map[K]V, S](key)
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,7 @@ type (
|
|||||||
func TestAtKey(t *testing.T) {
|
func TestAtKey(t *testing.T) {
|
||||||
sa := F.Pipe1(
|
sa := F.Pipe1(
|
||||||
L.Id[S](),
|
L.Id[S](),
|
||||||
AtKey[S, string, int]("a"),
|
AtKey[S, int]("a"),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, O.Some(1), sa.Get(S{"a": 1}))
|
assert.Equal(t, O.Some(1), sa.Get(S{"a": 1}))
|
||||||
|
@@ -198,7 +198,7 @@ func TestOuterLensLaws(t *testing.T) {
|
|||||||
eqValue := EQT.Eq[int]()
|
eqValue := EQT.Eq[int]()
|
||||||
eqOptValue := O.Eq(eqValue)
|
eqOptValue := O.Eq(eqValue)
|
||||||
// lens to access a value from outer
|
// lens to access a value from outer
|
||||||
valueFromOuter := L.ComposeOption[*Outer, *Inner, int](&defaultInner)(valueLens)(outerLens)
|
valueFromOuter := L.ComposeOption[*Outer, int](&defaultInner)(valueLens)(outerLens)
|
||||||
// try to access the value, this should get an option
|
// try to access the value, this should get an option
|
||||||
assert.True(t, eqOptValue.Equals(valueFromOuter.Get(&emptyOuter), O.None[int]()))
|
assert.True(t, eqOptValue.Equals(valueFromOuter.Get(&emptyOuter), O.None[int]()))
|
||||||
// update the object
|
// update the object
|
||||||
@@ -234,7 +234,7 @@ func TestOuterOptLensLaws(t *testing.T) {
|
|||||||
valueFromOuter := F.Pipe3(
|
valueFromOuter := F.Pipe3(
|
||||||
valueOptLens,
|
valueOptLens,
|
||||||
LI.Compose[*InnerOpt](intIso),
|
LI.Compose[*InnerOpt](intIso),
|
||||||
L.ComposeOptions[*OuterOpt, *InnerOpt, int](&defaultInnerOpt),
|
L.ComposeOptions[*OuterOpt, int](&defaultInnerOpt),
|
||||||
I.Ap[L.Lens[*OuterOpt, O.Option[int]]](outerOptLens),
|
I.Ap[L.Lens[*OuterOpt, O.Option[int]]](outerOptLens),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@ func ApplySemigroup[A any](s S.Semigroup[A]) S.Semigroup[Option[A]] {
|
|||||||
return S.ApplySemigroup(MonadMap[A, func(A) A], MonadAp[A, A], s)
|
return S.ApplySemigroup(MonadMap[A, func(A) A], MonadAp[A, A], s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplicativeMonoid returns a [Monoid] that concatenates [Option] instances via their applicative
|
||||||
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[Option[A]] {
|
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[Option[A]] {
|
||||||
return M.ApplicativeMonoid(Of[A], MonadMap[A, func(A) A], MonadAp[A, A], m)
|
return M.ApplicativeMonoid(Of[A], MonadMap[A, func(A) A], MonadAp[A, 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