mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-24 19:29:11 +02:00
Compare commits
182 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
89c34254a9 | ||
|
a14feff1d6 | ||
|
f3642bad60 | ||
|
997627b318 | ||
|
1e1411c003 | ||
|
9ed9f8a171 | ||
|
e7428549e4 | ||
|
aef0048119 | ||
|
709d74b135 | ||
|
38c6541254 | ||
|
813b83b423 | ||
|
9139dedbbe | ||
|
5e15119653 | ||
|
986aa21055 | ||
|
3a4c46ec1e | ||
|
96c3ee20ff | ||
|
7af9acfd99 | ||
|
36eefbcd27 | ||
|
973138c822 | ||
|
12ef79184b | ||
|
5ac47440a1 | ||
|
3aa55c74d4 | ||
|
a6f55a199c | ||
|
2b500d15da | ||
|
599b8256b6 | ||
|
cf70b47984 | ||
|
7bceb856f8 | ||
|
49e89de783 | ||
|
a87de2f644 | ||
|
6d043d2752 | ||
|
1d02f21ff5 | ||
|
e82575fe08 | ||
|
5fcd0b1595 | ||
|
5caabf478c | ||
|
b7ec18c83e | ||
|
96686425fb | ||
|
1f675e08fa | ||
|
4d2f410c98 | ||
|
8f49c1328c | ||
|
2a1d5821db | ||
|
6abbdc5ee1 | ||
|
5fea9858a9 | ||
|
e6426c90c0 | ||
|
54ce59105e | ||
|
8bb006c741 | ||
|
b6efa35b03 | ||
|
35848900c0 | ||
|
3d54f99739 | ||
|
ffd9418cac | ||
|
acfcea59f4 | ||
|
b4bf511f03 | ||
|
211340952b | ||
|
56860425c4 | ||
|
c0b16c675b | ||
|
4b68e66528 | ||
|
5b7e5b153b | ||
|
d43fbeb375 | ||
|
57d507c1ba | ||
|
aa19857127 | ||
|
7766787cc1 | ||
|
6a9f38f990 | ||
|
e9584bc247 | ||
|
55252c5680 | ||
|
88bf35c4af | ||
|
da3c9683eb | ||
|
08d9fed9af | ||
|
83a0c6cdef | ||
|
9da484b79e | ||
|
e46cfd89d4 | ||
|
6a4cdfa891 | ||
|
93a7e9964b | ||
|
9ef98e1ec4 | ||
|
f1a730998d | ||
|
f129297045 | ||
|
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 | ||
|
3ccafb5302 | ||
|
52b71ef4f3 | ||
|
5d77d5bb3d | ||
|
8ba8f852fa | ||
|
29d9882d2a | ||
|
f80ca31e14 | ||
|
8692078972 | ||
|
12a4f6801c | ||
|
8650a8a600 | ||
|
fb3b1f115c | ||
|
ce66cf2295 | ||
|
80e579dd0b | ||
|
ddafd1ee57 | ||
|
b5f077da71 | ||
|
1a0c40b419 | ||
|
d5d89b1853 | ||
|
0f061a5099 | ||
|
45e05f25ff | ||
|
a390d53451 | ||
|
1346b9378a | ||
|
befd4f471e | ||
|
db8d3da87a | ||
|
ee4e936183 | ||
|
0064ac1c75 | ||
|
8944a66c18 | ||
|
bd0c42db01 | ||
|
e9f03e2d26 | ||
|
bb630810fc | ||
|
9ba9eaacbe | ||
|
a9f6839acd | ||
|
1b1dccc551 | ||
|
39c6108bf5 | ||
|
83e1ff30c1 | ||
|
d9dda4cfa5 | ||
|
d9b2804a7e | ||
|
c0028918ae | ||
|
cd53cb7036 | ||
|
469c60f05d | ||
|
74fd0c96e7 | ||
|
e53e2c53e8 | ||
|
2cd35870cb | ||
|
411caa6dff | ||
|
d69a13ecf4 | ||
|
4ed0046971 | ||
|
e4fd34a6b5 | ||
|
89265eed7c | ||
|
fbc6757f82 | ||
|
a12936a86c | ||
|
94bcfde0d3 | ||
|
4e1cb825e7 | ||
|
9988ae27ef |
21
.github/workflows/build.yml
vendored
21
.github/workflows/build.yml
vendored
@@ -17,22 +17,25 @@ on:
|
||||
env:
|
||||
# Currently no way to detect automatically
|
||||
DEFAULT_BRANCH: main
|
||||
GO_VERSION: 1.20.5 # renovate: datasource=golang-version depName=golang
|
||||
NODE_VERSION: 18
|
||||
GO_VERSION: 1.21.6 # renovate: datasource=golang-version depName=golang
|
||||
NODE_VERSION: 20
|
||||
DRY_RUN: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [ '1.20.x', '1.21.x']
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up go ${{env.GO_VERSION}}
|
||||
uses: actions/setup-go@v4
|
||||
- name: Set up go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{env.GO_VERSION}}
|
||||
go-version: ${{ matrix.go-version }}
|
||||
-
|
||||
name: Tests
|
||||
run: |
|
||||
@@ -52,17 +55,17 @@ jobs:
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- name: Full checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
|
||||
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Set up go ${{env.GO_VERSION}}
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{env.GO_VERSION}}
|
||||
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
fp-go.exe
|
||||
main.exe
|
||||
build/
|
||||
build/
|
||||
.idea
|
36
README.md
36
README.md
@@ -1,6 +1,6 @@
|
||||
# Functional programming library for golang
|
||||
|
||||
**🚧 Work in progress! 🚧** Despite major version 1 because of https://github.com/semantic-release/semantic-release/issues/1507. Trying to not make breaking changes, but devil is in the details.
|
||||
**🚧 Work in progress! 🚧** Despite major version 1 because of <https://github.com/semantic-release/semantic-release/issues/1507>. Trying to not make breaking changes, but devil is in the details.
|
||||
|
||||

|
||||
|
||||
@@ -12,7 +12,9 @@ This library is strongly influenced by the awesome [fp-ts](https://github.com/gc
|
||||
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
|
||||
|
||||
@@ -65,7 +67,7 @@ This library aims to provide a set of data types and functions that make it easy
|
||||
|
||||
#### 🧘🏽 Moderation is a virtue
|
||||
|
||||
✔️ The library does not implement its own goroutines and also does not require any expensive synchronization primitives. Coordination of IO operations is implemented via atomic counters without additional primitives.
|
||||
✔️ The library does not implement its own goroutines and also does not require any expensive synchronization primitives. Coordination of IO operations is implemented via atomic counters without additional primitives.
|
||||
|
||||
#### 🧘🏽 Maintainability counts
|
||||
|
||||
@@ -73,7 +75,7 @@ This library aims to provide a set of data types and functions that make it easy
|
||||
|
||||
The library itself also comprises many small functions, but it's admittedly harder to maintain than code that uses it. However this asymmetry is intended because it offloads complexity from users into a central component.
|
||||
|
||||
## Comparation to Idiomatic Go
|
||||
## Comparison to Idiomatic Go
|
||||
|
||||
In this section we discuss how the functional APIs differ from idiomatic go function signatures and how to convert back and forth.
|
||||
|
||||
@@ -87,26 +89,25 @@ If your pure function does not return an error, the idiomatic signature is just
|
||||
|
||||
#### With Errors
|
||||
|
||||
If your pure function can return an error, then it will have a `(T, error)` return value in idiomatic go. In functional style the return value is [Either[error, T]](./either/) because function composition is easier with such a return type. Use the `EitherizeXXX` methods in ["github.com/IBM/fp-go/either"](./either/) to convert from idiomatic to functional style and `UneitherizeXXX` to convert from functional to idiomatic style.
|
||||
If your pure function can return an error, then it will have a `(T, error)` return value in idiomatic go. In functional style the return value is [Either[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/either) because function composition is easier with such a return type. Use the `EitherizeXXX` methods in ["github.com/IBM/fp-go/either"](https://pkg.go.dev/github.com/IBM/fp-go/either) to convert from idiomatic to functional style and `UneitherizeXXX` to convert from functional to idiomatic style.
|
||||
|
||||
### Effectful functions
|
||||
|
||||
An effectful function (or function with a side effect) is one that changes data outside the scope of the function or that does not always produce the same output for the same input (because it depends on some external, mutable state). There is no special way in idiomatic go to identify such a function other than documentation. In functional style we represent them as functions that do not take an input but that produce an output. The base type for these functions is [IO[T]](./io) because in many cases such functions represent `I/O` operations.
|
||||
An effectful function (or function with a side effect) is one that changes data outside the scope of the function or that does not always produce the same output for the same input (because it depends on some external, mutable state). There is no special way in idiomatic go to identify such a function other than documentation. In functional style we represent them as functions that do not take an input but that produce an output. The base type for these functions is [IO[T]](https://pkg.go.dev/github.com/IBM/fp-go/io) because in many cases such functions represent `I/O` operations.
|
||||
|
||||
#### Without Errors
|
||||
|
||||
If your effectful function does not return an error, the functional signature is [IO[T]](./io)
|
||||
If your effectful function does not return an error, the functional signature is [IO[T]](https://pkg.go.dev/github.com/IBM/fp-go/io)
|
||||
|
||||
#### With Errors
|
||||
|
||||
If your effectful function can return an error, the functional signature is [IOEither[error, T]](./ioeither). Use `EitherizeXXX` from ["github.com/IBM/fp-go/ioeither"](./ioeither/) to convert an idiomatic go function to functional style.
|
||||
If your effectful function can return an error, the functional signature is [IOEither[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/ioeither). Use `EitherizeXXX` from ["github.com/IBM/fp-go/ioeither"](https://pkg.go.dev/github.com/IBM/fp-go/ioeither) to convert an idiomatic go function to functional style.
|
||||
|
||||
### Go Context
|
||||
|
||||
Functions that take a [context](https://pkg.go.dev/context) are per definition effectful because they depend on the context parameter that is designed to be mutable (it can e.g. be used to cancel a running operation). Furthermore in idiomatic go the parameter is typically passed as the first parameter to a function.
|
||||
|
||||
In functional style we isolate the [context](https://pkg.go.dev/context) and represent the nature of the effectful function as an [IOEither[error, T]](./ioeither). The resulting type is [ReaderIOEither[T]](./readerioeither), a function taking a [context](https://pkg.go.dev/context) that returns a function without parameters returning an [Either[error, T]](./either/). Use the `EitherizeXXX` methods from ["github.com/IBM/fp-go/context/readerioeither"](./context/readerioeither/) to convert an idiomatic go function with a [context](https://pkg.go.dev/context) to functional style.
|
||||
Functions that take a [context](https://pkg.go.dev/context) are per definition effectful because they depend on the context parameter that is designed to be mutable (it can e.g. be used to cancel a running operation). Furthermore in idiomatic go the parameter is typically passed as the first parameter to a function.
|
||||
|
||||
In functional style we isolate the [context](https://pkg.go.dev/context) and represent the nature of the effectful function as an [IOEither[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/ioeither). The resulting type is [ReaderIOEither[T]](https://pkg.go.dev/github.com/IBM/fp-go/context/readerioeither), a function taking a [context](https://pkg.go.dev/context) that returns a function without parameters returning an [Either[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/either). Use the `EitherizeXXX` methods from ["github.com/IBM/fp-go/context/readerioeither"](https://pkg.go.dev/github.com/IBM/fp-go/context/readerioeither) to convert an idiomatic go function with a [context](https://pkg.go.dev/context) to functional style.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
@@ -182,7 +183,7 @@ The `Map` operation for `ReaderIOEither` is defined as:
|
||||
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
|
||||
```
|
||||
|
||||
and in fact the equivalent operations for all other mondas follow the same pattern, we could try to introduce a new type for `ReaderIOEither` (without a parameter) as a HKT, e.g. like so (made-up syntax, does not work in go):
|
||||
and in fact the equivalent operations for all other monads follow the same pattern, we could try to introduce a new type for `ReaderIOEither` (without a parameter) as a HKT, e.g. like so (made-up syntax, does not work in go):
|
||||
|
||||
```go
|
||||
func Map[HKT, R, E, A, B any](f func(A) B) func(HKT[R, E, A]) HKT[R, E, B]
|
||||
@@ -193,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.
|
||||
|
||||
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]` |
|
||||
|
30
array/any.go
Normal file
30
array/any.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
)
|
||||
|
||||
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||
func AnyWithIndex[A any](pred func(int, A) bool) func([]A) bool {
|
||||
return G.AnyWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// Any tests if any of the elements in the array matches the predicate
|
||||
func Any[A any](pred func(A) bool) func([]A) bool {
|
||||
return G.Any[[]A](pred)
|
||||
}
|
30
array/any_test.go
Normal file
30
array/any_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
anyBool := Any(F.Identity[bool])
|
||||
|
||||
assert.True(t, anyBool(From(false, true, false)))
|
||||
assert.False(t, anyBool(From(false, false, false)))
|
||||
}
|
117
array/array.go
117
array/array.go
@@ -17,6 +17,7 @@ package array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
EM "github.com/IBM/fp-go/endomorphism"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/array"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
@@ -52,6 +53,10 @@ func MonadMapRef[A, B any](as []A, f func(a *A) B) []B {
|
||||
return bs
|
||||
}
|
||||
|
||||
func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
|
||||
return G.MapWithIndex[[]A, []B](f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(a A) B) func([]A) []B {
|
||||
return F.Bind2nd(MonadMap[A, B], f)
|
||||
}
|
||||
@@ -60,18 +65,6 @@ func MapRef[A, B any](f func(a *A) B) func([]A) []B {
|
||||
return F.Bind2nd(MonadMapRef[A, B], f)
|
||||
}
|
||||
|
||||
func filter[A any](fa []A, pred func(A) bool) []A {
|
||||
var result []A
|
||||
count := len(fa)
|
||||
for i := 0; i < count; i++ {
|
||||
a := fa[i]
|
||||
if pred(a) {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func filterRef[A any](fa []A, pred func(a *A) bool) []A {
|
||||
var result []A
|
||||
count := len(fa)
|
||||
@@ -96,22 +89,43 @@ func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
|
||||
return result
|
||||
}
|
||||
|
||||
func Filter[A any](pred func(A) bool) func([]A) []A {
|
||||
return F.Bind2nd(filter[A], pred)
|
||||
// Filter returns a new array with all elements from the original array that match a predicate
|
||||
func Filter[A any](pred func(A) bool) EM.Endomorphism[[]A] {
|
||||
return G.Filter[[]A](pred)
|
||||
}
|
||||
|
||||
func FilterRef[A any](pred func(*A) bool) func([]A) []A {
|
||||
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
|
||||
func FilterWithIndex[A any](pred func(int, A) bool) EM.Endomorphism[[]A] {
|
||||
return G.FilterWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
|
||||
return F.Bind2nd(filterRef[A], pred)
|
||||
}
|
||||
|
||||
func MonadFilterMap[A, B any](fa []A, f func(a A) O.Option[B]) []B {
|
||||
func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
|
||||
return G.MonadFilterMap[[]A, []B](fa, f)
|
||||
}
|
||||
|
||||
func FilterMap[A, B any](f func(a A) O.Option[B]) func([]A) []B {
|
||||
func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) O.Option[B]) []B {
|
||||
return G.MonadFilterMapWithIndex[[]A, []B](fa, f)
|
||||
}
|
||||
|
||||
// FilterMap maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||
func FilterMap[A, B any](f func(A) O.Option[B]) func([]A) []B {
|
||||
return G.FilterMap[[]A, []B](f)
|
||||
}
|
||||
|
||||
// FilterMapWithIndex maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
|
||||
func FilterMapWithIndex[A, B any](f func(int, A) O.Option[B]) func([]A) []B {
|
||||
return G.FilterMapWithIndex[[]A, []B](f)
|
||||
}
|
||||
|
||||
// FilterChain maps an array with an iterating function that returns an [O.Option] of an array. It keeps only the Some values discarding the Nones and then flattens the result.
|
||||
func FilterChain[A, B any](f func(A) O.Option[[]B]) func([]A) []B {
|
||||
return G.FilterChain[[]A](f)
|
||||
}
|
||||
|
||||
func FilterMapRef[A, B any](pred func(a *A) bool, f func(a *A) B) func([]A) []B {
|
||||
return func(fa []A) []B {
|
||||
return filterMapRef(fa, pred, f)
|
||||
@@ -128,9 +142,19 @@ func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
|
||||
}
|
||||
|
||||
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
|
||||
return func(as []A) B {
|
||||
return array.Reduce(as, f, initial)
|
||||
}
|
||||
return G.Reduce[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func([]A) B {
|
||||
return G.ReduceWithIndex[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRight[A, B any](f func(A, B) B, initial B) func([]A) B {
|
||||
return G.ReduceRight[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRightWithIndex[A, B any](f func(int, A, B) B, initial B) func([]A) B {
|
||||
return G.ReduceRightWithIndex[[]A](f, initial)
|
||||
}
|
||||
|
||||
func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B {
|
||||
@@ -204,7 +228,7 @@ func Last[A any](as []A) O.Option[A] {
|
||||
return G.Last(as)
|
||||
}
|
||||
|
||||
func PrependAll[A any](middle A) func([]A) []A {
|
||||
func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
|
||||
return func(as []A) []A {
|
||||
count := len(as)
|
||||
dst := count * 2
|
||||
@@ -219,7 +243,7 @@ func PrependAll[A any](middle A) func([]A) []A {
|
||||
}
|
||||
}
|
||||
|
||||
func Intersperse[A any](middle A) func([]A) []A {
|
||||
func Intersperse[A any](middle A) EM.Endomorphism[[]A] {
|
||||
prepend := PrependAll(middle)
|
||||
return func(as []A) []A {
|
||||
if IsEmpty(as) {
|
||||
@@ -237,7 +261,7 @@ func Intercalate[A any](m M.Monoid[A]) func(A) func([]A) A {
|
||||
}
|
||||
|
||||
func Flatten[A any](mma [][]A) []A {
|
||||
return MonadChain(mma, F.Identity[[]A])
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func Slice[A any](low, high int) func(as []A) []A {
|
||||
@@ -248,7 +272,7 @@ func Lookup[A any](idx int) func([]A) O.Option[A] {
|
||||
return G.Lookup[[]A](idx)
|
||||
}
|
||||
|
||||
func UpsertAt[A any](a A) func([]A) []A {
|
||||
func UpsertAt[A any](a A) EM.Endomorphism[[]A] {
|
||||
return G.UpsertAt[[]A](a)
|
||||
}
|
||||
|
||||
@@ -280,3 +304,48 @@ func IsNonNil[A any](as []A) bool {
|
||||
func ConstNil[A any]() []A {
|
||||
return array.ConstNil[[]A]()
|
||||
}
|
||||
|
||||
func SliceRight[A any](start int) EM.Endomorphism[[]A] {
|
||||
return G.SliceRight[[]A](start)
|
||||
}
|
||||
|
||||
// Copy creates a shallow copy of the array
|
||||
func Copy[A any](b []A) []A {
|
||||
return G.Copy(b)
|
||||
}
|
||||
|
||||
// Clone creates a deep copy of the array using the provided endomorphism to clone the values
|
||||
func Clone[A any](f func(A) A) func(as []A) []A {
|
||||
return G.Clone[[]A](f)
|
||||
}
|
||||
|
||||
// FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
|
||||
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
|
||||
return G.FoldMap[[]A](m)
|
||||
}
|
||||
|
||||
// FoldMapWithIndex maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
|
||||
func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func([]A) B {
|
||||
return G.FoldMapWithIndex[[]A](m)
|
||||
}
|
||||
|
||||
// Fold folds the array using the provided Monoid.
|
||||
func Fold[A any](m M.Monoid[A]) func([]A) A {
|
||||
return G.Fold[[]A](m)
|
||||
}
|
||||
|
||||
func Push[A any](a A) EM.Endomorphism[[]A] {
|
||||
return G.Push[EM.Endomorphism[[]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)
|
||||
}
|
||||
|
||||
func Prepend[A any](head A) EM.Endomorphism[[]A] {
|
||||
return G.Prepend[EM.Endomorphism[[]A]](head)
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
package array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -58,6 +59,17 @@ func TestMap(t *testing.T) {
|
||||
assert.Equal(t, dst, []string{"A", "B", "C"})
|
||||
}
|
||||
|
||||
func TestReduceRight(t *testing.T) {
|
||||
values := From("a", "b", "c")
|
||||
f := func(a, acc string) string {
|
||||
return fmt.Sprintf("%s%s", acc, a)
|
||||
}
|
||||
b := ""
|
||||
|
||||
assert.Equal(t, "cba", ReduceRight(f, b)(values))
|
||||
assert.Equal(t, "", ReduceRight(f, b)(Empty[string]()))
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
|
||||
values := MakeBy(101, F.Identity[int])
|
||||
@@ -142,3 +154,52 @@ func TestPartition(t *testing.T) {
|
||||
assert.Equal(t, T.MakeTuple2(Empty[int](), Empty[int]()), Partition(pred)(Empty[int]()))
|
||||
assert.Equal(t, T.MakeTuple2(From(1), From(3)), Partition(pred)(From(1, 3)))
|
||||
}
|
||||
|
||||
func TestFilterChain(t *testing.T) {
|
||||
src := From(1, 2, 3)
|
||||
|
||||
f := func(i int) O.Option[[]string] {
|
||||
if i%2 != 0 {
|
||||
return O.Of(From(fmt.Sprintf("a%d", i), fmt.Sprintf("b%d", i)))
|
||||
}
|
||||
return O.None[[]string]()
|
||||
}
|
||||
|
||||
res := FilterChain(f)(src)
|
||||
|
||||
assert.Equal(t, From("a1", "b1", "a3", "b3"), res)
|
||||
}
|
||||
|
||||
func TestFilterMap(t *testing.T) {
|
||||
src := From(1, 2, 3)
|
||||
|
||||
f := func(i int) O.Option[string] {
|
||||
if i%2 != 0 {
|
||||
return O.Of(fmt.Sprintf("a%d", i))
|
||||
}
|
||||
return O.None[string]()
|
||||
}
|
||||
|
||||
res := FilterMap(f)(src)
|
||||
|
||||
assert.Equal(t, From("a1", "a3"), res)
|
||||
}
|
||||
|
||||
func TestFoldMap(t *testing.T) {
|
||||
src := From("a", "b", "c")
|
||||
|
||||
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
|
||||
|
||||
assert.Equal(t, "ABC", fold(src))
|
||||
}
|
||||
|
||||
func ExampleFoldMap() {
|
||||
src := From("a", "b", "c")
|
||||
|
||||
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
|
||||
|
||||
fmt.Println(fold(src))
|
||||
|
||||
// Output: ABC
|
||||
|
||||
}
|
||||
|
77
array/example_any_test.go
Normal file
77
array/example_any_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
func Example_any() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
fmt.Println(Any(pred)(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func Example_any_filter() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
// Any tests if any of the entries in the array matches the condition
|
||||
Any := F.Flow2(
|
||||
Filter(pred),
|
||||
IsNonEmpty[int],
|
||||
)
|
||||
|
||||
fmt.Println(Any(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func Example_any_find() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
// Any tests if any of the entries in the array matches the condition
|
||||
Any := F.Flow2(
|
||||
FindFirst(pred),
|
||||
O.IsSome[int],
|
||||
)
|
||||
|
||||
fmt.Println(Any(data1))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
55
array/example_find_test.go
Normal file
55
array/example_find_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
)
|
||||
|
||||
func Example_find() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
fmt.Println(FindFirst(pred)(data1))
|
||||
|
||||
// Output:
|
||||
// Some[int](1)
|
||||
}
|
||||
|
||||
func Example_find_filter() {
|
||||
|
||||
pred := func(val int) bool {
|
||||
return val&2 == 0
|
||||
}
|
||||
|
||||
data1 := From(1, 2, 3)
|
||||
|
||||
Find := F.Flow2(
|
||||
Filter(pred),
|
||||
Head[int],
|
||||
)
|
||||
|
||||
fmt.Println(Find(data1))
|
||||
|
||||
// Output:
|
||||
// Some[int](1)
|
||||
}
|
59
array/examples_basic_test.go
Normal file
59
array/examples_basic_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// Example_basic adapts examples from [https://github.com/inato/fp-ts-cheatsheet#basic-manipulation]
|
||||
func Example_basic() {
|
||||
|
||||
someArray := From(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) // []int
|
||||
|
||||
isEven := func(num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
square := func(num int) int {
|
||||
return num * num
|
||||
}
|
||||
|
||||
// filter and map
|
||||
result := F.Pipe2(
|
||||
someArray,
|
||||
Filter(isEven),
|
||||
Map(square),
|
||||
) // [0 4 16 36 64]
|
||||
|
||||
// or in one go with filterMap
|
||||
resultFilterMap := F.Pipe1(
|
||||
someArray,
|
||||
FilterMap(
|
||||
F.Flow2(O.FromPredicate(isEven), O.Map(square)),
|
||||
),
|
||||
)
|
||||
|
||||
fmt.Println(result)
|
||||
fmt.Println(resultFilterMap)
|
||||
|
||||
// Output:
|
||||
// [0 4 16 36 64]
|
||||
// [0 4 16 36 64]
|
||||
}
|
92
array/examples_sort_test.go
Normal file
92
array/examples_sort_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
I "github.com/IBM/fp-go/number/integer"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
"github.com/IBM/fp-go/ord"
|
||||
S "github.com/IBM/fp-go/string"
|
||||
)
|
||||
|
||||
type user struct {
|
||||
name string
|
||||
age O.Option[int]
|
||||
}
|
||||
|
||||
func (user user) GetName() string {
|
||||
return user.name
|
||||
}
|
||||
|
||||
func (user user) GetAge() O.Option[int] {
|
||||
return user.age
|
||||
}
|
||||
|
||||
// Example_sort adapts examples from [https://github.com/inato/fp-ts-cheatsheet#sort-elements-with-ord]
|
||||
func Example_sort() {
|
||||
|
||||
strings := From("zyx", "abc", "klm")
|
||||
|
||||
sortedStrings := F.Pipe1(
|
||||
strings,
|
||||
Sort(S.Ord),
|
||||
) // => ['abc', 'klm', 'zyx']
|
||||
|
||||
// reverse sort
|
||||
reverseSortedStrings := F.Pipe1(
|
||||
strings,
|
||||
Sort(ord.Reverse(S.Ord)),
|
||||
) // => ['zyx', 'klm', 'abc']
|
||||
|
||||
// sort Option
|
||||
optionalNumbers := From(O.Some(1337), O.None[int](), O.Some(42))
|
||||
|
||||
sortedNums := F.Pipe1(
|
||||
optionalNumbers,
|
||||
Sort(O.Ord(I.Ord)),
|
||||
)
|
||||
|
||||
// complex object with different rules
|
||||
byName := F.Pipe1(
|
||||
S.Ord,
|
||||
ord.Contramap(user.GetName),
|
||||
) // ord.Ord[user]
|
||||
|
||||
byAge := F.Pipe1(
|
||||
O.Ord(I.Ord),
|
||||
ord.Contramap(user.GetAge),
|
||||
) // ord.Ord[user]
|
||||
|
||||
sortedUsers := F.Pipe1(
|
||||
From(user{name: "a", age: O.Of(30)}, user{name: "d", age: O.Of(10)}, user{name: "c"}, user{name: "b", age: O.Of(10)}),
|
||||
SortBy(From(byAge, byName)),
|
||||
)
|
||||
|
||||
fmt.Println(sortedStrings)
|
||||
fmt.Println(reverseSortedStrings)
|
||||
fmt.Println(sortedNums)
|
||||
fmt.Println(sortedUsers)
|
||||
|
||||
// Output:
|
||||
// [abc klm zyx]
|
||||
// [zyx klm abc]
|
||||
// [None[int] Some[int](42) Some[int](1337)]
|
||||
// [{c {false 0}} {b {true 10}} {d {true 10}} {a {true 30}}]
|
||||
|
||||
}
|
61
array/find.go
Normal file
61
array/find.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirst[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||
return G.FindFirst[[]A](pred)
|
||||
}
|
||||
|
||||
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirstWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||
return G.FindFirstWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindFirstMap[[]A](sel)
|
||||
}
|
||||
|
||||
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindFirstMapWithIndex[[]A](sel)
|
||||
}
|
||||
|
||||
// FindLast finds the Last element which satisfies a predicate (or a refinement) function
|
||||
func FindLast[A any](pred func(A) bool) func([]A) O.Option[A] {
|
||||
return G.FindLast[[]A](pred)
|
||||
}
|
||||
|
||||
// FindLastWithIndex finds the Last element which satisfies a predicate (or a refinement) function
|
||||
func FindLastWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
|
||||
return G.FindLastWithIndex[[]A](pred)
|
||||
}
|
||||
|
||||
// FindLastMap finds the Last element returned by an [O.Option] based selector function
|
||||
func FindLastMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindLastMap[[]A](sel)
|
||||
}
|
||||
|
||||
// FindLastMapWithIndex finds the Last element returned by an [O.Option] based selector function
|
||||
func FindLastMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
|
||||
return G.FindLastMapWithIndex[[]A](sel)
|
||||
}
|
34
array/generic/any.go
Normal file
34
array/generic/any.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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 (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// AnyWithIndex tests if any of the elements in the array matches the predicate
|
||||
func AnyWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) bool {
|
||||
return F.Flow2(
|
||||
FindFirstWithIndex[AS](pred),
|
||||
O.IsSome[A],
|
||||
)
|
||||
}
|
||||
|
||||
// Any tests if any of the elements in the array matches the predicate
|
||||
func Any[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) bool {
|
||||
return AnyWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
@@ -18,6 +18,8 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/array"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
"github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
@@ -27,6 +29,46 @@ func Of[GA ~[]A, A any](value A) GA {
|
||||
return GA{value}
|
||||
}
|
||||
|
||||
func Reduce[GA ~[]A, A, B any](f func(B, A) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduce[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceWithIndex[GA ~[]A, A, B any](f func(int, B, A) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceWithIndex[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceRight[GA ~[]A, A, B any](f func(A, B) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceRight[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func ReduceRightWithIndex[GA ~[]A, A, B any](f func(int, A, B) B, initial B) func(GA) B {
|
||||
return func(as GA) B {
|
||||
return MonadReduceRightWithIndex[GA](as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func MonadReduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
|
||||
return array.Reduce(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
|
||||
return array.ReduceWithIndex(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B {
|
||||
return array.ReduceRight(fa, f, initial)
|
||||
}
|
||||
|
||||
func MonadReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B {
|
||||
return array.ReduceRightWithIndex(fa, f, initial)
|
||||
}
|
||||
|
||||
// From constructs an array from a set of variadic arguments
|
||||
func From[GA ~[]A, A any](data ...A) GA {
|
||||
return data
|
||||
@@ -104,24 +146,79 @@ func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
|
||||
return array.MonadMap[GA, GB](as, f)
|
||||
}
|
||||
|
||||
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
|
||||
return F.Bind2nd(MonadMap[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
|
||||
return array.MonadMapWithIndex[GA, GB](as, f)
|
||||
}
|
||||
|
||||
func MapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) B) func(GA) GB {
|
||||
return F.Bind2nd(MonadMapWithIndex[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func Size[GA ~[]A, A any](as GA) int {
|
||||
return len(as)
|
||||
}
|
||||
|
||||
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
|
||||
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||
return array.Reduce(fa, func(bs GB, a A) GB {
|
||||
return O.MonadFold(f(a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||
}, Empty[GB]())
|
||||
}
|
||||
|
||||
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
|
||||
func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||
return array.ReduceWithIndex(fa, func(idx int, bs GB, a A) GB {
|
||||
return O.MonadFold(f(idx, a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
|
||||
}, Empty[GB]())
|
||||
}
|
||||
|
||||
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
|
||||
return filterMap[GA, GB](fa, f)
|
||||
}
|
||||
|
||||
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[B]) func(GA) GB {
|
||||
func MonadFilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
|
||||
return filterMapWithIndex[GA, GB](fa, f)
|
||||
}
|
||||
|
||||
func filterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](fa AS, pred PRED) AS {
|
||||
result := make(AS, 0, len(fa))
|
||||
for i, a := range fa {
|
||||
if pred(i, a) {
|
||||
result = append(result, a)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func FilterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) AS {
|
||||
return F.Bind2nd(filterWithIndex[AS, PRED, A], pred)
|
||||
}
|
||||
|
||||
func Filter[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) AS {
|
||||
return FilterWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
func FilterChain[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[GB]) func(GA) GB {
|
||||
return F.Flow2(
|
||||
FilterMap[GA, []GB](f),
|
||||
Flatten[[]GB],
|
||||
)
|
||||
}
|
||||
|
||||
func Flatten[GAA ~[]GA, GA ~[]A, A any](mma GAA) GA {
|
||||
return MonadChain(mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(A) O.Option[B]) func(GA) GB {
|
||||
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func FilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) O.Option[B]) func(GA) GB {
|
||||
return F.Bind2nd(MonadFilterMapWithIndex[GA, GB, A, B], f)
|
||||
}
|
||||
|
||||
func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, GA] {
|
||||
left := Empty[GA]()
|
||||
right := Empty[GA]()
|
||||
@@ -163,6 +260,14 @@ func IsEmpty[AS ~[]A, A any](as AS) bool {
|
||||
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 {
|
||||
return func(as AS) B {
|
||||
if IsEmpty(as) {
|
||||
@@ -180,3 +285,68 @@ func MatchLeft[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(A, AS) B) fu
|
||||
return onNonEmpty(as[0], as[1:])
|
||||
}
|
||||
}
|
||||
|
||||
func Slice[AS ~[]A, A any](start int, end int) func(AS) AS {
|
||||
return func(a AS) AS {
|
||||
return a[start:end]
|
||||
}
|
||||
}
|
||||
|
||||
func SliceRight[AS ~[]A, A any](start int) func(AS) AS {
|
||||
return func(a AS) AS {
|
||||
return a[start:]
|
||||
}
|
||||
}
|
||||
|
||||
func Copy[AS ~[]A, A any](b AS) AS {
|
||||
buf := make(AS, len(b))
|
||||
copy(buf, b)
|
||||
return buf
|
||||
}
|
||||
|
||||
func Clone[AS ~[]A, A any](f func(A) A) func(as AS) AS {
|
||||
// implementation assumes that map does not optimize for the empty array
|
||||
return Map[AS, AS](f)
|
||||
}
|
||||
|
||||
func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
|
||||
return func(f func(A) B) func(AS) B {
|
||||
return func(as AS) B {
|
||||
return array.Reduce(as, func(cur B, a A) B {
|
||||
return m.Concat(cur, f(a))
|
||||
}, m.Empty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func FoldMapWithIndex[AS ~[]A, A, B any](m M.Monoid[B]) func(func(int, A) B) func(AS) B {
|
||||
return func(f func(int, A) B) func(AS) B {
|
||||
return func(as AS) B {
|
||||
return array.ReduceWithIndex(as, func(idx int, cur B, a A) B {
|
||||
return m.Concat(cur, f(idx, a))
|
||||
}, m.Empty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
|
||||
return func(as AS) A {
|
||||
return array.Reduce(as, m.Concat, m.Empty())
|
||||
}
|
||||
}
|
||||
|
||||
func Push[ENDO ~func(GA) GA, GA ~[]A, A any](a A) ENDO {
|
||||
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)
|
||||
}
|
||||
|
||||
func Prepend[ENDO ~func(AS) AS, AS []A, A any](head A) ENDO {
|
||||
return array.Prepend[ENDO](head)
|
||||
}
|
||||
|
97
array/generic/find.go
Normal file
97
array/generic/find.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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 (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirstWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
none := O.None[A]()
|
||||
return func(as AS) O.Option[A] {
|
||||
for i, a := range as {
|
||||
if pred(i, a) {
|
||||
return O.Some(a)
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindFirst[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
return FindFirstWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
none := O.None[B]()
|
||||
return func(as AS) O.Option[B] {
|
||||
count := len(as)
|
||||
for i := 0; i < count; i++ {
|
||||
out := pred(i, as[i])
|
||||
if O.IsSome(out) {
|
||||
return out
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindFirstMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindFirstMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
return FindFirstMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindLastWithIndex finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindLastWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
none := O.None[A]()
|
||||
return func(as AS) O.Option[A] {
|
||||
for i := len(as) - 1; i >= 0; i-- {
|
||||
a := as[i]
|
||||
if pred(i, a) {
|
||||
return O.Some(a)
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindLast finds the first element which satisfies a predicate (or a refinement) function
|
||||
func FindLast[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
|
||||
return FindLastWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
||||
|
||||
// FindLastMapWithIndex finds the first element returned by an [O.Option] based selector function
|
||||
func FindLastMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
none := O.None[B]()
|
||||
return func(as AS) O.Option[B] {
|
||||
for i := len(as) - 1; i >= 0; i-- {
|
||||
out := pred(i, as[i])
|
||||
if O.IsSome(out) {
|
||||
return out
|
||||
}
|
||||
}
|
||||
return none
|
||||
}
|
||||
}
|
||||
|
||||
// FindLastMap finds the first element returned by an [O.Option] based selector function
|
||||
func FindLastMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
|
||||
return FindLastMapWithIndex[AS](F.Ignore1of2[int](pred))
|
||||
}
|
@@ -18,11 +18,17 @@ package generic
|
||||
import (
|
||||
"sort"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
O "github.com/IBM/fp-go/ord"
|
||||
)
|
||||
|
||||
// Sort implements a stable sort on the array given the provided ordering
|
||||
func Sort[GA ~[]T, T any](ord O.Ord[T]) func(ma GA) GA {
|
||||
return SortByKey[GA](ord, F.Identity[T])
|
||||
}
|
||||
|
||||
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
|
||||
func SortByKey[GA ~[]T, K, T any](ord O.Ord[K], f func(T) K) func(ma GA) GA {
|
||||
|
||||
return func(ma GA) GA {
|
||||
// nothing to sort
|
||||
@@ -34,8 +40,17 @@ func Sort[GA ~[]T, T any](ord O.Ord[T]) func(ma GA) GA {
|
||||
cpy := make(GA, l)
|
||||
copy(cpy, ma)
|
||||
sort.Slice(cpy, func(i, j int) bool {
|
||||
return ord.Compare(cpy[i], cpy[j]) < 0
|
||||
return ord.Compare(f(cpy[i]), f(cpy[j])) < 0
|
||||
})
|
||||
return cpy
|
||||
}
|
||||
}
|
||||
|
||||
// SortBy implements a stable sort on the array given the provided ordering
|
||||
func SortBy[GA ~[]T, GO ~[]O.Ord[T], T any](ord GO) func(ma GA) GA {
|
||||
return F.Pipe2(
|
||||
ord,
|
||||
Fold[GO](O.Monoid[T]()),
|
||||
Sort[GA, T],
|
||||
)
|
||||
}
|
||||
|
32
array/generic/uniq.go
Normal file
32
array/generic/uniq.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package generic
|
||||
|
||||
import F "github.com/IBM/fp-go/function"
|
||||
|
||||
// StrictUniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined by the built-in uniqueness constraint
|
||||
func StrictUniq[AS ~[]A, A comparable](as AS) AS {
|
||||
return Uniq[AS](F.Identity[A])(as)
|
||||
}
|
||||
|
||||
// uniquePredUnsafe returns a predicate on a map for uniqueness
|
||||
func uniquePredUnsafe[PRED ~func(A) K, A any, K comparable](f PRED) func(int, A) bool {
|
||||
lookup := make(map[K]bool)
|
||||
return func(_ int, a A) bool {
|
||||
k := f(a)
|
||||
_, has := lookup[k]
|
||||
if has {
|
||||
return false
|
||||
}
|
||||
lookup[k] = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Uniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined based on a key extractor function
|
||||
func Uniq[AS ~[]A, PRED ~func(A) K, A any, K comparable](f PRED) func(as AS) AS {
|
||||
return func(as AS) AS {
|
||||
// we need to create a new predicate for each iteration
|
||||
return filterWithIndex(as, uniquePredUnsafe(f))
|
||||
}
|
||||
}
|
52
array/generic/zip.go
Normal file
52
array/generic/zip.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 generic
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
N "github.com/IBM/fp-go/number"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
|
||||
// input array is short, excess elements of the longer array are discarded.
|
||||
func ZipWith[AS ~[]A, BS ~[]B, CS ~[]C, FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
|
||||
l := N.Min(len(fa), len(fb))
|
||||
res := make(CS, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
res[i] = f(fa[i], fb[i])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
|
||||
// longer array are discarded
|
||||
func Zip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](fb BS) func(AS) CS {
|
||||
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) T.Tuple2[A, B]])(fb, T.MakeTuple2[A, B])
|
||||
}
|
||||
|
||||
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
|
||||
func Unzip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](cs CS) T.Tuple2[AS, BS] {
|
||||
l := len(cs)
|
||||
as := make(AS, l)
|
||||
bs := make(BS, l)
|
||||
for i := l - 1; i >= 0; i-- {
|
||||
t := cs[i]
|
||||
as[i] = t.F1
|
||||
bs[i] = t.F2
|
||||
}
|
||||
return T.MakeTuple2(as, bs)
|
||||
}
|
@@ -18,15 +18,16 @@ package array
|
||||
import (
|
||||
"github.com/IBM/fp-go/internal/array"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
func concat[T any](left, right []T) []T {
|
||||
// some performance checks
|
||||
ll := len(left)
|
||||
lr := len(right)
|
||||
if ll == 0 {
|
||||
return right
|
||||
}
|
||||
lr := len(right)
|
||||
if lr == 0 {
|
||||
return left
|
||||
}
|
||||
@@ -40,6 +41,10 @@ func Monoid[T any]() M.Monoid[[]T] {
|
||||
return M.MakeMonoid(concat[T], Empty[T]())
|
||||
}
|
||||
|
||||
func Semigroup[T any]() S.Semigroup[[]T] {
|
||||
return S.MakeSemigroup(concat[T])
|
||||
}
|
||||
|
||||
func addLen[A any](count int, data []A) int {
|
||||
return count + len(data)
|
||||
}
|
||||
|
136
array/nonempty/array.go
Normal file
136
array/nonempty/array.go
Normal file
@@ -0,0 +1,136 @@
|
||||
// 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"
|
||||
EM "github.com/IBM/fp-go/endomorphism"
|
||||
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 ReduceRight[A, B any](f func(A, B) B, initial B) func(NonEmptyArray[A]) B {
|
||||
return func(as NonEmptyArray[A]) B {
|
||||
return array.ReduceRight(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))
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend prepends a single value to an array
|
||||
func Prepend[A any](head A) EM.Endomorphism[NonEmptyArray[A]] {
|
||||
return array.Prepend[EM.Endomorphism[NonEmptyArray[A]]](head)
|
||||
}
|
@@ -24,3 +24,13 @@ import (
|
||||
func Sort[T any](ord O.Ord[T]) func(ma []T) []T {
|
||||
return G.Sort[[]T](ord)
|
||||
}
|
||||
|
||||
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
|
||||
func SortByKey[K, T any](ord O.Ord[K], f func(T) K) func(ma []T) []T {
|
||||
return G.SortByKey[[]T](ord, f)
|
||||
}
|
||||
|
||||
// SortBy implements a stable sort on the array given the provided ordering
|
||||
func SortBy[T any](ord []O.Ord[T]) func(ma []T) []T {
|
||||
return G.SortBy[[]T, []O.Ord[T]](ord)
|
||||
}
|
||||
|
17
array/uniq.go
Normal file
17
array/uniq.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
)
|
||||
|
||||
// StrictUniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined by the built-in uniqueness constraint
|
||||
func StrictUniq[A comparable](as []A) []A {
|
||||
return G.StrictUniq[[]A](as)
|
||||
}
|
||||
|
||||
// Uniq converts an array of arbitrary items into an array or unique items
|
||||
// where uniqueness is determined based on a key extractor function
|
||||
func Uniq[A any, K comparable](f func(A) K) func(as []A) []A {
|
||||
return G.Uniq[[]A](f)
|
||||
}
|
14
array/uniq_test.go
Normal file
14
array/uniq_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package array
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUniq(t *testing.T) {
|
||||
data := From(1, 2, 3, 2, 4, 1)
|
||||
|
||||
uniq := StrictUniq(data)
|
||||
assert.Equal(t, From(1, 2, 3, 4), uniq)
|
||||
}
|
38
array/zip.go
Normal file
38
array/zip.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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 array
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
|
||||
// input array is short, excess elements of the longer array are discarded.
|
||||
func ZipWith[FCT ~func(A, B) C, A, B, C any](fa []A, fb []B, f FCT) []C {
|
||||
return G.ZipWith[[]A, []B, []C, FCT](fa, fb, f)
|
||||
}
|
||||
|
||||
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
|
||||
// longer array are discarded
|
||||
func Zip[A, B any](fb []B) func([]A) []T.Tuple2[A, B] {
|
||||
return G.Zip[[]A, []B, []T.Tuple2[A, B]](fb)
|
||||
}
|
||||
|
||||
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
|
||||
func Unzip[A, B any](cs []T.Tuple2[A, B]) T.Tuple2[[]A, []B] {
|
||||
return G.Unzip[[]A, []B, []T.Tuple2[A, B]](cs)
|
||||
}
|
56
array/zip_test.go
Normal file
56
array/zip_test.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 array
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestZipWith(t *testing.T) {
|
||||
left := From(1, 2, 3)
|
||||
right := From("a", "b", "c", "d")
|
||||
|
||||
res := ZipWith(left, right, func(l int, r string) string {
|
||||
return fmt.Sprintf("%s%d", r, l)
|
||||
})
|
||||
|
||||
assert.Equal(t, From("a1", "b2", "c3"), res)
|
||||
}
|
||||
|
||||
func TestZip(t *testing.T) {
|
||||
left := From(1, 2, 3)
|
||||
right := From("a", "b", "c", "d")
|
||||
|
||||
res := Zip[string](left)(right)
|
||||
|
||||
assert.Equal(t, From(T.MakeTuple2("a", 1), T.MakeTuple2("b", 2), T.MakeTuple2("c", 3)), res)
|
||||
}
|
||||
|
||||
func TestUnzip(t *testing.T) {
|
||||
left := From(1, 2, 3)
|
||||
right := From("a", "b", "c")
|
||||
|
||||
zipped := Zip[string](left)(right)
|
||||
|
||||
unzipped := Unzip(zipped)
|
||||
|
||||
assert.Equal(t, right, unzipped.F1)
|
||||
assert.Equal(t, left, unzipped.F2)
|
||||
}
|
109
assert/assert_test.go
Normal file
109
assert/assert_test.go
Normal file
@@ -0,0 +1,109 @@
|
||||
// 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 assert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
errTest = fmt.Errorf("test failure")
|
||||
|
||||
// Eq is the equal predicate checking if objects are equal
|
||||
Eq = EQ.FromEquals(assert.ObjectsAreEqual)
|
||||
)
|
||||
|
||||
func wrap1[T any](wrapped func(t assert.TestingT, expected, actual any, msgAndArgs ...any) bool, t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return func(actual T) E.Either[error, T] {
|
||||
ok := wrapped(t, expected, actual)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NotEqual tests if the expected and the actual values are not equal
|
||||
func NotEqual[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return wrap1(assert.NotEqual, t, expected)
|
||||
}
|
||||
|
||||
// Equal tests if the expected and the actual values are equal
|
||||
func Equal[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return wrap1(assert.Equal, t, expected)
|
||||
}
|
||||
|
||||
// Length tests if an array has the expected length
|
||||
func Length[T any](t *testing.T, expected int) func(actual []T) E.Either[error, []T] {
|
||||
return func(actual []T) E.Either[error, []T] {
|
||||
ok := assert.Len(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[[]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NoError validates that there is no error
|
||||
func NoError[T any](t *testing.T) func(actual E.Either[error, T]) E.Either[error, T] {
|
||||
return func(actual E.Either[error, T]) E.Either[error, T] {
|
||||
return E.MonadFold(actual, func(e error) E.Either[error, T] {
|
||||
assert.NoError(t, e)
|
||||
return E.Left[T](e)
|
||||
}, func(value T) E.Either[error, T] {
|
||||
assert.NoError(t, nil)
|
||||
return E.Right[error](value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ArrayContains tests if a value is contained in an array
|
||||
func ArrayContains[T any](t *testing.T, expected T) func(actual []T) E.Either[error, []T] {
|
||||
return func(actual []T) E.Either[error, []T] {
|
||||
ok := assert.Contains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[[]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsKey tests if a key is contained in a map
|
||||
func ContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
return func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
ok := assert.Contains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[map[K]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NotContainsKey tests if a key is not contained in a map
|
||||
func NotContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
return func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
ok := assert.NotContains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[map[K]T](errTest)
|
||||
}
|
||||
}
|
59
boolean/boolean.go
Normal file
59
boolean/boolean.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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 boolean
|
||||
|
||||
import (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/ord"
|
||||
)
|
||||
|
||||
var (
|
||||
// MonoidAny is the boolean [M.Monoid] under disjunction
|
||||
MonoidAny = M.MakeMonoid(
|
||||
func(l, r bool) bool {
|
||||
return l || r
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
// MonoidAll is the boolean [M.Monoid] under conjuction
|
||||
MonoidAll = M.MakeMonoid(
|
||||
func(l, r bool) bool {
|
||||
return l && r
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
// Eq is the equals predicate for boolean
|
||||
Eq = EQ.FromStrictEquals[bool]()
|
||||
|
||||
// Ord is the strict ordering for boolean
|
||||
Ord = O.MakeOrd(func(l, r bool) int {
|
||||
if l {
|
||||
if r {
|
||||
return 0
|
||||
}
|
||||
return +1
|
||||
}
|
||||
if r {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}, func(l, r bool) bool {
|
||||
return l == r
|
||||
})
|
||||
)
|
@@ -388,7 +388,7 @@ func generateApplyHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
@@ -266,7 +266,7 @@ func generateBindHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n", pkg)
|
||||
|
||||
|
@@ -34,5 +34,6 @@ func Commands() []*C.Command {
|
||||
IOEitherCommand(),
|
||||
IOCommand(),
|
||||
IOOptionCommand(),
|
||||
DICommand(),
|
||||
}
|
||||
}
|
||||
|
231
cli/di.go
Normal file
231
cli/di.go
Normal file
@@ -0,0 +1,231 @@
|
||||
// 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 cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
C "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func generateMakeProvider(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// MakeProvider%d creates a [DIE.Provider] for an [InjectionToken] from a function with %d dependencies\n", i, i)
|
||||
fmt.Fprintf(f, "func MakeProvider%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
fmt.Fprintf(f, " token InjectionToken[R],\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||
fmt.Fprintf(f, ") DIE.Provider {\n")
|
||||
fmt.Fprint(f, " return DIE.MakeProvider(\n")
|
||||
fmt.Fprint(f, " token,\n")
|
||||
fmt.Fprintf(f, " MakeProviderFactory%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " f,\n")
|
||||
fmt.Fprint(f, " ))\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateMakeTokenWithDefault(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// MakeTokenWithDefault%d creates an [InjectionToken] with a default implementation with %d dependencies\n", i, i)
|
||||
fmt.Fprintf(f, "func MakeTokenWithDefault%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
fmt.Fprintf(f, " name string,\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||
fmt.Fprintf(f, ") InjectionToken[R] {\n")
|
||||
fmt.Fprintf(f, " return MakeTokenWithDefault[R](name, MakeProviderFactory%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " f,\n")
|
||||
fmt.Fprint(f, " ))\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateMakeProviderFactory(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// MakeProviderFactory%d creates a [DIE.ProviderFactory] from a function with %d arguments and %d dependencies\n", i, i, i)
|
||||
fmt.Fprintf(f, "func MakeProviderFactory%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
|
||||
fmt.Fprintf(f, ") DIE.ProviderFactory {\n")
|
||||
fmt.Fprint(f, " return DIE.MakeProviderFactory(\n")
|
||||
fmt.Fprint(f, " A.From[DIE.Dependency](\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " ),\n")
|
||||
fmt.Fprintf(f, " eraseProviderFactory%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d,\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " f,\n")
|
||||
fmt.Fprint(f, " ),\n")
|
||||
fmt.Fprint(f, " )\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateEraseProviderFactory(f *os.File, i int) {
|
||||
// non generic version
|
||||
fmt.Fprintf(f, "\n// eraseProviderFactory%d creates a function that takes a variadic number of untyped arguments and from a function of %d strongly typed arguments and %d dependencies\n", i, i, i)
|
||||
fmt.Fprintf(f, "func eraseProviderFactory%d[", i)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any, R any](\n")
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " f func(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ") IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {\n")
|
||||
fmt.Fprintf(f, " ft := eraseTuple(T.Tupled%d(f))\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d := lookupAt[T%d](%d, d%d)\n", j+1, j+1, j, j+1)
|
||||
}
|
||||
fmt.Fprint(f, " return func(params ...any) IOE.IOEither[error, any] {\n")
|
||||
fmt.Fprintf(f, " return ft(E.SequenceT%d(\n", i)
|
||||
for j := 0; j < i; j++ {
|
||||
fmt.Fprintf(f, " t%d(params),\n", j+1)
|
||||
}
|
||||
fmt.Fprint(f, " ))\n")
|
||||
fmt.Fprint(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateDIHelpers(filename string, count int) error {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
absDir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pkg := filepath.Base(absDir)
|
||||
f, err := os.Create(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
// log
|
||||
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
|
||||
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
fmt.Fprint(f, `
|
||||
import (
|
||||
E "github.com/IBM/fp-go/either"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
A "github.com/IBM/fp-go/array"
|
||||
DIE "github.com/IBM/fp-go/di/erasure"
|
||||
)
|
||||
`)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
generateEraseProviderFactory(f, i)
|
||||
generateMakeProviderFactory(f, i)
|
||||
generateMakeTokenWithDefault(f, i)
|
||||
generateMakeProvider(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DICommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "di",
|
||||
Usage: "generate code for the dependency injection package",
|
||||
Flags: []C.Flag{
|
||||
flagCount,
|
||||
flagFilename,
|
||||
},
|
||||
Action: func(ctx *C.Context) error {
|
||||
return generateDIHelpers(
|
||||
ctx.String(keyFilename),
|
||||
ctx.Int(keyCount),
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
@@ -115,16 +115,14 @@ func generateEitherize(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") Either[error, R] {\n")
|
||||
fmt.Fprintf(f, " return TryCatchError(func() (R, error) {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
fmt.Fprintf(f, " return TryCatchError(f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
fmt.Fprintln(f, ")")
|
||||
fmt.Fprintln(f, " })")
|
||||
fmt.Fprintln(f, "))")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
@@ -150,7 +148,7 @@ func generateEitherHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
@@ -27,5 +27,5 @@ func writePackage(f *os.File, pkg string) {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ func generateIdentityHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
@@ -81,7 +81,7 @@ func generateIOHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
@@ -217,7 +217,7 @@ func generateIOEitherHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
@@ -81,7 +81,7 @@ func generateIOOptionHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
@@ -148,7 +148,7 @@ func generateOptionHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
72
cli/pipe.go
72
cli/pipe.go
@@ -25,6 +25,40 @@ import (
|
||||
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) {
|
||||
// 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)
|
||||
@@ -83,7 +117,7 @@ func generateVariadic(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "v)\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
|
||||
fmt.Fprintf(f, "}")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
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, " }\n")
|
||||
|
||||
fmt.Fprintf(f, "}")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateNullary(f *os.File, i int) {
|
||||
@@ -261,15 +295,16 @@ func recurseCurry(f *os.File, indent string, total, count int) {
|
||||
func generateCurry(f *os.File, i int) {
|
||||
// Create the curry version
|
||||
fmt.Fprintf(f, "\n// Curry%d takes a function with %d parameters and returns a cascade of functions each taking only one parameter.\n// The inverse function is [Uncurry%d]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func Curry%d[T0", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, "func Curry%d[FCT ~func(T0", i)
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](f func(T0")
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j-1)
|
||||
fmt.Fprintf(f, ") T%d", i)
|
||||
// type arguments
|
||||
for j := 0; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ") T%d) func(T0)", i)
|
||||
fmt.Fprintf(f, " any](f FCT) func(T0)")
|
||||
for j := 2; j <= i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j-1)
|
||||
}
|
||||
@@ -281,15 +316,16 @@ func generateCurry(f *os.File, i int) {
|
||||
func generateUncurry(f *os.File, i int) {
|
||||
// Create the uncurry version
|
||||
fmt.Fprintf(f, "\n// Uncurry%d takes a cascade of %d functions each taking only one parameter and returns a function with %d parameters .\n// The inverse function is [Curry%d]\n", i, i, i, i)
|
||||
fmt.Fprintf(f, "func Uncurry%d[T0", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, "func Uncurry%d[FCT ~func(T0)", i)
|
||||
for j := 1; j < i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j)
|
||||
}
|
||||
fmt.Fprintf(f, " T%d", i)
|
||||
// the type parameters
|
||||
for j := 0; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, " any](f")
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " func(T%d)", j-1)
|
||||
}
|
||||
fmt.Fprintf(f, " T%d) func(", i)
|
||||
fmt.Fprintf(f, " any](f FCT) func(")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
@@ -337,7 +373,7 @@ func generatePipeHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n", pkg)
|
||||
|
||||
@@ -347,6 +383,8 @@ func generatePipeHelpers(filename string, count int) error {
|
||||
generateVariadic(f, 0)
|
||||
// unvariadic
|
||||
generateUnvariadic(f, 0)
|
||||
// unsliced
|
||||
generateUnsliced(f, 0)
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
|
||||
@@ -364,6 +402,8 @@ func generatePipeHelpers(filename string, count int) error {
|
||||
generateVariadic(f, i)
|
||||
// unvariadic
|
||||
generateUnvariadic(f, i)
|
||||
// unsliced
|
||||
generateUnsliced(f, i)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -12,6 +12,7 @@
|
||||
// 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 cli
|
||||
|
||||
import (
|
||||
@@ -117,7 +118,7 @@ func generateReaderHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
@@ -169,7 +169,7 @@ func generateReaderIOEitherHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
|
250
cli/tuple.go
250
cli/tuple.go
@@ -20,6 +20,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
C "github.com/urfave/cli/v2"
|
||||
@@ -36,8 +37,51 @@ func writeTupleType(f *os.File, symbol string, i int) {
|
||||
fmt.Fprintf(f, "]")
|
||||
}
|
||||
|
||||
func makeTupleType(name string) func(i int) string {
|
||||
return func(i int) string {
|
||||
var buf strings.Builder
|
||||
buf.WriteString(fmt.Sprintf("Tuple%d[", i))
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
|
||||
}
|
||||
buf.WriteString("]")
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
func generatePush(f *os.File, i int) {
|
||||
tuple1 := makeTupleType("T")(i)
|
||||
tuple2 := makeTupleType("T")(i + 1)
|
||||
// Create the replicate version
|
||||
fmt.Fprintf(f, "\n// Push%d creates a [Tuple%d] from a [Tuple%d] by appending a constant value\n", i, i+1, i)
|
||||
fmt.Fprintf(f, "func Push%d[", i)
|
||||
// function prototypes
|
||||
for j := 0; j <= i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "T%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, " any](value T%d) func(%s) %s {\n", i+1, tuple1, tuple2)
|
||||
fmt.Fprintf(f, " return func(t %s) %s {\n", tuple1, tuple2)
|
||||
fmt.Fprintf(f, " return MakeTuple%d(", i+1)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j+1)
|
||||
}
|
||||
fmt.Fprintf(f, ", value)\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateReplicate(f *os.File, i int) {
|
||||
// Create the optionize version
|
||||
// Create the replicate version
|
||||
fmt.Fprintf(f, "\n// Replicate%d creates a [Tuple%d] with all fields set to the input value `t`\n", i, i)
|
||||
fmt.Fprintf(f, "func Replicate%d[T any](t T) Tuple%d[", i, i)
|
||||
for j := 1; j <= i; j++ {
|
||||
@@ -294,7 +338,7 @@ func generateUntupled(f *os.File, i int) {
|
||||
|
||||
func generateTupled(f *os.File, i int) {
|
||||
// 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)
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
@@ -355,14 +399,16 @@ func generateTupleHelpers(filename string, count int) error {
|
||||
// some header
|
||||
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
|
||||
fmt.Fprintln(f, "// This file was generated by robots at")
|
||||
fmt.Fprintf(f, "// %s\n", time.Now())
|
||||
fmt.Fprintf(f, "// %s\n\n", time.Now())
|
||||
|
||||
fmt.Fprintf(f, "package %s\n\n", pkg)
|
||||
|
||||
fmt.Fprintf(f, `
|
||||
import (
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/ord"
|
||||
O "github.com/IBM/fp-go/ord"
|
||||
)
|
||||
`)
|
||||
|
||||
@@ -386,11 +432,207 @@ import (
|
||||
generateMap(f, i)
|
||||
// generate replicate
|
||||
generateReplicate(f, i)
|
||||
// generate tuple functions such as string and fmt
|
||||
generateTupleString(f, i)
|
||||
// generate json support
|
||||
generateTupleMarshal(f, i)
|
||||
// generate json support
|
||||
generateTupleUnmarshal(f, i)
|
||||
// generate toArray
|
||||
generateToArray(f, i)
|
||||
// generate fromArray
|
||||
generateFromArray(f, i)
|
||||
// generate push
|
||||
if i < count {
|
||||
generatePush(f, i)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateTupleMarshal(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// MarshalJSON marshals the [Tuple%d] into a JSON array\n", i)
|
||||
fmt.Fprintf(f, "func (t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
|
||||
fmt.Fprintf(f, " return json.Marshal([]any{")
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, "})\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateTupleUnmarshal(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// UnmarshalJSON unmarshals a JSON array into a [Tuple%d]\n", i)
|
||||
fmt.Fprintf(f, "func (t *")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") UnmarshalJSON(data []byte) error {\n")
|
||||
fmt.Fprintf(f, " var tmp []json.RawMessage\n")
|
||||
fmt.Fprintf(f, " if err := json.Unmarshal(data, &tmp); err != nil {return err}\n")
|
||||
fmt.Fprintf(f, " l := len(tmp)\n")
|
||||
// unmarshal fields
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " if l > %d {\n", j-1)
|
||||
fmt.Fprintf(f, " if err := json.Unmarshal(tmp[%d], &t.F%d); err != nil {return err}\n", j-1, j)
|
||||
}
|
||||
fmt.Fprintf(f, " ")
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, "}")
|
||||
}
|
||||
fmt.Fprintf(f, "\n return nil\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateToArray(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// ToArray converts the [Tuple%d] into an array of type [R] using %d transformation functions from [T] to [R]\n// The inverse function is [FromArray%d]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func ToArray%d[", i)
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(T%d) R", j, j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") []R {\n")
|
||||
fmt.Fprintf(f, " return func(t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") []R {\n")
|
||||
fmt.Fprintf(f, " return []R{\n")
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " f%d(t.F%d),\n", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateFromArray(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// FromArray converts an array of [R] into a [Tuple%d] using %d functions from [R] to [T]\n// The inverse function is [ToArray%d]\n", i, i, i)
|
||||
fmt.Fprintf(f, "func FromArray%d[", i)
|
||||
// function prototypes
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "F%d ~func(R) T%d", j, j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", T%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ", R any](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "f%d F%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") func(r []R) ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, " {\n")
|
||||
fmt.Fprintf(f, " return func(r []R) ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, " {\n")
|
||||
fmt.Fprintf(f, " return MakeTuple%d(\n", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, " f%d(r[%d]),\n", j, j-1)
|
||||
}
|
||||
fmt.Fprintf(f, " )\n")
|
||||
fmt.Fprintf(f, " }\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
func generateTupleString(f *os.File, i int) {
|
||||
// Create the stringify version
|
||||
fmt.Fprintf(f, "\n// String prints some debug info for the [Tuple%d]\n", i)
|
||||
fmt.Fprintf(f, "func (t ")
|
||||
writeTupleType(f, "T", i)
|
||||
fmt.Fprintf(f, ") String() string {\n")
|
||||
// convert to string
|
||||
fmt.Fprintf(f, " return fmt.Sprintf(\"Tuple%d[", i)
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", "%T")
|
||||
}
|
||||
fmt.Fprintf(f, "](")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "%s", "%v")
|
||||
}
|
||||
fmt.Fprintf(f, ")\", ")
|
||||
for j := 1; j <= i; j++ {
|
||||
if j > 1 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t.F%d", j)
|
||||
}
|
||||
for j := 1; j <= i; j++ {
|
||||
fmt.Fprintf(f, ", t.F%d", j)
|
||||
}
|
||||
fmt.Fprintf(f, ")\n")
|
||||
fmt.Fprintf(f, "}\n")
|
||||
}
|
||||
|
||||
// func generateTupleJson(f *os.File, i int) {
|
||||
// // Create the stringify version
|
||||
// fmt.Fprintf(f, "\n// MarshalJSON converts the [Tuple%d] into a JSON byte stream\n", i)
|
||||
// fmt.Fprintf(f, "func (t ")
|
||||
// writeTupleType(f, "T", i)
|
||||
// fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
|
||||
// // convert to string
|
||||
// fmt.Fprintf(f, " return fmt.Sprintf(\"Tuple%d[", i)
|
||||
// for j := 1; j <= i; j++ {
|
||||
// if j > 1 {
|
||||
// fmt.Fprintf(f, ", ")
|
||||
// }
|
||||
// fmt.Fprintf(f, "%s", "%T")
|
||||
// }
|
||||
// fmt.Fprintf(f, "](")
|
||||
// for j := 1; j <= i; j++ {
|
||||
// if j > 1 {
|
||||
// fmt.Fprintf(f, ", ")
|
||||
// }
|
||||
// fmt.Fprintf(f, "%s", "%v")
|
||||
// }
|
||||
// fmt.Fprintf(f, ")\", ")
|
||||
// for j := 1; j <= i; j++ {
|
||||
// if j > 1 {
|
||||
// fmt.Fprintf(f, ", ")
|
||||
// }
|
||||
// fmt.Fprintf(f, "t.F%d", j)
|
||||
// }
|
||||
// for j := 1; j <= i; j++ {
|
||||
// fmt.Fprintf(f, ", t.F%d", j)
|
||||
// }
|
||||
// fmt.Fprintf(f, ")\n")
|
||||
// fmt.Fprintf(f, "}\n")
|
||||
// }
|
||||
|
||||
func TupleCommand() *C.Command {
|
||||
return &C.Command{
|
||||
Name: "tuple",
|
||||
|
@@ -22,30 +22,28 @@ import (
|
||||
)
|
||||
|
||||
type Const[E, A any] struct {
|
||||
Value E
|
||||
value E
|
||||
}
|
||||
|
||||
func Make[E, A any](e E) Const[E, A] {
|
||||
return Const[E, A]{Value: e}
|
||||
return Const[E, A]{value: e}
|
||||
}
|
||||
|
||||
func Unwrap[E, A any](c Const[E, A]) E {
|
||||
return c.Value
|
||||
return c.value
|
||||
}
|
||||
|
||||
func Of[E, A any](m M.Monoid[E]) func(A) Const[E, A] {
|
||||
return func(a A) Const[E, A] {
|
||||
return Make[E, A](m.Empty())
|
||||
}
|
||||
return F.Constant1[A](Make[E, A](m.Empty()))
|
||||
}
|
||||
|
||||
func MonadMap[E, A, B any](fa Const[E, A], f func(A) B) Const[E, B] {
|
||||
return Make[E, B](fa.Value)
|
||||
return Make[E, B](fa.value)
|
||||
}
|
||||
|
||||
func MonadAp[E, A, B any](s S.Semigroup[E]) func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] {
|
||||
return func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] {
|
||||
return Make[E, B](s.Concat(fab.Value, fa.Value))
|
||||
return Make[E, B](s.Concat(fab.value, fa.value))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,15 +19,14 @@ import (
|
||||
"context"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
IOE "github.com/IBM/fp-go/ioeither/generic"
|
||||
)
|
||||
|
||||
// withContext wraps an existing IOEither and performs a context check for cancellation before delegating
|
||||
// WithContext wraps an existing IOEither and performs a context check for cancellation before delegating
|
||||
func WithContext[GIO ~func() E.Either[error, A], A any](ctx context.Context, ma GIO) GIO {
|
||||
return IOE.MakeIO[GIO](func() E.Either[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return ET.Left[A](err)
|
||||
return E.Left[A](err)
|
||||
}
|
||||
return ma()
|
||||
})
|
||||
|
@@ -1,53 +0,0 @@
|
||||
// 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 reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[A any](f func(context.Context) A) Reader[A] {
|
||||
return R.Curry0[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
|
||||
return R.Curry1[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1) func(T2) Reader[A] {
|
||||
return R.Curry2[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1) func(T2) func(T3) Reader[A] {
|
||||
return R.Curry3[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Uncurry1[T1, A any](f func(T1) Reader[A]) func(context.Context, T1) A {
|
||||
return R.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[T1, T2, A any](f func(T1) func(T2) Reader[A]) func(context.Context, T1, T2) A {
|
||||
return R.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[T1, T2, T3, A any](f func(T1) func(T2) func(T3) Reader[A]) func(context.Context, T1, T2, T3) A {
|
||||
return R.Uncurry3(f)
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
// 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 reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) A) func() Reader[A] {
|
||||
return R.From0[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
|
||||
return R.From1[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1, T2) Reader[A] {
|
||||
return R.From2[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1, T2, T3) Reader[A] {
|
||||
return R.From3[Reader[A]](f)
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
// 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 reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func MonadMap[A, B any](fa Reader[A], f func(A) B) Reader[B] {
|
||||
return R.MonadMap[Reader[A], Reader[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(Reader[A]) Reader[B] {
|
||||
return R.Map[Reader[A], Reader[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma Reader[A], f func(A) Reader[B]) Reader[B] {
|
||||
return R.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) Reader[B]) func(Reader[A]) Reader[B] {
|
||||
return R.Chain[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) Reader[A] {
|
||||
return R.Of[Reader[A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab Reader[func(A) B], fa Reader[A]) Reader[B] {
|
||||
return R.MonadAp[Reader[A], Reader[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa Reader[A]) func(Reader[func(A) B]) Reader[B] {
|
||||
return R.Ap[Reader[A], Reader[B], Reader[func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Ask() Reader[context.Context] {
|
||||
return R.Ask[Reader[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r Reader[A]) Reader[A] {
|
||||
return R.Asks(r)
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
// 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 reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func GoFunction(ctx context.Context, data string) string {
|
||||
return strings.ToUpper(data)
|
||||
}
|
||||
|
||||
func GoIntFunction(ctx context.Context, data string, number int) string {
|
||||
return fmt.Sprintf("%s: %d", data, number)
|
||||
}
|
||||
|
||||
func TestReaderFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := From1(GoFunction)
|
||||
|
||||
result := f("input")(ctx)
|
||||
|
||||
assert.Equal(t, result, "INPUT")
|
||||
|
||||
}
|
||||
|
||||
func MyFinalResult(left, right string) string {
|
||||
return fmt.Sprintf("%s-%s", left, right)
|
||||
}
|
||||
|
||||
func TestReadersFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
f1 := From1(GoFunction)
|
||||
f2 := From2(GoIntFunction)
|
||||
|
||||
result1 := f1("input")(ctx)
|
||||
result2 := f2("input", 10)(ctx)
|
||||
|
||||
result3 := MyFinalResult(result1, result2)
|
||||
|
||||
h := F.Pipe1(
|
||||
SequenceT2(f1("input"), f2("input", 10)),
|
||||
Map(T.Tupled2(MyFinalResult)),
|
||||
)
|
||||
|
||||
composedResult := h(ctx)
|
||||
|
||||
assert.Equal(t, result1, "INPUT")
|
||||
assert.Equal(t, result2, "input: 10")
|
||||
assert.Equal(t, result3, "INPUT-input: 10")
|
||||
|
||||
assert.Equal(t, composedResult, "INPUT-input: 10")
|
||||
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
// 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 reader
|
||||
|
||||
import (
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
|
||||
|
||||
func SequenceT1[A any](a Reader[A]) Reader[T.Tuple1[A]] {
|
||||
return R.SequenceT1[
|
||||
Reader[A],
|
||||
Reader[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a Reader[A], b Reader[B]) Reader[T.Tuple2[A, B]] {
|
||||
return R.SequenceT2[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a Reader[A], b Reader[B], c Reader[C]) Reader[T.Tuple3[A, B, C]] {
|
||||
return R.SequenceT3[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[C],
|
||||
Reader[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a Reader[A], b Reader[B], c Reader[C], d Reader[D]) Reader[T.Tuple4[A, B, C, D]] {
|
||||
return R.SequenceT4[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[C],
|
||||
Reader[D],
|
||||
Reader[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
@@ -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)
|
||||
}
|
||||
|
||||
// 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
|
||||
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
|
||||
return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma)
|
||||
|
@@ -34,8 +34,6 @@ var (
|
||||
|
||||
func command(name string, args []string, in []byte) RE.ReaderEither[exec.CommandOutput] {
|
||||
return func(ctx context.Context) E.Either[error, exec.CommandOutput] {
|
||||
return E.TryCatchError(func() (exec.CommandOutput, error) {
|
||||
return GE.Exec(ctx, name, args, in)
|
||||
})
|
||||
return E.TryCatchError(GE.Exec(ctx, name, args, in))
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ package readereither
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/context/reader"
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
RE "github.com/IBM/fp-go/readereither/generic"
|
||||
@@ -32,14 +31,6 @@ func FromEither[A any](e ET.Either[error, A]) ReaderEither[A] {
|
||||
return RE.FromEither[ReaderEither[A]](e)
|
||||
}
|
||||
|
||||
func RightReader[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.RightReader[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func LeftReader[A any](l R.Reader[error]) ReaderEither[A] {
|
||||
return RE.LeftReader[R.Reader[error], ReaderEither[A]](l)
|
||||
}
|
||||
|
||||
func Left[A any](l error) ReaderEither[A] {
|
||||
return RE.Left[ReaderEither[A]](l)
|
||||
}
|
||||
@@ -48,10 +39,6 @@ func Right[A any](r A) ReaderEither[A] {
|
||||
return RE.Right[ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func FromReader[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.FromReader[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](fa ReaderEither[A], f func(A) B) ReaderEither[B] {
|
||||
return RE.MonadMap[ReaderEither[A], ReaderEither[B]](fa, f)
|
||||
}
|
||||
@@ -84,30 +71,14 @@ func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) Read
|
||||
return RE.FromPredicate[ReaderEither[A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[A, B any](onLeft func(error) R.Reader[B], onRight func(A) R.Reader[B]) func(ReaderEither[A]) R.Reader[B] {
|
||||
return RE.Fold[ReaderEither[A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[A any](onLeft func(error) R.Reader[A]) func(ReaderEither[A]) R.Reader[A] {
|
||||
return RE.GetOrElse[ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[A any](onLeft func(error) ReaderEither[A]) func(ReaderEither[A]) ReaderEither[A] {
|
||||
return RE.OrElse[ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[A any](onLeft func(error) R.Reader[error]) func(ReaderEither[A]) ReaderEither[A] {
|
||||
return RE.OrLeft[ReaderEither[A], ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func Ask() ReaderEither[context.Context] {
|
||||
return RE.Ask[ReaderEither[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.Asks[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[A, B any](ma ReaderEither[A], f func(A) ET.Either[error, B]) ReaderEither[B] {
|
||||
return RE.MonadChainEitherK[ReaderEither[A], ReaderEither[B]](ma, f)
|
||||
}
|
||||
@@ -119,3 +90,11 @@ func ChainEitherK[A, B any](f func(A) ET.Either[error, B]) func(ma ReaderEither[
|
||||
func ChainOptionK[A, B any](onNone func() error) func(func(A) O.Option[B]) func(ReaderEither[A]) ReaderEither[B] {
|
||||
return RE.ChainOptionK[ReaderEither[A], ReaderEither[B]](onNone)
|
||||
}
|
||||
|
||||
func MonadFlap[B, A any](fab ReaderEither[func(A) B], a A) ReaderEither[B] {
|
||||
return RE.MonadFlap[ReaderEither[func(A) B], ReaderEither[B]](fab, a)
|
||||
}
|
||||
|
||||
func Flap[B, A any](a A) func(ReaderEither[func(A) B]) ReaderEither[B] {
|
||||
return RE.Flap[ReaderEither[func(A) B], ReaderEither[B]](a)
|
||||
}
|
||||
|
@@ -1,42 +0,0 @@
|
||||
// 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 readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
R "github.com/IBM/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) IO.IO[A]) func() ReaderIO[A] {
|
||||
return R.From0[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) IO.IO[A]) func(T1) ReaderIO[A] {
|
||||
return R.From1[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) IO.IO[A]) func(T1, T2) ReaderIO[A] {
|
||||
return R.From2[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) IO.IO[A]) func(T1, T2, T3) ReaderIO[A] {
|
||||
return R.From3[ReaderIO[A]](f)
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
// 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 readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
func MonadMap[A, B any](fa ReaderIO[A], f func(A) B) ReaderIO[B] {
|
||||
return R.MonadMap[ReaderIO[A], ReaderIO[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(ReaderIO[A]) ReaderIO[B] {
|
||||
return R.Map[ReaderIO[A], ReaderIO[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma ReaderIO[A], f func(A) ReaderIO[B]) ReaderIO[B] {
|
||||
return R.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) ReaderIO[B]) func(ReaderIO[A]) ReaderIO[B] {
|
||||
return R.Chain[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) ReaderIO[A] {
|
||||
return R.Of[ReaderIO[A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab ReaderIO[func(A) B], fa ReaderIO[A]) ReaderIO[B] {
|
||||
return R.MonadAp[ReaderIO[A], ReaderIO[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa ReaderIO[A]) func(ReaderIO[func(A) B]) ReaderIO[B] {
|
||||
return R.Ap[ReaderIO[A], ReaderIO[B], ReaderIO[func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Ask() ReaderIO[context.Context] {
|
||||
return R.Ask[ReaderIO[context.Context]]()
|
||||
}
|
||||
|
||||
// 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] {
|
||||
return R.Defer[ReaderIO[A]](gen)
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
// 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 readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func GoFunction(ctx context.Context, data string) IO.IO[string] {
|
||||
return func() string {
|
||||
return strings.ToUpper(data)
|
||||
}
|
||||
}
|
||||
|
||||
func GoIntFunction(ctx context.Context, data string, number int) IO.IO[string] {
|
||||
return func() string {
|
||||
return fmt.Sprintf("%s: %d", data, number)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaderFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := From1(GoFunction)
|
||||
|
||||
result := f("input")(ctx)
|
||||
|
||||
assert.Equal(t, result(), "INPUT")
|
||||
|
||||
}
|
||||
|
||||
func MyFinalResult(left, right string) string {
|
||||
return fmt.Sprintf("%s-%s", left, right)
|
||||
}
|
||||
|
||||
func TestReadersFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
f1 := From1(GoFunction)
|
||||
f2 := From2(GoIntFunction)
|
||||
|
||||
result1 := f1("input")(ctx)
|
||||
result2 := f2("input", 10)(ctx)
|
||||
|
||||
result3 := MyFinalResult(result1(), result2())
|
||||
|
||||
h := F.Pipe1(
|
||||
SequenceT2(f1("input"), f2("input", 10)),
|
||||
Map(T.Tupled2(MyFinalResult)),
|
||||
)
|
||||
|
||||
composedResult := h(ctx)
|
||||
|
||||
assert.Equal(t, result1(), "INPUT")
|
||||
assert.Equal(t, result2(), "input: 10")
|
||||
assert.Equal(t, result3, "INPUT-input: 10")
|
||||
|
||||
assert.Equal(t, composedResult(), "INPUT-input: 10")
|
||||
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
// 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 readerio
|
||||
|
||||
import (
|
||||
R "github.com/IBM/fp-go/readerio/generic"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
|
||||
|
||||
func SequenceT1[A any](a ReaderIO[A]) ReaderIO[T.Tuple1[A]] {
|
||||
return R.SequenceT1[
|
||||
ReaderIO[A],
|
||||
ReaderIO[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a ReaderIO[A], b ReaderIO[B]) ReaderIO[T.Tuple2[A, B]] {
|
||||
return R.SequenceT2[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C]) ReaderIO[T.Tuple3[A, B, C]] {
|
||||
return R.SequenceT3[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[C],
|
||||
ReaderIO[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C], d ReaderIO[D]) ReaderIO[T.Tuple4[A, B, C, D]] {
|
||||
return R.SequenceT4[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[C],
|
||||
ReaderIO[D],
|
||||
ReaderIO[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
37
context/readerioeither/bracket.go
Normal file
37
context/readerioeither/bracket.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 readerioeither
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
A, B, ANY any](
|
||||
|
||||
acquire ReaderIOEither[A],
|
||||
use func(A) ReaderIOEither[B],
|
||||
release func(A, E.Either[error, B]) ReaderIOEither[ANY],
|
||||
) ReaderIOEither[B] {
|
||||
return G.Bracket[ReaderIOEither[A], ReaderIOEither[B], ReaderIOEither[ANY]](
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
@@ -25,25 +25,31 @@ import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/file"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
IOEF "github.com/IBM/fp-go/ioeither/file"
|
||||
)
|
||||
|
||||
var (
|
||||
openIOE = IOE.Eitherize1(os.Open)
|
||||
// Open opens a file for reading within the given context
|
||||
Open = F.Flow3(
|
||||
openIOE,
|
||||
IOEF.Open,
|
||||
RIOE.FromIOEither[*os.File],
|
||||
RIOE.WithContext[*os.File],
|
||||
)
|
||||
|
||||
// Remove removes a file by name
|
||||
Remove = F.Flow2(
|
||||
IOEF.Remove,
|
||||
RIOE.FromIOEither[string],
|
||||
)
|
||||
)
|
||||
|
||||
// Close closes an object
|
||||
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
|
||||
return RIOE.FromIOEither(func() ET.Either[error, any] {
|
||||
return ET.TryCatchError(func() (any, error) {
|
||||
return c, c.Close()
|
||||
})
|
||||
})
|
||||
return F.Pipe2(
|
||||
c,
|
||||
IOEF.Close[C],
|
||||
RIOE.FromIOEither[any],
|
||||
)
|
||||
}
|
||||
|
||||
// ReadFile reads a file in the scope of a context
|
||||
|
@@ -19,9 +19,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
RIO "github.com/IBM/fp-go/context/readerio"
|
||||
R "github.com/IBM/fp-go/context/readerioeither"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
J "github.com/IBM/fp-go/json"
|
||||
@@ -37,20 +35,17 @@ func getData(r RecordType) string {
|
||||
|
||||
func ExampleReadFile() {
|
||||
|
||||
data := F.Pipe4(
|
||||
data := F.Pipe3(
|
||||
ReadFile("./data/file.json"),
|
||||
R.ChainEitherK(J.Unmarshal[RecordType]),
|
||||
R.ChainFirstIOK(IO.Logf[RecordType]("Log: %v")),
|
||||
R.Map(getData),
|
||||
R.GetOrElse(F.Flow2(
|
||||
errors.ToString,
|
||||
RIO.Of[string],
|
||||
)),
|
||||
)
|
||||
|
||||
result := data(context.Background())
|
||||
|
||||
fmt.Println(result())
|
||||
|
||||
// Output: Carsten
|
||||
// Output:
|
||||
// Right[<nil>, string](Carsten)
|
||||
}
|
||||
|
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.
|
||||
// This file was generated by robots at
|
||||
// 2023-07-27 22:37:23.9090443 +0200 CEST m=+0.018400201
|
||||
// 2023-10-23 08:30:39.012572 +0200 CEST m=+0.008846101
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -14,515 +14,515 @@ import (
|
||||
// Eitherize0 converts a function with 0 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize0]
|
||||
func Eitherize0[F ~func(context.Context) (R, error), R any](f F) func() ReaderIOEither[R] {
|
||||
return G.Eitherize0[ReaderIOEither[R]](f)
|
||||
return G.Eitherize0[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize1]
|
||||
func Eitherize1[F ~func(context.Context, T0) (R, error), T0, R any](f F) func(T0) ReaderIOEither[R] {
|
||||
return G.Eitherize1[ReaderIOEither[R]](f)
|
||||
return G.Eitherize1[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func SequenceT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.SequenceT1[ReaderIOEither[T.Tuple1[T1]]](t1)
|
||||
return G.SequenceT1[ReaderIOEither[T.Tuple1[T1]]](t1)
|
||||
}
|
||||
|
||||
// SequenceSeqT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func SequenceSeqT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.SequenceSeqT1[ReaderIOEither[T.Tuple1[T1]]](t1)
|
||||
return G.SequenceSeqT1[ReaderIOEither[T.Tuple1[T1]]](t1)
|
||||
}
|
||||
|
||||
// SequenceParT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func SequenceParT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.SequenceParT1[ReaderIOEither[T.Tuple1[T1]]](t1)
|
||||
return G.SequenceParT1[ReaderIOEither[T.Tuple1[T1]]](t1)
|
||||
}
|
||||
|
||||
// SequenceTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func SequenceTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.SequenceTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
|
||||
return G.SequenceTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func SequenceSeqTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.SequenceSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
|
||||
return G.SequenceSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func SequenceParTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.SequenceParTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
|
||||
return G.SequenceParTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func TraverseTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.TraverseTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
|
||||
return G.TraverseTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func TraverseSeqTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.TraverseSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
|
||||
return G.TraverseSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
|
||||
}
|
||||
|
||||
// TraverseParTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
|
||||
func TraverseParTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
|
||||
return G.TraverseParTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
|
||||
return G.TraverseParTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
|
||||
}
|
||||
|
||||
// Eitherize2 converts a function with 2 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize2]
|
||||
func Eitherize2[F ~func(context.Context, T0, T1) (R, error), T0, T1, R any](f F) func(T0, T1) ReaderIOEither[R] {
|
||||
return G.Eitherize2[ReaderIOEither[R]](f)
|
||||
return G.Eitherize2[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func SequenceT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.SequenceT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
|
||||
return G.SequenceT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
|
||||
}
|
||||
|
||||
// SequenceSeqT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func SequenceSeqT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.SequenceSeqT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
|
||||
return G.SequenceSeqT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
|
||||
}
|
||||
|
||||
// SequenceParT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func SequenceParT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.SequenceParT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
|
||||
return G.SequenceParT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
|
||||
}
|
||||
|
||||
// SequenceTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func SequenceTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.SequenceTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
|
||||
return G.SequenceTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func SequenceSeqTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.SequenceSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
|
||||
return G.SequenceSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func SequenceParTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.SequenceParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
|
||||
return G.SequenceParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func TraverseTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.TraverseTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
|
||||
return G.TraverseTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func TraverseSeqTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.TraverseSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
|
||||
return G.TraverseSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
|
||||
}
|
||||
|
||||
// TraverseParTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
|
||||
func TraverseParTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
|
||||
return G.TraverseParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
|
||||
return G.TraverseParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
|
||||
}
|
||||
|
||||
// Eitherize3 converts a function with 3 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize3]
|
||||
func Eitherize3[F ~func(context.Context, T0, T1, T2) (R, error), T0, T1, T2, R any](f F) func(T0, T1, T2) ReaderIOEither[R] {
|
||||
return G.Eitherize3[ReaderIOEither[R]](f)
|
||||
return G.Eitherize3[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func SequenceT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.SequenceT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
|
||||
return G.SequenceT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
|
||||
}
|
||||
|
||||
// SequenceSeqT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func SequenceSeqT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.SequenceSeqT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
|
||||
return G.SequenceSeqT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
|
||||
}
|
||||
|
||||
// SequenceParT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func SequenceParT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.SequenceParT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
|
||||
return G.SequenceParT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
|
||||
}
|
||||
|
||||
// SequenceTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func SequenceTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.SequenceTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
|
||||
return G.SequenceTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func SequenceSeqTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.SequenceSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
|
||||
return G.SequenceSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func SequenceParTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.SequenceParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
|
||||
return G.SequenceParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func TraverseTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.TraverseTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
|
||||
return G.TraverseTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func TraverseSeqTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.TraverseSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
|
||||
return G.TraverseSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
|
||||
}
|
||||
|
||||
// TraverseParTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
|
||||
func TraverseParTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
|
||||
return G.TraverseParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
|
||||
return G.TraverseParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
|
||||
}
|
||||
|
||||
// Eitherize4 converts a function with 4 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize4]
|
||||
func Eitherize4[F ~func(context.Context, T0, T1, T2, T3) (R, error), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) ReaderIOEither[R] {
|
||||
return G.Eitherize4[ReaderIOEither[R]](f)
|
||||
return G.Eitherize4[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func SequenceT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.SequenceT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
|
||||
return G.SequenceT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
|
||||
}
|
||||
|
||||
// SequenceSeqT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func SequenceSeqT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.SequenceSeqT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
|
||||
return G.SequenceSeqT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
|
||||
}
|
||||
|
||||
// SequenceParT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func SequenceParT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.SequenceParT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
|
||||
return G.SequenceParT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
|
||||
}
|
||||
|
||||
// SequenceTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func SequenceTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.SequenceTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
|
||||
return G.SequenceTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func SequenceSeqTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.SequenceSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
|
||||
return G.SequenceSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func SequenceParTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.SequenceParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
|
||||
return G.SequenceParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func TraverseTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.TraverseTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
|
||||
return G.TraverseTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func TraverseSeqTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.TraverseSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
|
||||
return G.TraverseSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
|
||||
}
|
||||
|
||||
// TraverseParTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
|
||||
func TraverseParTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
|
||||
return G.TraverseParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
|
||||
return G.TraverseParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
|
||||
}
|
||||
|
||||
// Eitherize5 converts a function with 5 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize5]
|
||||
func Eitherize5[F ~func(context.Context, T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOEither[R] {
|
||||
return G.Eitherize5[ReaderIOEither[R]](f)
|
||||
return G.Eitherize5[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func SequenceT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.SequenceT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
|
||||
return G.SequenceT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
|
||||
}
|
||||
|
||||
// SequenceSeqT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func SequenceSeqT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.SequenceSeqT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
|
||||
return G.SequenceSeqT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
|
||||
}
|
||||
|
||||
// SequenceParT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func SequenceParT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.SequenceParT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
|
||||
return G.SequenceParT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
|
||||
}
|
||||
|
||||
// SequenceTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func SequenceTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.SequenceTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
|
||||
return G.SequenceTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func SequenceSeqTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.SequenceSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
|
||||
return G.SequenceSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func SequenceParTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.SequenceParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
|
||||
return G.SequenceParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func TraverseTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.TraverseTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
|
||||
return G.TraverseTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func TraverseSeqTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.TraverseSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
|
||||
return G.TraverseSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
|
||||
}
|
||||
|
||||
// TraverseParTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
|
||||
func TraverseParTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
|
||||
return G.TraverseParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
|
||||
return G.TraverseParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
|
||||
}
|
||||
|
||||
// Eitherize6 converts a function with 6 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize6]
|
||||
func Eitherize6[F ~func(context.Context, T0, T1, T2, T3, T4, T5) (R, error), T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOEither[R] {
|
||||
return G.Eitherize6[ReaderIOEither[R]](f)
|
||||
return G.Eitherize6[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func SequenceT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.SequenceT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
|
||||
return G.SequenceT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
|
||||
}
|
||||
|
||||
// SequenceSeqT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func SequenceSeqT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.SequenceSeqT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
|
||||
return G.SequenceSeqT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
|
||||
}
|
||||
|
||||
// SequenceParT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func SequenceParT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.SequenceParT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
|
||||
return G.SequenceParT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
|
||||
}
|
||||
|
||||
// SequenceTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func SequenceTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.SequenceTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
|
||||
return G.SequenceTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func SequenceSeqTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.SequenceSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
|
||||
return G.SequenceSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func SequenceParTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.SequenceParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
|
||||
return G.SequenceParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func TraverseTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.TraverseTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
|
||||
return G.TraverseTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func TraverseSeqTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.TraverseSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
|
||||
return G.TraverseSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
|
||||
}
|
||||
|
||||
// TraverseParTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
|
||||
func TraverseParTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
|
||||
return G.TraverseParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
|
||||
return G.TraverseParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
|
||||
}
|
||||
|
||||
// Eitherize7 converts a function with 7 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize7]
|
||||
func Eitherize7[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error), T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[R] {
|
||||
return G.Eitherize7[ReaderIOEither[R]](f)
|
||||
return G.Eitherize7[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.SequenceT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
|
||||
return G.SequenceT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
|
||||
}
|
||||
|
||||
// SequenceSeqT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func SequenceSeqT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.SequenceSeqT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
|
||||
return G.SequenceSeqT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
|
||||
}
|
||||
|
||||
// SequenceParT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func SequenceParT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.SequenceParT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
|
||||
return G.SequenceParT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
|
||||
}
|
||||
|
||||
// SequenceTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func SequenceTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.SequenceTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
|
||||
return G.SequenceTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func SequenceSeqTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.SequenceSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
|
||||
return G.SequenceSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func SequenceParTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.SequenceParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
|
||||
return G.SequenceParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func TraverseTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.TraverseTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
|
||||
return G.TraverseTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func TraverseSeqTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.TraverseSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
|
||||
return G.TraverseSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
|
||||
}
|
||||
|
||||
// TraverseParTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
|
||||
func TraverseParTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
|
||||
return G.TraverseParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
|
||||
return G.TraverseParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
|
||||
}
|
||||
|
||||
// Eitherize8 converts a function with 8 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize8]
|
||||
func Eitherize8[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[R] {
|
||||
return G.Eitherize8[ReaderIOEither[R]](f)
|
||||
return G.Eitherize8[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.SequenceT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
|
||||
return G.SequenceT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
|
||||
}
|
||||
|
||||
// SequenceSeqT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func SequenceSeqT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.SequenceSeqT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
|
||||
return G.SequenceSeqT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
|
||||
}
|
||||
|
||||
// SequenceParT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func SequenceParT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.SequenceParT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
|
||||
return G.SequenceParT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
|
||||
}
|
||||
|
||||
// SequenceTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func SequenceTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.SequenceTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
|
||||
return G.SequenceTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func SequenceSeqTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.SequenceSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
|
||||
return G.SequenceSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func SequenceParTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.SequenceParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
|
||||
return G.SequenceParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func TraverseTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.TraverseTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
|
||||
return G.TraverseTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func TraverseSeqTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.TraverseSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
|
||||
return G.TraverseSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
|
||||
}
|
||||
|
||||
// TraverseParTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
|
||||
func TraverseParTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
|
||||
return G.TraverseParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
|
||||
return G.TraverseParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
|
||||
}
|
||||
|
||||
// Eitherize9 converts a function with 9 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize9]
|
||||
func Eitherize9[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[R] {
|
||||
return G.Eitherize9[ReaderIOEither[R]](f)
|
||||
return G.Eitherize9[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.SequenceT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
|
||||
return G.SequenceT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
|
||||
}
|
||||
|
||||
// SequenceSeqT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func SequenceSeqT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.SequenceSeqT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
|
||||
return G.SequenceSeqT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
|
||||
}
|
||||
|
||||
// SequenceParT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func SequenceParT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.SequenceParT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
|
||||
return G.SequenceParT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
|
||||
}
|
||||
|
||||
// SequenceTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func SequenceTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.SequenceTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
|
||||
return G.SequenceTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func SequenceSeqTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.SequenceSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
|
||||
return G.SequenceSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func SequenceParTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.SequenceParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
|
||||
return G.SequenceParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func TraverseTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.TraverseTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
|
||||
return G.TraverseTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func TraverseSeqTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.TraverseSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
|
||||
return G.TraverseSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
|
||||
}
|
||||
|
||||
// TraverseParTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
|
||||
func TraverseParTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
|
||||
return G.TraverseParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
|
||||
return G.TraverseParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
|
||||
}
|
||||
|
||||
// Eitherize10 converts a function with 10 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOEither[R]]
|
||||
// The inverse function is [Uneitherize10]
|
||||
func Eitherize10[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[R] {
|
||||
return G.Eitherize10[ReaderIOEither[R]](f)
|
||||
return G.Eitherize10[ReaderIOEither[R]](f)
|
||||
}
|
||||
|
||||
// SequenceT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.SequenceT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
|
||||
return G.SequenceT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
|
||||
}
|
||||
|
||||
// SequenceSeqT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func SequenceSeqT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.SequenceSeqT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
|
||||
return G.SequenceSeqT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
|
||||
}
|
||||
|
||||
// SequenceParT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func SequenceParT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.SequenceParT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
|
||||
return G.SequenceParT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
|
||||
}
|
||||
|
||||
// SequenceTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func SequenceTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.SequenceTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
|
||||
return G.SequenceTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
|
||||
}
|
||||
|
||||
// SequenceSeqTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func SequenceSeqTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.SequenceSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
|
||||
return G.SequenceSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
|
||||
}
|
||||
|
||||
// SequenceParTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func SequenceParTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.SequenceParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
|
||||
return G.SequenceParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
|
||||
}
|
||||
|
||||
// TraverseTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func TraverseTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.TraverseTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
|
||||
return G.TraverseTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
|
||||
}
|
||||
|
||||
// TraverseSeqTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func TraverseSeqTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.TraverseSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
|
||||
return G.TraverseSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
|
||||
}
|
||||
|
||||
// TraverseParTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
|
||||
func TraverseParTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
|
||||
return G.TraverseParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
|
||||
return G.TraverseParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
|
||||
}
|
||||
|
53
context/readerioeither/generic/bracket.go
Normal file
53
context/readerioeither/generic/bracket.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
G "github.com/IBM/fp-go/internal/bracket"
|
||||
I "github.com/IBM/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
GA ~func(context.Context) TA,
|
||||
GB ~func(context.Context) TB,
|
||||
GANY ~func(context.Context) TANY,
|
||||
|
||||
TA ~func() E.Either[error, A],
|
||||
TB ~func() E.Either[error, B],
|
||||
TANY ~func() E.Either[error, ANY],
|
||||
|
||||
A, B, ANY any](
|
||||
|
||||
acquire GA,
|
||||
use func(A) GB,
|
||||
release func(A, E.Either[error, B]) GANY,
|
||||
) GB {
|
||||
return G.Bracket[GA, GB, GANY, E.Either[error, B], A, B](
|
||||
I.Of[GB, TB, context.Context, E.Either[error, B]],
|
||||
MonadChain[GA, GB, TA, TB, A, B],
|
||||
I.MonadChain[GB, GB, TB, TB, context.Context, E.Either[error, B], E.Either[error, B]],
|
||||
MonadChain[GANY, GB, TANY, TB, ANY, B],
|
||||
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
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)
|
||||
}
|
||||
|
||||
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[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GRB ~func(context.Context) GIOB,
|
||||
@@ -410,10 +432,10 @@ func FromIOEither[
|
||||
|
||||
func FromIO[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOA ~func() E.Either[error, A],
|
||||
|
||||
GIOB ~func() A,
|
||||
|
||||
GIOA ~func() E.Either[error, A],
|
||||
|
||||
A any](t GIOB) GRA {
|
||||
return RIE.FromIO[GRA](t)
|
||||
}
|
||||
@@ -458,6 +480,34 @@ func ChainIOK[
|
||||
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[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOA ~func() E.Either[error, A],
|
||||
@@ -521,7 +571,7 @@ func Timer[
|
||||
](delay time.Duration) GRA {
|
||||
return F.Pipe2(
|
||||
IO.Now[func() time.Time](),
|
||||
FromIO[GRA, GIOA, func() time.Time],
|
||||
FromIO[GRA, func() time.Time],
|
||||
Delay[GRA](delay),
|
||||
)
|
||||
}
|
||||
@@ -543,3 +593,82 @@ func TryCatch[
|
||||
A any](f func(context.Context) func() (A, error)) GRA {
|
||||
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)
|
||||
}
|
||||
|
@@ -13,18 +13,17 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reader
|
||||
package generic
|
||||
|
||||
import (
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
"context"
|
||||
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[A, B any](f func(A) Reader[B]) func([]A) Reader[[]B] {
|
||||
return R.TraverseArray[Reader[B], Reader[[]B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[A any](ma []Reader[A]) Reader[[]A] {
|
||||
return R.SequenceArray[Reader[A], Reader[[]A]](ma)
|
||||
func AltSemigroup[GRA ~func(context.Context) GIOA, GIOA ~func() ET.Either[error, A], A any]() S.Semigroup[GRA] {
|
||||
return S.AltSemigroup(
|
||||
MonadAlt[func() GRA],
|
||||
)
|
||||
}
|
44
context/readerioeither/generic/sync.go
Normal file
44
context/readerioeither/generic/sync.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io/generic"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOA ~func() E.Either[error, A],
|
||||
GRCANCEL ~func(context.Context) GIOCANCEL,
|
||||
GIOCANCEL ~func() E.Either[error, context.CancelFunc],
|
||||
A any](lock GRCANCEL) func(fa GRA) GRA {
|
||||
|
||||
type GRANY func(ctx context.Context) func() E.Either[error, any]
|
||||
type IOANY func() any
|
||||
|
||||
return F.Flow2(
|
||||
F.Constant1[context.CancelFunc, GRA],
|
||||
WithResource[GRA, GRCANCEL, GRANY](lock, F.Flow2(
|
||||
IO.FromImpure[IOANY, context.CancelFunc],
|
||||
FromIO[GRANY, IOANY],
|
||||
)),
|
||||
)
|
||||
}
|
@@ -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
|
||||
func SequenceArray[
|
||||
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
|
||||
func SequenceRecord[K comparable,
|
||||
AS ~map[K]A,
|
||||
@@ -127,3 +166,289 @@ func SequenceRecord[K comparable,
|
||||
|
||||
return MonadTraverseRecord[K, GAS, GRAS](ma, F.Identity[GRA])
|
||||
}
|
||||
|
||||
// MonadTraverseArraySeq transforms an array
|
||||
func MonadTraverseArraySeq[
|
||||
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](as AS, f func(A) GRB) GRBS {
|
||||
|
||||
return RA.MonadTraverse[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],
|
||||
ApSeq[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
as, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArraySeq transforms an array
|
||||
func TraverseArraySeq[
|
||||
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(A) GRB) func(AS) GRBS {
|
||||
|
||||
return RA.Traverse[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],
|
||||
ApSeq[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArrayWithIndexSeq transforms an array
|
||||
func TraverseArrayWithIndexSeq[
|
||||
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],
|
||||
ApSeq[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceArraySeq converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArraySeq[
|
||||
AS ~[]A,
|
||||
GAS ~[]GRA,
|
||||
GRAS ~func(context.Context) GIOAS,
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOAS ~func() E.Either[error, AS],
|
||||
GIOA ~func() E.Either[error, A],
|
||||
A any](ma GAS) GRAS {
|
||||
|
||||
return MonadTraverseArraySeq[GAS, GRAS](ma, F.Identity[GRA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecordSeq transforms a record
|
||||
func MonadTraverseRecordSeq[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](ma AS, f func(A) GRB) GRBS {
|
||||
|
||||
return RR.MonadTraverse[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],
|
||||
ApSeq[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordSeq transforms a record
|
||||
func TraverseRecordSeq[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(A) GRB) func(AS) GRBS {
|
||||
|
||||
return RR.Traverse[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],
|
||||
ApSeq[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexSeq transforms a record
|
||||
func TraverseRecordWithIndexSeq[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],
|
||||
ApSeq[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceRecordSeq converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceRecordSeq[K comparable,
|
||||
AS ~map[K]A,
|
||||
GAS ~map[K]GRA,
|
||||
GRAS ~func(context.Context) GIOAS,
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOAS ~func() E.Either[error, AS],
|
||||
GIOA ~func() E.Either[error, A],
|
||||
A any](ma GAS) GRAS {
|
||||
|
||||
return MonadTraverseRecordSeq[K, GAS, GRAS](ma, F.Identity[GRA])
|
||||
}
|
||||
|
||||
// MonadTraverseArrayPar transforms an array
|
||||
func MonadTraverseArrayPar[
|
||||
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](as AS, f func(A) GRB) GRBS {
|
||||
|
||||
return RA.MonadTraverse[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],
|
||||
ApPar[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
as, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArrayPar transforms an array
|
||||
func TraverseArrayPar[
|
||||
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(A) GRB) func(AS) GRBS {
|
||||
|
||||
return RA.Traverse[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],
|
||||
ApPar[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArrayWithIndexPar transforms an array
|
||||
func TraverseArrayWithIndexPar[
|
||||
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],
|
||||
ApPar[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceArrayPar converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArrayPar[
|
||||
AS ~[]A,
|
||||
GAS ~[]GRA,
|
||||
GRAS ~func(context.Context) GIOAS,
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOAS ~func() E.Either[error, AS],
|
||||
GIOA ~func() E.Either[error, A],
|
||||
A any](ma GAS) GRAS {
|
||||
|
||||
return MonadTraverseArrayPar[GAS, GRAS](ma, F.Identity[GRA])
|
||||
}
|
||||
|
||||
// MonadTraverseRecordPar transforms a record
|
||||
func MonadTraverseRecordPar[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](ma AS, f func(A) GRB) GRBS {
|
||||
|
||||
return RR.MonadTraverse[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],
|
||||
ApPar[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordPar transforms a record
|
||||
func TraverseRecordPar[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(A) GRB) func(AS) GRBS {
|
||||
|
||||
return RR.Traverse[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],
|
||||
ApPar[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexPar transforms a record
|
||||
func TraverseRecordWithIndexPar[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],
|
||||
ApPar[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceRecordPar converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceRecordPar[K comparable,
|
||||
AS ~map[K]A,
|
||||
GAS ~map[K]GRA,
|
||||
GRAS ~func(context.Context) GIOAS,
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOAS ~func() E.Either[error, AS],
|
||||
GIOA ~func() E.Either[error, A],
|
||||
A any](ma GAS) GRAS {
|
||||
|
||||
return MonadTraverseRecordPar[K, GAS, GRAS](ma, F.Identity[GRA])
|
||||
}
|
||||
|
72
context/readerioeither/http/builder/builder.go
Normal file
72
context/readerioeither/http/builder/builder.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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 builder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||
RIOEH "github.com/IBM/fp-go/context/readerioeither/http"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
R "github.com/IBM/fp-go/http/builder"
|
||||
H "github.com/IBM/fp-go/http/headers"
|
||||
LZ "github.com/IBM/fp-go/lazy"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
func Requester(builder *R.Builder) RIOEH.Requester {
|
||||
|
||||
withBody := F.Curry3(func(data []byte, url string, method string) RIOE.ReaderIOEither[*http.Request] {
|
||||
return RIOE.TryCatch(func(ctx context.Context) func() (*http.Request, error) {
|
||||
return func() (*http.Request, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, method, url, bytes.NewReader(data))
|
||||
if err == nil {
|
||||
req.Header.Set(H.ContentLength, strconv.Itoa(len(data)))
|
||||
H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||
}
|
||||
return req, err
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
withoutBody := F.Curry2(func(url string, method string) RIOE.ReaderIOEither[*http.Request] {
|
||||
return RIOE.TryCatch(func(ctx context.Context) func() (*http.Request, error) {
|
||||
return func() (*http.Request, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, method, url, nil)
|
||||
if err == nil {
|
||||
H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||
}
|
||||
return req, err
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return F.Pipe5(
|
||||
builder.GetBody(),
|
||||
O.Fold(LZ.Of(E.Of[error](withoutBody)), E.Map[error](withBody)),
|
||||
E.Ap[func(string) RIOE.ReaderIOEither[*http.Request]](builder.GetTargetUrl()),
|
||||
E.Flap[error, RIOE.ReaderIOEither[*http.Request]](builder.GetMethod()),
|
||||
E.GetOrElse(RIOE.Left[*http.Request]),
|
||||
RIOE.Map(func(req *http.Request) *http.Request {
|
||||
req.Header = H.Monoid.Concat(req.Header, builder.GetHeaders())
|
||||
return req
|
||||
}),
|
||||
)
|
||||
}
|
59
context/readerioeither/http/builder/builder_test.go
Normal file
59
context/readerioeither/http/builder/builder_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// 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 builder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
R "github.com/IBM/fp-go/http/builder"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuilderWithQuery(t *testing.T) {
|
||||
// add some query
|
||||
withLimit := R.WithQueryArg("limit")("10")
|
||||
withUrl := R.WithUrl("http://www.example.org?a=b")
|
||||
|
||||
b := F.Pipe2(
|
||||
R.Default,
|
||||
withLimit,
|
||||
withUrl,
|
||||
)
|
||||
|
||||
req := F.Pipe3(
|
||||
b,
|
||||
Requester,
|
||||
RIOE.Map(func(r *http.Request) *url.URL {
|
||||
return r.URL
|
||||
}),
|
||||
RIOE.ChainFirstIOK(func(u *url.URL) IO.IO[any] {
|
||||
return IO.FromImpure(func() {
|
||||
q := u.Query()
|
||||
assert.Equal(t, "10", q.Get("limit"))
|
||||
assert.Equal(t, "b", q.Get("a"))
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
assert.True(t, E.IsRight(req(context.Background())()))
|
||||
}
|
@@ -21,6 +21,13 @@ import (
|
||||
"testing"
|
||||
|
||||
H "net/http"
|
||||
|
||||
R "github.com/IBM/fp-go/context/readerioeither"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type PostItem struct {
|
||||
@@ -30,6 +37,47 @@ type PostItem struct {
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
func getTitle(item PostItem) string {
|
||||
return item.Title
|
||||
}
|
||||
|
||||
type simpleRequestBuilder struct {
|
||||
method string
|
||||
url string
|
||||
headers H.Header
|
||||
}
|
||||
|
||||
func requestBuilder() simpleRequestBuilder {
|
||||
return simpleRequestBuilder{method: "GET"}
|
||||
}
|
||||
|
||||
func (b simpleRequestBuilder) WithURL(url string) simpleRequestBuilder {
|
||||
b.url = url
|
||||
return b
|
||||
}
|
||||
|
||||
func (b simpleRequestBuilder) WithHeader(key, value string) simpleRequestBuilder {
|
||||
if b.headers == nil {
|
||||
b.headers = make(H.Header)
|
||||
} else {
|
||||
b.headers = b.headers.Clone()
|
||||
}
|
||||
b.headers.Set(key, value)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b simpleRequestBuilder) Build() R.ReaderIOEither[*H.Request] {
|
||||
return func(ctx context.Context) IOE.IOEither[error, *H.Request] {
|
||||
return IOE.TryCatchError(func() (*H.Request, error) {
|
||||
req, err := H.NewRequestWithContext(ctx, b.method, b.url, nil)
|
||||
if err == nil {
|
||||
req.Header = b.headers
|
||||
}
|
||||
return req, err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendSingleRequest(t *testing.T) {
|
||||
|
||||
client := MakeClient(H.DefaultClient)
|
||||
@@ -40,7 +88,70 @@ func TestSendSingleRequest(t *testing.T) {
|
||||
|
||||
resp1 := readItem(req1)
|
||||
|
||||
resE := resp1(context.Background())()
|
||||
resE := resp1(context.TODO())()
|
||||
|
||||
fmt.Println(resE)
|
||||
}
|
||||
|
||||
// setHeaderUnsafe updates a header value in a request object by mutating the request object
|
||||
func setHeaderUnsafe(key, value string) func(*H.Request) *H.Request {
|
||||
return func(req *H.Request) *H.Request {
|
||||
req.Header.Set(key, value)
|
||||
return req
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendSingleRequestWithHeaderUnsafe(t *testing.T) {
|
||||
|
||||
client := MakeClient(H.DefaultClient)
|
||||
|
||||
// this is not safe from a puristic perspective, because the map call mutates the request object
|
||||
req1 := F.Pipe2(
|
||||
"https://jsonplaceholder.typicode.com/posts/1",
|
||||
MakeGetRequest,
|
||||
R.Map(setHeaderUnsafe("Content-Type", "text/html")),
|
||||
)
|
||||
|
||||
readItem := ReadJson[PostItem](client)
|
||||
|
||||
resp1 := F.Pipe2(
|
||||
req1,
|
||||
readItem,
|
||||
R.Map(getTitle),
|
||||
)
|
||||
|
||||
res := F.Pipe1(
|
||||
resp1(context.TODO())(),
|
||||
E.GetOrElse(errors.ToString),
|
||||
)
|
||||
|
||||
assert.Equal(t, "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", res)
|
||||
}
|
||||
|
||||
func TestSendSingleRequestWithHeaderSafe(t *testing.T) {
|
||||
|
||||
client := MakeClient(H.DefaultClient)
|
||||
|
||||
// the request builder assembles config values to construct
|
||||
// the final http request. Each `With` step creates a copy of the settings
|
||||
// so the flow is pure
|
||||
request := requestBuilder().
|
||||
WithURL("https://jsonplaceholder.typicode.com/posts/1").
|
||||
WithHeader("Content-Type", "text/html").
|
||||
Build()
|
||||
|
||||
readItem := ReadJson[PostItem](client)
|
||||
|
||||
response := F.Pipe2(
|
||||
request,
|
||||
readItem,
|
||||
R.Map(getTitle),
|
||||
)
|
||||
|
||||
res := F.Pipe1(
|
||||
response(context.TODO())(),
|
||||
E.GetOrElse(errors.ToString),
|
||||
)
|
||||
|
||||
assert.Equal(t, "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", res)
|
||||
}
|
||||
|
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],
|
||||
)
|
||||
}
|
@@ -19,12 +19,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
R "github.com/IBM/fp-go/context/reader"
|
||||
RIO "github.com/IBM/fp-go/context/readerio"
|
||||
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
L "github.com/IBM/fp-go/lazy"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
@@ -32,14 +31,6 @@ func FromEither[A any](e ET.Either[error, A]) ReaderIOEither[A] {
|
||||
return G.FromEither[ReaderIOEither[A]](e)
|
||||
}
|
||||
|
||||
func RightReader[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return G.RightReader[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func LeftReader[A any](l R.Reader[error]) ReaderIOEither[A] {
|
||||
return G.LeftReader[ReaderIOEither[A]](l)
|
||||
}
|
||||
|
||||
func Left[A any](l error) ReaderIOEither[A] {
|
||||
return G.Left[ReaderIOEither[A]](l)
|
||||
}
|
||||
@@ -48,10 +39,6 @@ func Right[A any](r A) ReaderIOEither[A] {
|
||||
return G.Right[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func FromReader[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return G.FromReader[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](fa ReaderIOEither[A], f func(A) B) ReaderIOEither[B] {
|
||||
return G.MonadMap[ReaderIOEither[A], ReaderIOEither[B]](fa, f)
|
||||
}
|
||||
@@ -60,6 +47,14 @@ func Map[A, B any](f func(A) B) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
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] {
|
||||
return G.MonadChain(ma, f)
|
||||
}
|
||||
@@ -94,30 +89,14 @@ func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) Read
|
||||
return G.FromPredicate[ReaderIOEither[A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[A, B any](onLeft func(error) RIO.ReaderIO[B], onRight func(A) RIO.ReaderIO[B]) func(ReaderIOEither[A]) RIO.ReaderIO[B] {
|
||||
return G.Fold[RIO.ReaderIO[B], ReaderIOEither[A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[A any](onLeft func(error) RIO.ReaderIO[A]) func(ReaderIOEither[A]) RIO.ReaderIO[A] {
|
||||
return G.GetOrElse[RIO.ReaderIO[A], ReaderIOEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[A any](onLeft func(error) ReaderIOEither[A]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.OrElse[ReaderIOEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[A any](onLeft func(error) RIO.ReaderIO[error]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.OrLeft[ReaderIOEither[A], RIO.ReaderIO[error]](onLeft)
|
||||
}
|
||||
|
||||
func Ask() ReaderIOEither[context.Context] {
|
||||
return G.Ask[ReaderIOEither[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return G.Asks[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[A, B any](ma ReaderIOEither[A], f func(A) ET.Either[error, B]) ReaderIOEither[B] {
|
||||
return G.MonadChainEitherK[ReaderIOEither[A], ReaderIOEither[B]](ma, f)
|
||||
}
|
||||
@@ -146,6 +125,10 @@ func FromIO[A any](t IO.IO[A]) ReaderIOEither[A] {
|
||||
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
|
||||
func Never[A any]() ReaderIOEither[A] {
|
||||
return G.Never[ReaderIOEither[A]]()
|
||||
@@ -182,7 +165,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
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -190,3 +173,34 @@ func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] {
|
||||
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 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())()
|
||||
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]]()
|
||||
}
|
@@ -13,14 +13,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package reader implements a specialization of the Reader monad assuming a golang context as the context of the monad
|
||||
package reader
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader"
|
||||
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||
)
|
||||
|
||||
// Reader is a specialization of the Reader monad assuming a golang context as the context of the monad
|
||||
type Reader[A any] R.Reader[context.Context, A]
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[A any](lock ReaderIOEither[context.CancelFunc]) func(fa ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.WithLock[ReaderIOEither[A]](lock)
|
||||
}
|
@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) ReaderIOEither[B]) func([]A) ReaderIOEith
|
||||
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
|
||||
func SequenceArray[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
|
||||
return G.SequenceArray[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma)
|
||||
@@ -34,7 +39,72 @@ 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
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)
|
||||
}
|
||||
|
||||
// TraverseArraySeq uses transforms an array [[]A] into [[]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[[]B]]
|
||||
func TraverseArraySeq[A, B any](f func(A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
|
||||
return G.TraverseArraySeq[[]A, ReaderIOEither[[]B]](f)
|
||||
}
|
||||
|
||||
// TraverseArrayWithIndexSeq uses transforms an array [[]A] into [[]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[[]B]]
|
||||
func TraverseArrayWithIndexSeq[A, B any](f func(int, A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
|
||||
return G.TraverseArrayWithIndexSeq[[]A, ReaderIOEither[[]B]](f)
|
||||
}
|
||||
|
||||
// SequenceArraySeq converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArraySeq[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
|
||||
return G.SequenceArraySeq[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma)
|
||||
}
|
||||
|
||||
// TraverseRecordSeq uses transforms a record [map[K]A] into [map[K]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[map[K]B]]
|
||||
func TraverseRecordSeq[K comparable, A, B any](f func(A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
|
||||
return G.TraverseRecordSeq[K, map[K]A, ReaderIOEither[map[K]B]](f)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexSeq uses transforms a record [map[K]A] into [map[K]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[map[K]B]]
|
||||
func TraverseRecordWithIndexSeq[K comparable, A, B any](f func(K, A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
|
||||
return G.TraverseRecordWithIndexSeq[K, map[K]A, ReaderIOEither[map[K]B]](f)
|
||||
}
|
||||
|
||||
// SequenceRecordSeq converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceRecordSeq[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] {
|
||||
return G.SequenceRecordSeq[K, map[K]A, map[K]ReaderIOEither[A], ReaderIOEither[map[K]A]](ma)
|
||||
}
|
||||
|
||||
// TraverseArrayPar uses transforms an array [[]A] into [[]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[[]B]]
|
||||
func TraverseArrayPar[A, B any](f func(A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
|
||||
return G.TraverseArrayPar[[]A, ReaderIOEither[[]B]](f)
|
||||
}
|
||||
|
||||
// TraverseArrayWithIndexPar uses transforms an array [[]A] into [[]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[[]B]]
|
||||
func TraverseArrayWithIndexPar[A, B any](f func(int, A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
|
||||
return G.TraverseArrayWithIndexPar[[]A, ReaderIOEither[[]B]](f)
|
||||
}
|
||||
|
||||
// SequenceArrayPar converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArrayPar[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
|
||||
return G.SequenceArrayPar[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma)
|
||||
}
|
||||
|
||||
// TraverseRecordPar uses transforms a record [map[K]A] into [map[K]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[map[K]B]]
|
||||
func TraverseRecordPar[K comparable, A, B any](f func(A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
|
||||
return G.TraverseRecordPar[K, map[K]A, ReaderIOEither[map[K]B]](f)
|
||||
}
|
||||
|
||||
// TraverseRecordWithIndexPar uses transforms a record [map[K]A] into [map[K]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[map[K]B]]
|
||||
func TraverseRecordWithIndexPar[K comparable, A, B any](f func(K, A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
|
||||
return G.TraverseRecordWithIndexPar[K, map[K]A, ReaderIOEither[map[K]B]](f)
|
||||
}
|
||||
|
||||
// SequenceRecordPar converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceRecordPar[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] {
|
||||
return G.SequenceRecordPar[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
|
38
di/app.go
Normal file
38
di/app.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// 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 di
|
||||
|
||||
import (
|
||||
DIE "github.com/IBM/fp-go/di/erasure"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
)
|
||||
|
||||
var (
|
||||
// InjMain is the [InjectionToken] for the main application
|
||||
InjMain = MakeToken[any]("APP")
|
||||
|
||||
// Main is the resolver for the main application
|
||||
Main = Resolve(InjMain)
|
||||
)
|
||||
|
||||
// RunMain runs the main application from a set of [DIE.Provider]s
|
||||
var RunMain = F.Flow3(
|
||||
DIE.MakeInjector,
|
||||
Main,
|
||||
IOE.Fold(IO.Of[error], F.Constant1[any](IO.Of[error](nil))),
|
||||
)
|
43
di/doc.go
Normal file
43
di/doc.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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 di implements functions and data types supporting dependency injection patterns
|
||||
//
|
||||
// The fundamental building block is the concept of a [Dependency]. This describes the abstract concept of a function, service or value together with its type.
|
||||
// Examples for dependencies can be as simple as configuration values such as the API URL for a service, the current username, a [Dependency] could be the map
|
||||
// of the configuration environment, an http client or as complex as a service interface. Important is that a [Dependency] only defines the concept but
|
||||
// not the implementation.
|
||||
//
|
||||
// The implementation of a [Dependency] is called a [Provider], the dependency of an `API URL` could e.g. be realized by a provider that consults the environment to read the information
|
||||
// or a config file or simply hardcode it.
|
||||
// In many cases the implementation of a [Provider] depends in turn on other [Dependency] (but never directly on other [Provider]s), a provider for an `API URL` that reads
|
||||
// the information from the environment would e.g. depend on a [Dependency] that represents this environment.
|
||||
//
|
||||
// It is the resposibility of the [InjectableFactory] to create an instance of a [Dependency]. All instances are considered singletons. Create an [InjectableFactory] via the [MakeInjector] method. Use [Resolve] to create a strongly typed
|
||||
// factory for a particular [InjectionToken].
|
||||
//
|
||||
// In most cases it is not required to use [InjectableFactory] directly, instead you would create a [Provider] via the [MakeProvider2] method (suffix indicates the number of dependencies). In this call
|
||||
// you give a number of (strongly typed) [Dependency] identifiers and a (strongly typed) factory function for the implementation. The dependency injection framework makes
|
||||
// sure to resolve the dependencies before calling the factory method.
|
||||
//
|
||||
// For convenience purposes it can be helpful to attach a default implementation of a [Dependency]. In this case use the [MakeTokenWithDefault2] method (suffix indicates the number of dependencies)
|
||||
// to define the [InjectionToken].
|
||||
//
|
||||
// [Provider]: [github.com/IBM/fp-go/di/erasure.Provider]
|
||||
// [InjectableFactory]: [github.com/IBM/fp-go/di/erasure.InjectableFactory]
|
||||
// [MakeInjector]: [github.com/IBM/fp-go/di/erasure.MakeInjector]
|
||||
package di
|
||||
|
||||
//go:generate go run .. di --count 10 --filename gen.go
|
170
di/erasure/injector.go
Normal file
170
di/erasure/injector.go
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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 erasure
|
||||
|
||||
import (
|
||||
A "github.com/IBM/fp-go/array"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
I "github.com/IBM/fp-go/identity"
|
||||
IG "github.com/IBM/fp-go/identity/generic"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
L "github.com/IBM/fp-go/lazy"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
R "github.com/IBM/fp-go/record"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
|
||||
"sync"
|
||||
)
|
||||
|
||||
func providerToEntry(p Provider) T.Tuple2[string, ProviderFactory] {
|
||||
return T.MakeTuple2(p.Provides().Id(), p.Factory())
|
||||
}
|
||||
|
||||
func itemProviderToMap(p Provider) map[string][]ProviderFactory {
|
||||
return R.Singleton(p.Provides().Id(), A.Of(p.Factory()))
|
||||
}
|
||||
|
||||
var (
|
||||
// missingProviderError returns a [ProviderFactory] that fails due to a missing dependency
|
||||
missingProviderError = F.Flow4(
|
||||
Dependency.String,
|
||||
errors.OnSome[string]("no provider for dependency [%s]"),
|
||||
IOE.Left[any, error],
|
||||
F.Constant1[InjectableFactory, IOE.IOEither[error, any]],
|
||||
)
|
||||
|
||||
// missingProviderErrorOrDefault returns the default [ProviderFactory] or an error
|
||||
missingProviderErrorOrDefault = F.Flow3(
|
||||
T.Replicate2[Dependency],
|
||||
T.Map2(Dependency.ProviderFactory, F.Flow2(missingProviderError, F.Constant[ProviderFactory])),
|
||||
T.Tupled2(O.MonadGetOrElse[ProviderFactory]),
|
||||
)
|
||||
|
||||
emptyMulti any = A.Empty[any]()
|
||||
|
||||
// emptyMultiDependency returns a [ProviderFactory] for an empty, multi dependency
|
||||
emptyMultiDependency = F.Constant1[Dependency](F.Constant1[InjectableFactory](IOE.Of[error](emptyMulti)))
|
||||
|
||||
// handleMissingProvider covers the case of a missing provider. It either
|
||||
// returns an error or an empty multi value provider
|
||||
handleMissingProvider = F.Flow2(
|
||||
F.Ternary(isMultiDependency, emptyMultiDependency, missingProviderErrorOrDefault),
|
||||
F.Constant[ProviderFactory],
|
||||
)
|
||||
|
||||
// mergeItemProviders is a monoid for item provider factories
|
||||
mergeItemProviders = R.UnionMonoid[string](A.Semigroup[ProviderFactory]())
|
||||
|
||||
// mergeProviders is a monoid for provider factories
|
||||
mergeProviders = R.UnionLastMonoid[string, ProviderFactory]()
|
||||
|
||||
// collectItemProviders create a provider map for item providers
|
||||
collectItemProviders = F.Flow2(
|
||||
A.FoldMap[Provider](mergeItemProviders)(itemProviderToMap),
|
||||
R.Map[string](itemProviderFactory),
|
||||
)
|
||||
|
||||
// collectProviders collects non-item providers
|
||||
collectProviders = F.Flow2(
|
||||
A.Map(providerToEntry),
|
||||
R.FromEntries[string, ProviderFactory],
|
||||
)
|
||||
|
||||
// assembleProviders constructs the provider map for item and non-item providers
|
||||
assembleProviders = F.Flow3(
|
||||
A.Partition(isItemProvider),
|
||||
T.Map2(collectProviders, collectItemProviders),
|
||||
T.Tupled2(mergeProviders.Concat),
|
||||
)
|
||||
)
|
||||
|
||||
// isMultiDependency tests if a dependency is a container dependency
|
||||
func isMultiDependency(dep Dependency) bool {
|
||||
return dep.Flag()&Multi == Multi
|
||||
}
|
||||
|
||||
// isItemProvider tests if a provivder provides a single item
|
||||
func isItemProvider(provider Provider) bool {
|
||||
return provider.Provides().Flag()&Item == Item
|
||||
}
|
||||
|
||||
// itemProviderFactory combines multiple factories into one, returning an array
|
||||
func itemProviderFactory(fcts []ProviderFactory) ProviderFactory {
|
||||
return func(inj InjectableFactory) IOE.IOEither[error, any] {
|
||||
return F.Pipe2(
|
||||
fcts,
|
||||
IOE.TraverseArray(I.Flap[IOE.IOEither[error, any]](inj)),
|
||||
IOE.Map[error](F.ToAny[[]any]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeInjector creates an [InjectableFactory] based on a set of [Provider]s
|
||||
//
|
||||
// The resulting [InjectableFactory] can then be used to retrieve service instances given their [Dependency]. The implementation
|
||||
// makes sure to transitively resolve the required dependencies.
|
||||
func MakeInjector(providers []Provider) InjectableFactory {
|
||||
|
||||
type Result = IOE.IOEither[error, any]
|
||||
type LazyResult = L.Lazy[Result]
|
||||
|
||||
// resolved stores the values resolved so far, key is the string ID
|
||||
// of the token, value is a lazy result
|
||||
var resolved sync.Map
|
||||
|
||||
// provide a mapping for all providers
|
||||
factoryById := assembleProviders(providers)
|
||||
|
||||
// the actual factory, we need lazy initialization
|
||||
var injFct InjectableFactory
|
||||
|
||||
// lazy initialization, so we can cross reference it
|
||||
injFct = func(token Dependency) Result {
|
||||
|
||||
key := token.Id()
|
||||
|
||||
// according to https://github.com/golang/go/issues/44159 this
|
||||
// is the best way to use the sync map
|
||||
actual, loaded := resolved.Load(key)
|
||||
if !loaded {
|
||||
|
||||
computeResult := L.MakeLazy(func() Result {
|
||||
return F.Pipe5(
|
||||
token,
|
||||
T.Replicate2[Dependency],
|
||||
T.Map2(F.Flow3(
|
||||
Dependency.Id,
|
||||
R.Lookup[ProviderFactory, string],
|
||||
I.Ap[O.Option[ProviderFactory]](factoryById),
|
||||
), handleMissingProvider),
|
||||
T.Tupled2(O.MonadGetOrElse[ProviderFactory]),
|
||||
IG.Ap[ProviderFactory](injFct),
|
||||
IOE.Memoize[error, any],
|
||||
)
|
||||
})
|
||||
|
||||
actual, _ = resolved.LoadOrStore(key, F.Pipe1(
|
||||
computeResult,
|
||||
L.Memoize[Result],
|
||||
))
|
||||
}
|
||||
|
||||
return actual.(LazyResult)()
|
||||
}
|
||||
|
||||
return injFct
|
||||
}
|
181
di/erasure/provider.go
Normal file
181
di/erasure/provider.go
Normal file
@@ -0,0 +1,181 @@
|
||||
// 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 erasure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
I "github.com/IBM/fp-go/identity"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
IOG "github.com/IBM/fp-go/io/generic"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
IOO "github.com/IBM/fp-go/iooption"
|
||||
Int "github.com/IBM/fp-go/number/integer"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
R "github.com/IBM/fp-go/record"
|
||||
)
|
||||
|
||||
type (
|
||||
// InjectableFactory is a factory function that can create an untyped instance of a service based on its [Dependency] identifier
|
||||
InjectableFactory = func(Dependency) IOE.IOEither[error, any]
|
||||
ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any]
|
||||
|
||||
paramIndex = map[int]int
|
||||
paramValue = map[int]any
|
||||
handler = func(paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue]
|
||||
mapping = map[int]paramIndex
|
||||
|
||||
Provider interface {
|
||||
fmt.Stringer
|
||||
// Provides returns the [Dependency] implemented by this provider
|
||||
Provides() Dependency
|
||||
// Factory returns s function that can create an instance of the dependency based on an [InjectableFactory]
|
||||
Factory() ProviderFactory
|
||||
}
|
||||
|
||||
provider struct {
|
||||
provides Dependency
|
||||
factory ProviderFactory
|
||||
}
|
||||
)
|
||||
|
||||
func (p *provider) Provides() Dependency {
|
||||
return p.provides
|
||||
}
|
||||
|
||||
func (p *provider) Factory() ProviderFactory {
|
||||
return p.factory
|
||||
}
|
||||
|
||||
func (p *provider) String() string {
|
||||
return fmt.Sprintf("Provider for [%s]", p.provides)
|
||||
}
|
||||
|
||||
func MakeProvider(token Dependency, fct ProviderFactory) Provider {
|
||||
return &provider{token, fct}
|
||||
}
|
||||
|
||||
func mapFromToken(idx int, token Dependency) map[int]paramIndex {
|
||||
return R.Singleton(token.Flag()&BehaviourMask, R.Singleton(idx, idx))
|
||||
}
|
||||
|
||||
var (
|
||||
// Empty is the empty array of providers
|
||||
Empty = A.Empty[Provider]()
|
||||
|
||||
mergeTokenMaps = R.UnionMonoid[int](R.UnionLastSemigroup[int, int]())
|
||||
foldDeps = A.FoldMapWithIndex[Dependency](mergeTokenMaps)(mapFromToken)
|
||||
mergeMaps = R.UnionLastMonoid[int, any]()
|
||||
collectParams = R.CollectOrd[any, any](Int.Ord)(F.SK[int, any])
|
||||
|
||||
mapDeps = F.Curry2(A.MonadMap[Dependency, IOE.IOEither[error, any]])
|
||||
|
||||
handlers = map[int]handler{
|
||||
Identity: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return F.Pipe1(
|
||||
mp,
|
||||
IOE.TraverseRecord[int](getAt(res)),
|
||||
)
|
||||
}
|
||||
},
|
||||
Option: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return F.Pipe3(
|
||||
mp,
|
||||
IOG.TraverseRecord[IO.IO[map[int]E.Either[error, any]], paramIndex](getAt(res)),
|
||||
IO.Map(R.Map[int](F.Flow2(
|
||||
E.ToOption[error, any],
|
||||
F.ToAny[O.Option[any]],
|
||||
))),
|
||||
IOE.FromIO[error, paramValue],
|
||||
)
|
||||
}
|
||||
},
|
||||
IOEither: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return F.Pipe2(
|
||||
mp,
|
||||
R.Map[int](F.Flow2(
|
||||
getAt(res),
|
||||
F.ToAny[IOE.IOEither[error, any]],
|
||||
)),
|
||||
IOE.Of[error, paramValue],
|
||||
)
|
||||
}
|
||||
},
|
||||
IOOption: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return F.Pipe2(
|
||||
mp,
|
||||
R.Map[int](F.Flow3(
|
||||
getAt(res),
|
||||
IOE.ToIOOption[error, any],
|
||||
F.ToAny[IOO.IOOption[any]],
|
||||
)),
|
||||
IOE.Of[error, paramValue],
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func getAt[T any](ar []T) func(idx int) T {
|
||||
return func(idx int) T {
|
||||
return ar[idx]
|
||||
}
|
||||
}
|
||||
|
||||
func handleMapping(mp mapping) func(res []IOE.IOEither[error, any]) IOE.IOEither[error, []any] {
|
||||
preFct := F.Pipe1(
|
||||
mp,
|
||||
R.Collect(func(idx int, p paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||
return handlers[idx](p)
|
||||
}),
|
||||
)
|
||||
doFct := F.Flow2(
|
||||
I.Flap[IOE.IOEither[error, paramValue], []IOE.IOEither[error, any]],
|
||||
IOE.TraverseArray[error, func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue], paramValue],
|
||||
)
|
||||
postFct := IOE.Map[error](F.Flow2(
|
||||
A.Fold(mergeMaps),
|
||||
collectParams,
|
||||
))
|
||||
|
||||
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, []any] {
|
||||
return F.Pipe2(
|
||||
preFct,
|
||||
doFct(res),
|
||||
postFct,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MakeProviderFactory constructs a [ProviderFactory] based on a set of [Dependency]s and
|
||||
// a function that accepts the resolved dependencies to return a result
|
||||
func MakeProviderFactory(
|
||||
deps []Dependency,
|
||||
fct func(param ...any) IOE.IOEither[error, any]) ProviderFactory {
|
||||
|
||||
return F.Flow3(
|
||||
mapDeps(deps),
|
||||
handleMapping(foldDeps(deps)),
|
||||
IOE.Chain(F.Unvariadic0(fct)),
|
||||
)
|
||||
}
|
45
di/erasure/token.go
Normal file
45
di/erasure/token.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 erasure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
const (
|
||||
BehaviourMask = 0x0f
|
||||
Identity = 0 // required dependency
|
||||
Option = 1 // optional dependency
|
||||
IOEither = 2 // lazy and required
|
||||
IOOption = 3 // lazy and optional
|
||||
|
||||
TypeMask = 0xf0
|
||||
Multi = 1 << 4 // array of implementations
|
||||
Item = 2 << 4 // item of a multi token
|
||||
)
|
||||
|
||||
// Dependency describes the relationship to a service
|
||||
type Dependency interface {
|
||||
fmt.Stringer
|
||||
// Id returns a unique identifier for a token that can be used as a cache key
|
||||
Id() string
|
||||
// Flag returns a tag that identifies the behaviour of the dependency
|
||||
Flag() int
|
||||
// ProviderFactory optionally returns an attached [ProviderFactory] that represents the default for this dependency
|
||||
ProviderFactory() O.Option[ProviderFactory]
|
||||
}
|
32
di/injector.go
Normal file
32
di/injector.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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 di
|
||||
|
||||
import (
|
||||
DIE "github.com/IBM/fp-go/di/erasure"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IG "github.com/IBM/fp-go/identity/generic"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
RIOE "github.com/IBM/fp-go/readerioeither"
|
||||
)
|
||||
|
||||
// Resolve performs a type safe resolution of a dependency
|
||||
func Resolve[T any](token InjectionToken[T]) RIOE.ReaderIOEither[DIE.InjectableFactory, error, T] {
|
||||
return F.Flow2(
|
||||
IG.Ap[DIE.InjectableFactory](asDependency(token)),
|
||||
IOE.ChainEitherK(token.Unerase),
|
||||
)
|
||||
}
|
79
di/provider.go
Normal file
79
di/provider.go
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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 di
|
||||
|
||||
import (
|
||||
A "github.com/IBM/fp-go/array"
|
||||
DIE "github.com/IBM/fp-go/di/erasure"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
)
|
||||
|
||||
func lookupAt[T any](idx int, token Dependency[T]) func(params []any) E.Either[error, T] {
|
||||
return F.Flow3(
|
||||
A.Lookup[any](idx),
|
||||
E.FromOption[any](errors.OnNone("No parameter at position %d", idx)),
|
||||
E.Chain(token.Unerase),
|
||||
)
|
||||
}
|
||||
|
||||
func eraseTuple[A, R any](f func(A) IOE.IOEither[error, R]) func(E.Either[error, A]) IOE.IOEither[error, any] {
|
||||
return F.Flow3(
|
||||
IOE.FromEither[error, A],
|
||||
IOE.Chain(f),
|
||||
IOE.Map[error](F.ToAny[R]),
|
||||
)
|
||||
}
|
||||
|
||||
func eraseProviderFactory0[R any](f IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
||||
return func(params ...any) IOE.IOEither[error, any] {
|
||||
return F.Pipe1(
|
||||
f,
|
||||
IOE.Map[error](F.ToAny[R]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func MakeProviderFactory0[R any](
|
||||
fct IOE.IOEither[error, R],
|
||||
) DIE.ProviderFactory {
|
||||
return DIE.MakeProviderFactory(
|
||||
A.Empty[DIE.Dependency](),
|
||||
eraseProviderFactory0(fct),
|
||||
)
|
||||
}
|
||||
|
||||
// MakeTokenWithDefault0 creates a unique [InjectionToken] for a specific type with an attached default [DIE.Provider]
|
||||
func MakeTokenWithDefault0[R any](name string, fct IOE.IOEither[error, R]) InjectionToken[R] {
|
||||
return MakeTokenWithDefault[R](name, MakeProviderFactory0(fct))
|
||||
}
|
||||
|
||||
func MakeProvider0[R any](
|
||||
token InjectionToken[R],
|
||||
fct IOE.IOEither[error, R],
|
||||
) DIE.Provider {
|
||||
return DIE.MakeProvider(
|
||||
token,
|
||||
MakeProviderFactory0(fct),
|
||||
)
|
||||
}
|
||||
|
||||
// ConstProvider simple implementation for a provider with a constant value
|
||||
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
|
||||
return MakeProvider0[R](token, IOE.Of[error](value))
|
||||
}
|
346
di/provider_test.go
Normal file
346
di/provider_test.go
Normal file
@@ -0,0 +1,346 @@
|
||||
// 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 di
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
DIE "github.com/IBM/fp-go/di/erasure"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
INJ_KEY2 = MakeToken[string]("INJ_KEY2")
|
||||
INJ_KEY1 = MakeToken[string]("INJ_KEY1")
|
||||
INJ_KEY3 = MakeToken[string]("INJ_KEY3")
|
||||
)
|
||||
|
||||
func TestSimpleProvider(t *testing.T) {
|
||||
|
||||
var staticCount int
|
||||
|
||||
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
staticCount++
|
||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
var dynamicCount int
|
||||
|
||||
dynamicValue := func(value string) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
dynamicCount++
|
||||
return E.Of[error](fmt.Sprintf("Dynamic based on [%s] at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
p1 := MakeProvider0(INJ_KEY1, staticValue("Carsten"))
|
||||
p2 := MakeProvider1(INJ_KEY2, INJ_KEY1.Identity(), dynamicValue)
|
||||
|
||||
inj := DIE.MakeInjector(A.From(p1, p2))
|
||||
|
||||
i1 := Resolve(INJ_KEY1)
|
||||
i2 := Resolve(INJ_KEY2)
|
||||
|
||||
res := IOE.SequenceT4(
|
||||
i2(inj),
|
||||
i1(inj),
|
||||
i2(inj),
|
||||
i1(inj),
|
||||
)
|
||||
|
||||
r := res()
|
||||
|
||||
assert.True(t, E.IsRight(r))
|
||||
assert.Equal(t, 1, staticCount)
|
||||
assert.Equal(t, 1, dynamicCount)
|
||||
}
|
||||
|
||||
func TestOptionalProvider(t *testing.T) {
|
||||
|
||||
var staticCount int
|
||||
|
||||
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
staticCount++
|
||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
var dynamicCount int
|
||||
|
||||
dynamicValue := func(value O.Option[string]) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
dynamicCount++
|
||||
return E.Of[error](fmt.Sprintf("Dynamic based on [%s] at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
p1 := MakeProvider0(INJ_KEY1, staticValue("Carsten"))
|
||||
p2 := MakeProvider1(INJ_KEY2, INJ_KEY1.Option(), dynamicValue)
|
||||
|
||||
inj := DIE.MakeInjector(A.From(p1, p2))
|
||||
|
||||
i1 := Resolve(INJ_KEY1)
|
||||
i2 := Resolve(INJ_KEY2)
|
||||
|
||||
res := IOE.SequenceT4(
|
||||
i2(inj),
|
||||
i1(inj),
|
||||
i2(inj),
|
||||
i1(inj),
|
||||
)
|
||||
|
||||
r := res()
|
||||
|
||||
assert.True(t, E.IsRight(r))
|
||||
assert.Equal(t, 1, staticCount)
|
||||
assert.Equal(t, 1, dynamicCount)
|
||||
}
|
||||
|
||||
func TestOptionalProviderMissingDependency(t *testing.T) {
|
||||
|
||||
var dynamicCount int
|
||||
|
||||
dynamicValue := func(value O.Option[string]) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
dynamicCount++
|
||||
return E.Of[error](fmt.Sprintf("Dynamic based on [%s] at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
p2 := MakeProvider1(INJ_KEY2, INJ_KEY1.Option(), dynamicValue)
|
||||
|
||||
inj := DIE.MakeInjector(A.From(p2))
|
||||
|
||||
i2 := Resolve(INJ_KEY2)
|
||||
|
||||
res := IOE.SequenceT2(
|
||||
i2(inj),
|
||||
i2(inj),
|
||||
)
|
||||
|
||||
r := res()
|
||||
|
||||
assert.True(t, E.IsRight(r))
|
||||
assert.Equal(t, 1, dynamicCount)
|
||||
}
|
||||
|
||||
func TestProviderMissingDependency(t *testing.T) {
|
||||
|
||||
var dynamicCount int
|
||||
|
||||
dynamicValue := func(value string) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
dynamicCount++
|
||||
return E.Of[error](fmt.Sprintf("Dynamic based on [%s] at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
p2 := MakeProvider1(INJ_KEY2, INJ_KEY1.Identity(), dynamicValue)
|
||||
|
||||
inj := DIE.MakeInjector(A.From(p2))
|
||||
|
||||
i2 := Resolve(INJ_KEY2)
|
||||
|
||||
res := IOE.SequenceT2(
|
||||
i2(inj),
|
||||
i2(inj),
|
||||
)
|
||||
|
||||
r := res()
|
||||
|
||||
assert.True(t, E.IsLeft(r))
|
||||
assert.Equal(t, 0, dynamicCount)
|
||||
}
|
||||
|
||||
func TestEagerAndLazyProvider(t *testing.T) {
|
||||
|
||||
var staticCount int
|
||||
|
||||
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
staticCount++
|
||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
var dynamicCount int
|
||||
|
||||
dynamicValue := func(value string) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
dynamicCount++
|
||||
return E.Of[error](fmt.Sprintf("Dynamic based on [%s] at [%s]", value, time.Now()))
|
||||
}
|
||||
}
|
||||
|
||||
var lazyEagerCount int
|
||||
|
||||
lazyEager := func(laz IOE.IOEither[error, string], eager string) IOE.IOEither[error, string] {
|
||||
return F.Pipe1(
|
||||
laz,
|
||||
IOE.Chain(func(lazValue string) IOE.IOEither[error, string] {
|
||||
return func() E.Either[error, string] {
|
||||
lazyEagerCount++
|
||||
return E.Of[error](fmt.Sprintf("Dynamic based on [%s], [%s] at [%s]", lazValue, eager, time.Now()))
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
p1 := MakeProvider0(INJ_KEY1, staticValue("Carsten"))
|
||||
p2 := MakeProvider1(INJ_KEY2, INJ_KEY1.Identity(), dynamicValue)
|
||||
p3 := MakeProvider2(INJ_KEY3, INJ_KEY2.IOEither(), INJ_KEY1.Identity(), lazyEager)
|
||||
|
||||
inj := DIE.MakeInjector(A.From(p1, p2, p3))
|
||||
|
||||
i3 := Resolve(INJ_KEY3)
|
||||
|
||||
r := i3(inj)()
|
||||
|
||||
fmt.Println(r)
|
||||
|
||||
assert.True(t, E.IsRight(r))
|
||||
assert.Equal(t, 1, staticCount)
|
||||
assert.Equal(t, 1, dynamicCount)
|
||||
assert.Equal(t, 1, lazyEagerCount)
|
||||
}
|
||||
|
||||
func TestItemProvider(t *testing.T) {
|
||||
// define a multi token
|
||||
injMulti := MakeMultiToken[string]("configs")
|
||||
|
||||
// provide some values
|
||||
v1 := ConstProvider(injMulti.Item(), "Value1")
|
||||
v2 := ConstProvider(injMulti.Item(), "Value2")
|
||||
// mix in non-multi values
|
||||
p1 := ConstProvider(INJ_KEY1, "Value3")
|
||||
p2 := ConstProvider(INJ_KEY2, "Value4")
|
||||
|
||||
// populate the injector
|
||||
inj := DIE.MakeInjector(A.From(p1, v1, p2, v2))
|
||||
|
||||
// access the multi value
|
||||
multi := Resolve(injMulti.Container())
|
||||
|
||||
multiInj := multi(inj)
|
||||
|
||||
value := multiInj()
|
||||
|
||||
assert.Equal(t, E.Of[error](A.From("Value1", "Value2")), value)
|
||||
}
|
||||
|
||||
func TestEmptyItemProvider(t *testing.T) {
|
||||
// define a multi token
|
||||
injMulti := MakeMultiToken[string]("configs")
|
||||
|
||||
// mix in non-multi values
|
||||
p1 := ConstProvider(INJ_KEY1, "Value3")
|
||||
p2 := ConstProvider(INJ_KEY2, "Value4")
|
||||
|
||||
// populate the injector
|
||||
inj := DIE.MakeInjector(A.From(p1, p2))
|
||||
|
||||
// access the multi value
|
||||
multi := Resolve(injMulti.Container())
|
||||
|
||||
multiInj := multi(inj)
|
||||
|
||||
value := multiInj()
|
||||
|
||||
assert.Equal(t, E.Of[error](A.Empty[string]()), value)
|
||||
}
|
||||
|
||||
func TestDependencyOnMultiProvider(t *testing.T) {
|
||||
// define a multi token
|
||||
injMulti := MakeMultiToken[string]("configs")
|
||||
|
||||
// provide some values
|
||||
v1 := ConstProvider(injMulti.Item(), "Value1")
|
||||
v2 := ConstProvider(injMulti.Item(), "Value2")
|
||||
// mix in non-multi values
|
||||
p1 := ConstProvider(INJ_KEY1, "Value3")
|
||||
p2 := ConstProvider(INJ_KEY2, "Value4")
|
||||
|
||||
fromMulti := func(val string, multi []string) IOE.IOEither[error, string] {
|
||||
return IOE.Of[error](fmt.Sprintf("Val: %s, Multi: %s", val, multi))
|
||||
}
|
||||
p3 := MakeProvider2(INJ_KEY3, INJ_KEY1.Identity(), injMulti.Container().Identity(), fromMulti)
|
||||
|
||||
// populate the injector
|
||||
inj := DIE.MakeInjector(A.From(p1, p2, v1, v2, p3))
|
||||
|
||||
r3 := Resolve(INJ_KEY3)
|
||||
|
||||
v := r3(inj)()
|
||||
|
||||
assert.Equal(t, E.Of[error]("Val: Value3, Multi: [Value1 Value2]"), v)
|
||||
}
|
||||
|
||||
func TestTokenWithDefaultProvider(t *testing.T) {
|
||||
// token without a default
|
||||
injToken1 := MakeToken[string]("Token1")
|
||||
// token with a default
|
||||
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
|
||||
// dependency
|
||||
injToken3 := MakeToken[string]("Token3")
|
||||
|
||||
p3 := MakeProvider1(injToken3, injToken2.Identity(), func(data string) IOE.IOEither[error, string] {
|
||||
return IOE.Of[error](fmt.Sprintf("Token: %s", data))
|
||||
})
|
||||
|
||||
// populate the injector
|
||||
inj := DIE.MakeInjector(A.From(p3))
|
||||
|
||||
// resolving injToken3 should work and use the default provider for injToken2
|
||||
r1 := Resolve(injToken1)
|
||||
r3 := Resolve(injToken3)
|
||||
|
||||
// inj1 should not be available
|
||||
assert.True(t, E.IsLeft(r1(inj)()))
|
||||
// r3 should work
|
||||
assert.Equal(t, E.Of[error]("Token: Carsten"), r3(inj)())
|
||||
}
|
||||
|
||||
func TestTokenWithDefaultProviderAndOverride(t *testing.T) {
|
||||
// token with a default
|
||||
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
|
||||
// dependency
|
||||
injToken3 := MakeToken[string]("Token3")
|
||||
|
||||
p2 := ConstProvider(injToken2, "Override")
|
||||
|
||||
p3 := MakeProvider1(injToken3, injToken2.Identity(), func(data string) IOE.IOEither[error, string] {
|
||||
return IOE.Of[error](fmt.Sprintf("Token: %s", data))
|
||||
})
|
||||
|
||||
// populate the injector
|
||||
inj := DIE.MakeInjector(A.From(p2, p3))
|
||||
|
||||
// resolving injToken3 should work and use the default provider for injToken2
|
||||
r3 := Resolve(injToken3)
|
||||
|
||||
// r3 should work
|
||||
assert.Equal(t, E.Of[error]("Token: Override"), r3(inj)())
|
||||
}
|
197
di/token.go
Normal file
197
di/token.go
Normal file
@@ -0,0 +1,197 @@
|
||||
// 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 di
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
|
||||
DIE "github.com/IBM/fp-go/di/erasure"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
IOO "github.com/IBM/fp-go/iooption"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// Dependency describes the relationship to a service, that has a type and
|
||||
// a behaviour such as required, option or lazy
|
||||
type Dependency[T any] interface {
|
||||
DIE.Dependency
|
||||
// Unerase converts a value with erased type signature into a strongly typed value
|
||||
Unerase(val any) E.Either[error, T]
|
||||
}
|
||||
|
||||
// InjectionToken uniquely identifies a dependency by giving it an Id, Type and name
|
||||
type InjectionToken[T any] interface {
|
||||
Dependency[T]
|
||||
// Identity idenifies this dependency as a mandatory, required dependency, it will be resolved eagerly and injected as `T`.
|
||||
// If the dependency cannot be resolved, the resolution process fails
|
||||
Identity() Dependency[T]
|
||||
// Option identifies this dependency as optional, it will be resolved eagerly and injected as [O.Option[T]].
|
||||
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as [O.None[T]]
|
||||
Option() Dependency[O.Option[T]]
|
||||
// IOEither identifies this dependency as mandatory but it will be resolved lazily as a [IOE.IOEither[error, T]]. This
|
||||
// value is memoized to make sure the dependency is a singleton.
|
||||
// If the dependency cannot be resolved, the resolution process fails
|
||||
IOEither() Dependency[IOE.IOEither[error, T]]
|
||||
// IOOption identifies this dependency as optional but it will be resolved lazily as a [IOO.IOOption[T]]. This
|
||||
// value is memoized to make sure the dependency is a singleton.
|
||||
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as the none value.
|
||||
IOOption() Dependency[IOO.IOOption[T]]
|
||||
}
|
||||
|
||||
// MultiInjectionToken uniquely identifies a dependency by giving it an Id, Type and name that can have multiple implementations.
|
||||
// Implementations are provided via the [MultiInjectionToken.Item] injection token.
|
||||
type MultiInjectionToken[T any] interface {
|
||||
// Container returns the injection token used to request an array of all provided items
|
||||
Container() InjectionToken[[]T]
|
||||
// Item returns the injection token used to provide an item
|
||||
Item() InjectionToken[T]
|
||||
}
|
||||
|
||||
// makeID creates a generator of unique string IDs
|
||||
func makeId() IO.IO[string] {
|
||||
var count atomic.Int64
|
||||
return IO.MakeIO(func() string {
|
||||
return strconv.FormatInt(count.Add(1), 16)
|
||||
})
|
||||
}
|
||||
|
||||
// genId is the common generator of unique string IDs
|
||||
var genId = makeId()
|
||||
|
||||
type token[T any] struct {
|
||||
name string
|
||||
id string
|
||||
flag int
|
||||
toType func(val any) E.Either[error, T]
|
||||
providerFactory O.Option[DIE.ProviderFactory]
|
||||
}
|
||||
|
||||
func (t *token[T]) Id() string {
|
||||
return t.id
|
||||
}
|
||||
|
||||
func (t *token[T]) Flag() int {
|
||||
return t.flag
|
||||
}
|
||||
|
||||
func (t *token[T]) String() string {
|
||||
return t.name
|
||||
}
|
||||
|
||||
func (t *token[T]) Unerase(val any) E.Either[error, T] {
|
||||
return t.toType(val)
|
||||
}
|
||||
|
||||
func (t *token[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
|
||||
return t.providerFactory
|
||||
}
|
||||
|
||||
func makeToken[T any](name string, id string, typ int, unerase func(val any) E.Either[error, T], providerFactory O.Option[DIE.ProviderFactory]) Dependency[T] {
|
||||
return &token[T]{name, id, typ, unerase, providerFactory}
|
||||
}
|
||||
|
||||
type injectionToken[T any] struct {
|
||||
token[T]
|
||||
option Dependency[O.Option[T]]
|
||||
ioeither Dependency[IOE.IOEither[error, T]]
|
||||
iooption Dependency[IOO.IOOption[T]]
|
||||
}
|
||||
|
||||
type multiInjectionToken[T any] struct {
|
||||
container *injectionToken[[]T]
|
||||
item *injectionToken[T]
|
||||
}
|
||||
|
||||
func (i *injectionToken[T]) Identity() Dependency[T] {
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *injectionToken[T]) Option() Dependency[O.Option[T]] {
|
||||
return i.option
|
||||
}
|
||||
|
||||
func (i *injectionToken[T]) IOEither() Dependency[IOE.IOEither[error, T]] {
|
||||
return i.ioeither
|
||||
}
|
||||
|
||||
func (i *injectionToken[T]) IOOption() Dependency[IOO.IOOption[T]] {
|
||||
return i.iooption
|
||||
}
|
||||
|
||||
func (i *injectionToken[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
|
||||
return i.providerFactory
|
||||
}
|
||||
|
||||
func (m *multiInjectionToken[T]) Container() InjectionToken[[]T] {
|
||||
return m.container
|
||||
}
|
||||
|
||||
func (m *multiInjectionToken[T]) Item() InjectionToken[T] {
|
||||
return m.item
|
||||
}
|
||||
|
||||
// makeToken create a unique [InjectionToken] for a specific type
|
||||
func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.ProviderFactory]) InjectionToken[T] {
|
||||
id := genId()
|
||||
toIdentity := toType[T]()
|
||||
return &injectionToken[T]{
|
||||
token[T]{name, id, DIE.Identity, toIdentity, providerFactory},
|
||||
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", name), id, DIE.Option, toOptionType(toIdentity), providerFactory),
|
||||
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", name), id, DIE.IOEither, toIOEitherType(toIdentity), providerFactory),
|
||||
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", name), id, DIE.IOOption, toIOOptionType(toIdentity), providerFactory),
|
||||
}
|
||||
}
|
||||
|
||||
// MakeToken create a unique [InjectionToken] for a specific type
|
||||
func MakeToken[T any](name string) InjectionToken[T] {
|
||||
return makeInjectionToken[T](name, O.None[DIE.ProviderFactory]())
|
||||
}
|
||||
|
||||
// MakeToken create a unique [InjectionToken] for a specific type
|
||||
func MakeTokenWithDefault[T any](name string, providerFactory DIE.ProviderFactory) InjectionToken[T] {
|
||||
return makeInjectionToken[T](name, O.Of(providerFactory))
|
||||
}
|
||||
|
||||
// MakeMultiToken creates a [MultiInjectionToken]
|
||||
func MakeMultiToken[T any](name string) MultiInjectionToken[T] {
|
||||
id := genId()
|
||||
toItem := toType[T]()
|
||||
toContainer := toArrayType(toItem)
|
||||
containerName := fmt.Sprintf("Container[%s]", name)
|
||||
itemName := fmt.Sprintf("Item[%s]", name)
|
||||
// empty factory
|
||||
providerFactory := O.None[DIE.ProviderFactory]()
|
||||
// container
|
||||
container := &injectionToken[[]T]{
|
||||
token[[]T]{containerName, id, DIE.Multi | DIE.Identity, toContainer, providerFactory},
|
||||
makeToken[O.Option[[]T]](fmt.Sprintf("Option[%s]", containerName), id, DIE.Multi|DIE.Option, toOptionType(toContainer), providerFactory),
|
||||
makeToken[IOE.IOEither[error, []T]](fmt.Sprintf("IOEither[%s]", containerName), id, DIE.Multi|DIE.IOEither, toIOEitherType(toContainer), providerFactory),
|
||||
makeToken[IOO.IOOption[[]T]](fmt.Sprintf("IOOption[%s]", containerName), id, DIE.Multi|DIE.IOOption, toIOOptionType(toContainer), providerFactory),
|
||||
}
|
||||
// item
|
||||
item := &injectionToken[T]{
|
||||
token[T]{itemName, id, DIE.Item | DIE.Identity, toItem, providerFactory},
|
||||
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", itemName), id, DIE.Item|DIE.Option, toOptionType(toItem), providerFactory),
|
||||
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", itemName), id, DIE.Item|DIE.IOEither, toIOEitherType(toItem), providerFactory),
|
||||
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", itemName), id, DIE.Item|DIE.IOOption, toIOOptionType(toItem), providerFactory),
|
||||
}
|
||||
// returns the token
|
||||
return &multiInjectionToken[T]{container, item}
|
||||
}
|
77
di/utils.go
Normal file
77
di/utils.go
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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 di
|
||||
|
||||
import (
|
||||
DIE "github.com/IBM/fp-go/di/erasure"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
IOO "github.com/IBM/fp-go/iooption"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// asDependency converts a generic type to a [DIE.Dependency]
|
||||
func asDependency[T DIE.Dependency](t T) DIE.Dependency {
|
||||
return t
|
||||
}
|
||||
|
||||
// toType converts an any to a T
|
||||
func toType[T any]() func(t any) E.Either[error, T] {
|
||||
return E.ToType[T](errors.OnSome[any]("Value of type [%T] cannot be converted."))
|
||||
}
|
||||
|
||||
// toOptionType converts an any to an Option[any] and then to an Option[T]
|
||||
func toOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, O.Option[T]] {
|
||||
return F.Flow2(
|
||||
toType[O.Option[any]](),
|
||||
E.Chain(O.Fold(
|
||||
F.Nullary2(O.None[T], E.Of[error, O.Option[T]]),
|
||||
F.Flow2(
|
||||
item,
|
||||
E.Map[error](O.Of[T]),
|
||||
),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
// toIOEitherType converts an any to an IOEither[error, any] and then to an IOEither[error, T]
|
||||
func toIOEitherType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOE.IOEither[error, T]] {
|
||||
return F.Flow2(
|
||||
toType[IOE.IOEither[error, any]](),
|
||||
E.Map[error](IOE.ChainEitherK(item)),
|
||||
)
|
||||
}
|
||||
|
||||
// toIOOptionType converts an any to an IOOption[any] and then to an IOOption[T]
|
||||
func toIOOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOO.IOOption[T]] {
|
||||
return F.Flow2(
|
||||
toType[IOO.IOOption[any]](),
|
||||
E.Map[error](IOO.ChainOptionK(F.Flow2(
|
||||
item,
|
||||
E.ToOption[error, T],
|
||||
))),
|
||||
)
|
||||
}
|
||||
|
||||
// toArrayType converts an any to a []T
|
||||
func toArrayType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, []T] {
|
||||
return F.Flow2(
|
||||
toType[[]any](),
|
||||
E.Chain(E.TraverseArray(item)),
|
||||
)
|
||||
}
|
84
di/utils_test.go
Normal file
84
di/utils_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// 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 di
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
A "github.com/IBM/fp-go/array"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
toInt = toType[int]()
|
||||
toString = toType[string]()
|
||||
)
|
||||
|
||||
func TestToType(t *testing.T) {
|
||||
// good cases
|
||||
assert.Equal(t, E.Of[error](10), toInt(any(10)))
|
||||
assert.Equal(t, E.Of[error]("Carsten"), toString(any("Carsten")))
|
||||
assert.Equal(t, E.Of[error](O.Of("Carsten")), toType[O.Option[string]]()(any(O.Of("Carsten"))))
|
||||
assert.Equal(t, E.Of[error](O.Of(any("Carsten"))), toType[O.Option[any]]()(any(O.Of(any("Carsten")))))
|
||||
// failure
|
||||
assert.False(t, E.IsRight(toInt(any("Carsten"))))
|
||||
assert.False(t, E.IsRight(toType[O.Option[string]]()(O.Of(any("Carsten")))))
|
||||
}
|
||||
|
||||
func TestToOptionType(t *testing.T) {
|
||||
// shortcuts
|
||||
toOptInt := toOptionType(toInt)
|
||||
toOptString := toOptionType(toString)
|
||||
// good cases
|
||||
assert.Equal(t, E.Of[error](O.Of(10)), toOptInt(any(O.Of(any(10)))))
|
||||
assert.Equal(t, E.Of[error](O.Of("Carsten")), toOptString(any(O.Of(any("Carsten")))))
|
||||
// bad cases
|
||||
assert.False(t, E.IsRight(toOptInt(any(10))))
|
||||
assert.False(t, E.IsRight(toOptInt(any(O.Of(10)))))
|
||||
}
|
||||
|
||||
func invokeIOEither[T any](e E.Either[error, IOE.IOEither[error, T]]) E.Either[error, T] {
|
||||
return F.Pipe1(
|
||||
e,
|
||||
E.Chain(func(ioe IOE.IOEither[error, T]) E.Either[error, T] {
|
||||
return ioe()
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func TestToIOEitherType(t *testing.T) {
|
||||
// shortcuts
|
||||
toIOEitherInt := toIOEitherType(toInt)
|
||||
toIOEitherString := toIOEitherType(toString)
|
||||
// good cases
|
||||
assert.Equal(t, E.Of[error](10), invokeIOEither(toIOEitherInt(any(IOE.Of[error](any(10))))))
|
||||
assert.Equal(t, E.Of[error]("Carsten"), invokeIOEither(toIOEitherString(any(IOE.Of[error](any("Carsten"))))))
|
||||
// bad cases
|
||||
assert.False(t, E.IsRight(invokeIOEither(toIOEitherString(any(IOE.Of[error](any(10)))))))
|
||||
assert.False(t, E.IsRight(invokeIOEither(toIOEitherString(any(IOE.Of[error]("Carsten"))))))
|
||||
assert.False(t, E.IsRight(invokeIOEither(toIOEitherString(any("Carsten")))))
|
||||
}
|
||||
|
||||
func TestToArrayType(t *testing.T) {
|
||||
// shortcuts
|
||||
toArrayString := toArrayType(toString)
|
||||
// good cases
|
||||
assert.Equal(t, E.Of[error](A.From("a", "b")), toArrayString(any(A.From(any("a"), any("b")))))
|
||||
}
|
@@ -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)
|
||||
}
|
||||
|
||||
// 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]] {
|
||||
return M.ApplicativeMonoid(Of[E, A], MonadMap[E, A, func(A) A], MonadAp[A, E, A], m)
|
||||
}
|
||||
|
74
either/array.go
Normal file
74
either/array.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// 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 (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
RA "github.com/IBM/fp-go/internal/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] {
|
||||
return RA.Traverse[GA](
|
||||
Of[E, GB],
|
||||
Map[E, GB, func(B) GB],
|
||||
Ap[GB, E, B],
|
||||
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[E, A, B any](f func(A) Either[E, B]) func([]A) Either[E, []B] {
|
||||
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] {
|
||||
return TraverseArrayG[GOA, GA](F.Identity[Either[E, A]])(ma)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[E, A any](ma []Either[E, A]) Either[E, []A] {
|
||||
return SequenceArrayG[[]A](ma)
|
||||
}
|
||||
|
||||
// CompactArrayG discards the none values and keeps the right 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, 0, len(fa)))
|
||||
}
|
||||
|
||||
// CompactArray discards the none values and keeps the right values
|
||||
func CompactArray[E, A any](fa []Either[E, A]) []A {
|
||||
return CompactArrayG[[]Either[E, A], []A](fa)
|
||||
}
|
18
either/array_test.go
Normal file
18
either/array_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package either
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCompactArray(t *testing.T) {
|
||||
ar := []Either[string, string]{
|
||||
Of[string]("ok"),
|
||||
Left[string]("err"),
|
||||
Of[string]("ok"),
|
||||
}
|
||||
|
||||
res := CompactArray(ar)
|
||||
assert.Equal(t, 2, len(res))
|
||||
}
|
@@ -46,12 +46,12 @@ func (s Either[E, A]) Format(f fmt.State, c rune) {
|
||||
}
|
||||
}
|
||||
|
||||
// IsLeft tests if the either is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
|
||||
// IsLeft tests if the [Either] is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
|
||||
func IsLeft[E, A any](val Either[E, A]) bool {
|
||||
return val.isLeft
|
||||
}
|
||||
|
||||
// IsLeft tests if the either is a right value. Rather use [Fold] if you need to access the values. Inverse is [IsLeft].
|
||||
// IsLeft tests if the [Either] is a right value. Rather use [Fold] if you need to access the values. Inverse is [IsLeft].
|
||||
func IsRight[E, A any](val Either[E, A]) bool {
|
||||
return !val.isLeft
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package option defines the [Either] datastructure and its monadic operations
|
||||
package either
|
||||
|
||||
//go:generate go run .. either --count 10 --filename gen.go
|
||||
|
@@ -22,6 +22,8 @@ package either
|
||||
import (
|
||||
E "github.com/IBM/fp-go/errors"
|
||||
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"
|
||||
)
|
||||
|
||||
@@ -65,16 +67,17 @@ func MapTo[E, A, B any](b B) func(Either[E, A]) Either[E, B] {
|
||||
return F.Bind2nd(MonadMapTo[E, A, B], b)
|
||||
}
|
||||
|
||||
func MonadMapLeft[E, A, B any](fa Either[E, A], f func(E) B) Either[B, A] {
|
||||
return MonadFold(fa, F.Flow2(f, Left[A, B]), Right[B, A])
|
||||
func MonadMapLeft[E1, A, E2 any](fa Either[E1, A], f func(E1) E2) Either[E2, A] {
|
||||
return MonadFold(fa, F.Flow2(f, Left[A, E2]), Right[E2, A])
|
||||
}
|
||||
|
||||
func Map[E, A, B any](f func(a A) B) func(fa Either[E, A]) Either[E, B] {
|
||||
return Chain(F.Flow2(f, Right[E, B]))
|
||||
}
|
||||
|
||||
func MapLeft[E, A, B any](f func(E) B) func(fa Either[E, A]) Either[B, A] {
|
||||
return F.Bind2nd(MonadMapLeft[E, A, B], f)
|
||||
// MapLeft applies a mapping function to the error channel
|
||||
func MapLeft[A, E1, E2 any](f func(E1) E2) func(fa Either[E1, A]) Either[E2, A] {
|
||||
return F.Bind2nd(MonadMapLeft[E1, A, E2], f)
|
||||
}
|
||||
|
||||
func MonadChain[E, A, B any](fa Either[E, A], f func(a A) Either[E, B]) Either[E, B] {
|
||||
@@ -87,23 +90,23 @@ func MonadChainFirst[E, A, B any](ma Either[E, A], f func(a A) Either[E, B]) Eit
|
||||
})
|
||||
}
|
||||
|
||||
func MonadChainTo[E, A, B any](ma Either[E, A], mb Either[E, B]) Either[E, B] {
|
||||
func MonadChainTo[A, E, B any](ma Either[E, A], mb Either[E, B]) Either[E, B] {
|
||||
return mb
|
||||
}
|
||||
|
||||
func MonadChainOptionK[E, A, B 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)))
|
||||
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[B](onNone)))
|
||||
}
|
||||
|
||||
func ChainOptionK[E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
|
||||
from := FromOption[E, B](onNone)
|
||||
func ChainOptionK[A, B, E any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
|
||||
from := FromOption[B](onNone)
|
||||
return func(f func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
|
||||
return Chain(F.Flow2(f, from))
|
||||
}
|
||||
}
|
||||
|
||||
func ChainTo[E, A, B any](mb Either[E, B]) func(Either[E, A]) Either[E, B] {
|
||||
return F.Bind2nd(MonadChainTo[E, A, B], mb)
|
||||
func ChainTo[A, E, B any](mb Either[E, B]) func(Either[E, A]) Either[E, B] {
|
||||
return F.Bind2nd(MonadChainTo[A, E, B], mb)
|
||||
}
|
||||
|
||||
func Chain[E, A, B any](f func(a A) Either[E, B]) func(Either[E, A]) Either[E, B] {
|
||||
@@ -118,16 +121,15 @@ func Flatten[E, A any](mma Either[E, Either[E, A]]) Either[E, A] {
|
||||
return MonadChain(mma, F.Identity[Either[E, A]])
|
||||
}
|
||||
|
||||
func TryCatch[FA ~func() (A, error), FE func(error) E, E, A any](f FA, onThrow FE) Either[E, A] {
|
||||
val, err := f()
|
||||
func TryCatch[FE func(error) E, E, A any](val A, err error, onThrow FE) Either[E, A] {
|
||||
if err != nil {
|
||||
return F.Pipe2(err, onThrow, Left[A, E])
|
||||
}
|
||||
return F.Pipe1(val, Right[E, A])
|
||||
}
|
||||
|
||||
func TryCatchError[F ~func() (A, error), A any](f F) Either[error, A] {
|
||||
return TryCatch(f, E.IdentityError)
|
||||
func TryCatchError[A any](val A, err error) Either[error, A] {
|
||||
return TryCatch(val, err, E.IdentityError)
|
||||
}
|
||||
|
||||
func Sequence2[E, T1, T2, R any](f func(T1, T2) Either[E, R]) func(Either[E, T1], Either[E, T2]) Either[E, R] {
|
||||
@@ -142,19 +144,17 @@ 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])
|
||||
}
|
||||
|
||||
func ToOption[E, A any]() func(Either[E, A]) O.Option[A] {
|
||||
return Fold(F.Ignore1of1[E](O.None[A]), O.Some[A])
|
||||
func ToOption[E, A any](ma Either[E, A]) O.Option[A] {
|
||||
return MonadFold(ma, F.Ignore1of1[E](O.None[A]), O.Some[A])
|
||||
}
|
||||
|
||||
func FromError[A any](f func(a A) error) func(A) Either[error, A] {
|
||||
return func(a A) Either[error, A] {
|
||||
return TryCatchError(func() (A, error) {
|
||||
return a, f(a)
|
||||
})
|
||||
return TryCatchError(a, f(a))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func FromPredicate[E, A any](pred func(A) bool, onFalse func(A) E) func(A) Eithe
|
||||
}
|
||||
}
|
||||
|
||||
func FromNillable[E, A any](e E) func(*A) Either[E, *A] {
|
||||
func FromNillable[A, E any](e E) func(*A) Either[E, *A] {
|
||||
return FromPredicate(F.IsNonNil[A], F.Constant1[*A](e))
|
||||
}
|
||||
|
||||
@@ -197,11 +197,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])
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -209,7 +209,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])
|
||||
}
|
||||
|
||||
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 F.Pipe2(
|
||||
value,
|
||||
@@ -245,3 +245,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] {
|
||||
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) {
|
||||
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 {
|
||||
return O.Some(n)
|
||||
}
|
||||
@@ -112,6 +112,6 @@ func TestChainOptionK(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, Right[string](1), FromOption[string, int](F.Constant("none"))(O.Some(1)))
|
||||
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
|
||||
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
|
||||
}
|
||||
|
58
either/examples_create_test.go
Normal file
58
either/examples_create_test.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 either
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/IBM/fp-go/errors"
|
||||
)
|
||||
|
||||
func ExampleEither_creation() {
|
||||
// Build an Either
|
||||
leftValue := Left[string](fmt.Errorf("some error"))
|
||||
rightValue := Right[error]("value")
|
||||
|
||||
// Build from a value
|
||||
fromNillable := FromNillable[string](fmt.Errorf("value was nil"))
|
||||
leftFromNil := fromNillable(nil)
|
||||
value := "value"
|
||||
rightFromPointer := fromNillable(&value)
|
||||
|
||||
// some predicate
|
||||
isEven := func(num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
fromEven := FromPredicate(isEven, errors.OnSome[int]("%d is an odd number"))
|
||||
leftFromPred := fromEven(3)
|
||||
rightFromPred := fromEven(4)
|
||||
|
||||
fmt.Println(leftValue)
|
||||
fmt.Println(rightValue)
|
||||
fmt.Println(leftFromNil)
|
||||
fmt.Println(IsRight(rightFromPointer))
|
||||
fmt.Println(leftFromPred)
|
||||
fmt.Println(rightFromPred)
|
||||
|
||||
// Output:
|
||||
// Left[*errors.errorString, string](some error)
|
||||
// Right[<nil>, string](value)
|
||||
// Left[*errors.errorString, *string](value was nil)
|
||||
// true
|
||||
// Left[*errors.errorString, int](3 is an odd number)
|
||||
// Right[<nil>, int](4)
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user