1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-08-26 19:38:58 +02:00

Compare commits

...

57 Commits

Author SHA1 Message Date
Carsten Leue
3ccafb5302 Merge pull request #35 from IBM/cleue-mostly-adequate-capter10
Add more examples for mostly-adequate
2023-09-06 15:15:00 +02:00
Dr. Carsten Leue
52b71ef4f3 fix: add more examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-05 22:51:46 +02:00
Dr. Carsten Leue
5d77d5bb3d fix: add sample app for rendering cat images
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-04 22:55:14 +02:00
Dr. Carsten Leue
8ba8f852fa Merge branch 'main' into cleue-mostly-adequate-capter10 2023-09-04 22:35:13 +02:00
Carsten Leue
29d9882d2a Merge pull request #34 from IBM/cleue-request-builder-example
doc: document how to use a request builder for http
2023-09-04 11:15:28 +02:00
Dr. Carsten Leue
f80ca31e14 doc: document how to use a request builder for http
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-04 11:13:58 +02:00
Dr. Carsten Leue
8692078972 doc: add examples and solutions from mostly adequate
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-03 22:21:23 +02:00
Dr. Carsten Leue
12a4f6801c fix: add ap sample
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-02 14:30:01 +02:00
Carsten Leue
8650a8a600 Merge pull request #33 from IBM/cleue-mostly-adequate-fp-go
fix: add examples for [Frisby's Mostly Adequate Guide]
2023-09-01 17:50:59 +02:00
Dr. Carsten Leue
fb3b1f115c fix: add examples for [Frisby's Mostly Adequate Guide] 2023-09-01 17:31:47 +02:00
Carsten Leue
ce66cf2295 Merge pull request #31 from IBM/cleue-add-cache
fix: implement simple cache for pure functions
2023-08-31 11:07:46 +02:00
Dr. Carsten Leue
80e579dd0b fix: implement simple cache for pure functions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-31 10:27:32 +02:00
Carsten Leue
ddafd1ee57 Merge pull request #30 from IBM/cleue-sample-ioeither
Add samples for IOEither
2023-08-29 09:16:17 +02:00
Dr. Carsten Leue
b5f077da71 fix: remove types from this branch
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-29 09:11:03 +02:00
Dr. Carsten Leue
1a0c40b419 fix: add helpers for reflect types
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-25 22:53:09 +02:00
Carsten Leue
d5d89b1853 fix: add runtime type validation
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-24 22:49:03 +02:00
Carsten Leue
0f061a5099 fix: initial implementation of types
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-22 22:34:05 +02:00
Carsten Leue
45e05f25ff Merge pull request #27 from jdbaldry/main-1
Fix a couple of spelling errors
2023-08-21 14:49:54 +02:00
Carsten Leue
a390d53451 add: bind to IOEither
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-18 22:15:26 +02:00
Jack Baldry
1346b9378a Fix a couple spelling errors 2023-08-18 09:45:27 +01:00
Carsten Leue
befd4f471e fix: add basic bind as do notation
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-17 23:03:03 +02:00
Carsten Leue
db8d3da87a Merge pull request #26 from IBM/cleue-more-samples
fix: add array examples
2023-08-11 22:32:26 +02:00
Dr. Carsten Leue
ee4e936183 fix: add array examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 22:31:36 +02:00
Carsten Leue
0064ac1c75 Merge pull request #25 from IBM/cleue-fix-build-break-1
fix: build break
2023-08-11 17:32:07 +02:00
Dr. Carsten Leue
8944a66c18 fix: build break
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 17:31:31 +02:00
Carsten Leue
bd0c42db01 Merge pull request #24 from IBM/cleue-add-disclaimer
fix: add more examples
2023-08-11 16:26:58 +02:00
Dr. Carsten Leue
e9f03e2d26 fix: add more examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 16:26:15 +02:00
Carsten Leue
bb630810fc Merge pull request #23 from IBM/cleue-better-docs
fix: experiment with docs and examples
2023-08-11 12:08:51 +02:00
Dr. Carsten Leue
9ba9eaacbe fix: experiment with docs and examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 11:56:11 +02:00
Carsten Leue
a9f6839acd Merge pull request #22 from IBM/cleue-add-FoldMap
fix: implement FoldMap
2023-08-10 18:08:48 +02:00
Dr. Carsten Leue
1b1dccc551 fix: implement FoldMap
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 18:08:11 +02:00
Carsten Leue
39c6108bf5 Merge pull request #21 from IBM/cleue-fix-buildbreak
fix: build break
2023-08-10 13:24:28 +02:00
Dr. Carsten Leue
83e1ff30c1 chore: test on multiple versions of go
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 13:22:31 +02:00
Dr. Carsten Leue
d9dda4cfa5 fix: build break
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 13:14:48 +02:00
Carsten Leue
d9b2804a7e Merge pull request #20 from IBM/cleue-add-FilterChain-operations
fix: implement FilterChain
2023-08-10 11:47:07 +02:00
Dr. Carsten Leue
c0028918ae fix: implement FilterChain
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 11:46:30 +02:00
Carsten Leue
cd53cb7036 Merge pull request #19 from IBM/cleue-implement-first-and-last
fix: add first and last
2023-08-07 22:36:12 +02:00
Dr. Carsten Leue
469c60f05d fix: add first and last
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-07 22:35:06 +02:00
Carsten Leue
74fd0c96e7 Merge pull request #18 from IBM/cleue-add-some-more-itertools
fix: more iterator functions
2023-08-04 17:12:50 +02:00
Dr. Carsten Leue
e53e2c53e8 fix: more iterator functions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-04 17:12:24 +02:00
Carsten Leue
2cd35870cb Merge pull request #17 from IBM/cleue-add-take
fix: add Take to Iterables
2023-08-03 15:33:05 +02:00
Dr. Carsten Leue
411caa6dff fix: add Take to Iterables
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-03 15:32:27 +02:00
Carsten Leue
d69a13ecf4 Merge pull request #16 from IBM/cleue-add-zip
Cleue add zip
2023-08-03 14:34:09 +02:00
Dr. Carsten Leue
4ed0046971 fix: add uniq
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-03 14:32:46 +02:00
Dr. Carsten Leue
e4fd34a6b5 fix: add Zip and ZipWith to iterators
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-03 13:27:41 +02:00
Carsten Leue
89265eed7c Merge pull request #15 from IBM/cleue-implement-with-temp-file
fix: add WithTempFile
2023-07-30 16:05:00 +02:00
Dr. Carsten Leue
fbc6757f82 fix: add WithTempFile
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-30 16:04:37 +02:00
Carsten Leue
a12936a86c Merge pull request #14 from IBM/cleue-add-missing-methods
fix: add missing array traversal to either
2023-07-28 22:51:34 +02:00
Dr. Carsten Leue
94bcfde0d3 fix: add missing array traversal to either
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-28 22:50:52 +02:00
Carsten Leue
4e1cb825e7 Merge pull request #13 from IBM/cleue-add-more-generated-code
fix: add support for JSON serialization on tuples
2023-07-28 15:50:30 +02:00
Dr. Carsten Leue
9988ae27ef fix: add support for JSON serialization on tuples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-28 15:50:03 +02:00
Carsten Leue
903669c1bc Merge pull request #12 from IBM/cleue-more-iterator
Add more iterators and auto generate sequence operations
2023-07-27 23:06:33 +02:00
Dr. Carsten Leue
dc836fd0be fix: add some typical usecases to readme
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-27 23:05:12 +02:00
Dr. Carsten Leue
47a6d3c177 fix: auto generate more sequence operations
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-27 22:39:38 +02:00
Dr. Carsten Leue
d2346b016e fix: add Ap for iterators
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-25 17:34:32 +02:00
Carsten Leue
41b792b23a Merge pull request #11 from IBM/cleue-better-doc
fix: introduce stateless iterator
2023-07-24 16:44:12 +02:00
Dr. Carsten Leue
1713de0c3e fix: introduce stateless iterator
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-24 16:43:07 +02:00
206 changed files with 12786 additions and 645 deletions

View File

@@ -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
GO_VERSION: 1.20.6 # renovate: datasource=golang-version depName=golang
NODE_VERSION: 18
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
with:
fetch-depth: 0
- name: Set up go ${{env.GO_VERSION}}
- name: Set up go ${{ matrix.go-version }}
uses: actions/setup-go@v4
with:
go-version: ${{env.GO_VERSION}}
go-version: ${{ matrix.go-version }}
-
name: Tests
run: |

View File

@@ -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.
![logo](resources/images/logo.png)
@@ -12,7 +12,7 @@ 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/).
## Design Goal
@@ -65,7 +65,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,6 +73,40 @@ 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.
## 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.
### Pure functions
Pure functions are functions that take input parameters and that compute an output without changing any global state and without mutating the input parameters. They will always return the same output for the same input.
#### Without Errors
If your pure function does not return an error, the idiomatic signature is just fine and no changes are required.
#### 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]](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]](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]](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]](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]](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
### Generics
@@ -147,7 +181,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]

View File

@@ -108,10 +108,16 @@ func MonadFilterMap[A, B any](fa []A, f func(a A) O.Option[B]) []B {
return G.MonadFilterMap[[]A, []B](fa, f)
}
// FilterChain 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 A) O.Option[B]) func([]A) []B {
return G.FilterMap[[]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)
@@ -144,7 +150,7 @@ func Append[A any](as []A, a A) []A {
}
func IsEmpty[A any](as []A) bool {
return array.IsEmpty(as)
return G.IsEmpty(as)
}
func IsNonEmpty[A any](as []A) bool {
@@ -181,12 +187,11 @@ func Ap[B, A any](fa []A) func([]func(A) B) []B {
}
func Match[A, B any](onEmpty func() B, onNonEmpty func([]A) B) func([]A) B {
return func(as []A) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as)
}
return G.Match[[]A](onEmpty, onNonEmpty)
}
func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A) B {
return G.MatchLeft[[]A](onEmpty, onNonEmpty)
}
func Tail[A any](as []A) O.Option[[]A] {
@@ -231,14 +236,14 @@ func Intersperse[A any](middle A) func([]A) []A {
}
func Intercalate[A any](m M.Monoid[A]) func(A) func([]A) A {
concatAll := ConcatAll[A](m)(m.Empty())
concatAll := ConcatAll[A](m)
return func(middle A) func([]A) A {
return Match(m.Empty, F.Flow2(Intersperse(middle), concatAll))
}
}
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 {
@@ -281,3 +286,25 @@ func IsNonNil[A any](as []A) bool {
func ConstNil[A any]() []A {
return array.ConstNil[[]A]()
}
func SliceRight[A any](start int) func([]A) []A {
return G.SliceRight[[]A](start)
}
func Copy[A any](b []A) []A {
return G.Copy(b)
}
// 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)
}
// 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) func([]A) []A {
return G.Push[[]A](a)
}

View File

@@ -16,6 +16,7 @@
package array
import (
"fmt"
"strings"
"testing"
@@ -142,3 +143,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
}

View 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]
}

View 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}}]
}

View File

@@ -18,6 +18,7 @@ package generic
import (
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array"
M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/option"
"github.com/IBM/fp-go/tuple"
)
@@ -27,6 +28,14 @@ func Of[GA ~[]A, A any](value A) GA {
return GA{value}
}
func Reduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
return array.Reduce(fa, f, initial)
}
func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
return array.ReduceWithIndex(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,6 +113,10 @@ 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 Size[GA ~[]A, A any](as GA) int {
return len(as)
}
@@ -118,6 +131,17 @@ func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B])
return filterMap[GA, GB](fa, f)
}
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 A) O.Option[B]) func(GA) GB {
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
}
@@ -158,3 +182,63 @@ func MonadAp[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fab ABS, fa AS) BS {
func Ap[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fa AS) func(ABS) BS {
return F.Bind2nd(MonadAp[BS, ABS, AS], fa)
}
func IsEmpty[AS ~[]A, A any](as AS) bool {
return array.IsEmpty(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) {
return onEmpty()
}
return onNonEmpty(as)
}
}
func MatchLeft[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(A, AS) B) func(AS) B {
return func(as AS) B {
if IsEmpty(as) {
return onEmpty()
}
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 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 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[GA ~[]A, A any](a A) func(GA) GA {
return F.Bind2nd(array.Push[GA, A], a)
}

View File

@@ -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],
)
}

52
array/generic/zip.go Normal file
View 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)
}

View File

@@ -16,10 +16,9 @@
package array
import (
F "github.com/IBM/fp-go/function"
M "github.com/IBM/fp-go/magma"
M "github.com/IBM/fp-go/monoid"
)
func ConcatAll[A any](m M.Magma[A]) func(A) func([]A) A {
return F.Bind1st(Reduce[A, A], m.Concat)
func ConcatAll[A any](m M.Monoid[A]) func([]A) A {
return Reduce(m.Concat, m.Empty())
}

View File

@@ -20,16 +20,16 @@ import (
"github.com/stretchr/testify/assert"
M "github.com/IBM/fp-go/magma"
M "github.com/IBM/fp-go/monoid"
)
var subInt = M.MakeMagma(func(first int, second int) int {
var subInt = M.MakeMonoid(func(first int, second int) int {
return first - second
})
}, 0)
func TestConcatAll(t *testing.T) {
var subAll = ConcatAll(subInt)(0)
var subAll = ConcatAll(subInt)
assert.Equal(t, subAll([]int{1, 2, 3}), -6)

View File

@@ -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)
}

38
array/zip.go Normal file
View 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
View 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)
}

64
bounded/bounded.go Normal file
View File

@@ -0,0 +1,64 @@
// 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 bounded
import (
O "github.com/IBM/fp-go/ord"
)
type Bounded[T any] interface {
O.Ord[T]
Top() T
Bottom() T
}
type bounded[T any] struct {
c func(x, y T) int
e func(x, y T) bool
t T
b T
}
func (self bounded[T]) Equals(x, y T) bool {
return self.e(x, y)
}
func (self bounded[T]) Compare(x, y T) int {
return self.c(x, y)
}
func (self bounded[T]) Top() T {
return self.t
}
func (self bounded[T]) Bottom() T {
return self.b
}
// MakeBounded creates an instance of a bounded type
func MakeBounded[T any](o O.Ord[T], t, b T) Bounded[T] {
return bounded[T]{c: o.Compare, e: o.Equals, t: t, b: b}
}
// Clamp returns a function that clamps against the bounds defined in the bounded type
func Clamp[T any](b Bounded[T]) func(T) T {
return O.Clamp[T](b)(b.Bottom(), b.Top())
}
// Reverse reverses the ordering and swaps the bounds
func Reverse[T any](b Bounded[T]) Bounded[T] {
return MakeBounded(O.Reverse[T](b), b.Bottom(), b.Top())
}

View File

@@ -18,3 +18,7 @@ package bytes
func ToString(a []byte) string {
return string(a)
}
func Size(as []byte) int {
return len(as)
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -31,5 +31,8 @@ func Commands() []*C.Command {
ContextReaderIOEitherCommand(),
ReaderIOEitherCommand(),
ReaderCommand(),
IOEitherCommand(),
IOCommand(),
IOOptionCommand(),
}
}

View File

@@ -150,7 +150,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)

View File

@@ -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())
}

View File

@@ -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)

136
cli/io.go Normal file
View 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 cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
A "github.com/IBM/fp-go/array"
C "github.com/urfave/cli/v2"
)
func nonGenericIO(param string) string {
return fmt.Sprintf("IO[%s]", param)
}
func genericIO(param string) string {
return fmt.Sprintf("func() %s", param)
}
var extrasIO = A.Empty[string]()
func generateIOSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOHelpers(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()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.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.Fprintf(f, `
import (
G "github.com/IBM/fp-go/%s/generic"
T "github.com/IBM/fp-go/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
T "github.com/IBM/fp-go/tuple"
A "github.com/IBM/fp-go/internal/apply"
)
`)
for i := 1; i <= count; i++ {
// sequenceT
generateIOSequenceT(f, fg, i)
// sequenceTuple
generateIOSequenceTuple(f, fg, i)
// traverseTuple
generateIOTraverseTuple(f, fg, i)
}
return nil
}
func IOCommand() *C.Command {
return &C.Command{
Name: "io",
Usage: "generate code for IO",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

282
cli/ioeither.go Normal file
View File

@@ -0,0 +1,282 @@
// 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"
A "github.com/IBM/fp-go/array"
C "github.com/urfave/cli/v2"
)
// [GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GTAB ~func() ET.Either[E, T.Tuple2[A, B]], E, A, B any](a GA, b GB) GTAB {
func nonGenericIOEither(param string) string {
return fmt.Sprintf("IOEither[E, %s]", param)
}
func genericIOEither(param string) string {
return fmt.Sprintf("func() ET.Either[E, %s]", param)
}
var extrasIOEither = A.From("E")
func generateIOEitherSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOEither[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](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, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[IOEither[error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GIOA ~func() ET.Either[error, R], GTA ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") GIOA")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j+1)
}
fmt.Fprintf(fg, ", R any](f GTA) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return ET.Unwrap(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j+1)
}
fmt.Fprintf(fg, ")())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateIOEitherEitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\n", i, i+1, i)
fmt.Fprintf(f, "func Eitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](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, ") IOEither[error, R] {\n")
fmt.Fprintf(f, " return G.Eitherize%d[IOEither[error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
fmt.Fprintf(fg, "func Eitherize%d[GIOA ~func() ET.Either[error, R], F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j+1)
}
fmt.Fprintf(fg, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") GIOA {\n")
fmt.Fprintf(fg, " e := ET.Eitherize%d(f)\n", i)
fmt.Fprintf(fg, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
}
fmt.Fprintf(fg, ") GIOA {\n")
fmt.Fprintf(fg, " return func() ET.Either[error, R] {\n")
fmt.Fprintf(fg, " return e(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j+1)
}
fmt.Fprintf(fg, ")\n")
fmt.Fprintf(fg, " }}\n")
fmt.Fprintf(fg, "}\n")
}
func generateIOEitherHelpers(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()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.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.Fprintf(f, `
import (
G "github.com/IBM/fp-go/%s/generic"
T "github.com/IBM/fp-go/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
ET "github.com/IBM/fp-go/either"
T "github.com/IBM/fp-go/tuple"
A "github.com/IBM/fp-go/internal/apply"
)
`)
// eitherize
generateIOEitherEitherize(f, fg, 0)
// uneitherize
generateIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// eitherize
generateIOEitherEitherize(f, fg, i)
// uneitherize
generateIOEitherUneitherize(f, fg, i)
// sequenceT
generateIOEitherSequenceT(f, fg, i)
// sequenceTuple
generateIOEitherSequenceTuple(f, fg, i)
// traverseTuple
generateIOEitherTraverseTuple(f, fg, i)
}
return nil
}
func IOEitherCommand() *C.Command {
return &C.Command{
Name: "ioeither",
Usage: "generate code for IOEither",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOEitherHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

137
cli/iooption.go Normal file
View File

@@ -0,0 +1,137 @@
// 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"
A "github.com/IBM/fp-go/array"
C "github.com/urfave/cli/v2"
)
func nonGenericIOOption(param string) string {
return fmt.Sprintf("IOOption[%s]", param)
}
func genericIOOption(param string) string {
return fmt.Sprintf("func() O.Option[%s]", param)
}
var extrasIOOption = A.Empty[string]()
func generateIOOptionSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionHelpers(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()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.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.Fprintf(f, `
import (
G "github.com/IBM/fp-go/%s/generic"
T "github.com/IBM/fp-go/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
T "github.com/IBM/fp-go/tuple"
O "github.com/IBM/fp-go/option"
A "github.com/IBM/fp-go/internal/apply"
)
`)
for i := 1; i <= count; i++ {
// sequenceT
generateIOOptionSequenceT(f, fg, i)
// sequenceTuple
generateIOOptionSequenceTuple(f, fg, i)
// traverseTuple
generateIOOptionTraverseTuple(f, fg, i)
}
return nil
}
func IOOptionCommand() *C.Command {
return &C.Command{
Name: "iooption",
Usage: "generate code for IOOption",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOOptionHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

284
cli/monad2.go Normal file
View File

@@ -0,0 +1,284 @@
// 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"
"os"
A "github.com/IBM/fp-go/array"
F "github.com/IBM/fp-go/function"
N "github.com/IBM/fp-go/number"
S "github.com/IBM/fp-go/string"
)
var (
concStrgs = A.Monoid[string]().Concat
intercalStrgs = A.Intercalate(S.Monoid)
concAllStrgs = A.ConcatAll(A.Monoid[string]())
)
func joinAll(middle string) func(all ...[]string) string {
ic := intercalStrgs(middle)
return func(all ...[]string) string {
return ic(concAllStrgs(all))
}
}
func generateGenericSequenceT(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tuple := tupleType("T")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// non generic version
fmt.Fprintf(f, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
fmt.Fprintf(f, "func SequenceT%d[%s any](\n", i, joinAll(", ")(extra, typesT))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d %s,\n", j+1, nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, ") %s {\n", nonGenericType(tuple))
fmt.Fprintf(f, " return G.SequenceT%d[\n", i)
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, " ](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
fmt.Fprintf(fg, "func SequenceT%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](\n", joinAll(", ")(extra, typesT))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d G_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, ") G_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceT%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d,\n", j+1)
}
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateGenericSequenceTuple(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tuple := tupleType("T")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// non generic version
fmt.Fprintf(f, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
fmt.Fprintf(f, "func SequenceTuple%d[%s any](t T.Tuple%d[", i, joinAll(", ")(extra, typesT), i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%s", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, "]) %s {\n", nonGenericType(tuple))
fmt.Fprintf(f, " return G.SequenceTuple%d[\n", i)
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, " ](t)\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
fmt.Fprintf(fg, "func SequenceTuple%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](t T.Tuple%d[", joinAll(", ")(extra, typesT), i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "G_T%d", j+1)
}
fmt.Fprintf(fg, "]) G_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceTuple%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
fmt.Fprintf(fg, " t)\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateGenericTraverseTuple(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tupleT := tupleType("T")(i)
tupleA := tupleType("A")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// all types A
typesA := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("A%d"),
))
// all function types
typesF := A.MakeBy(i, F.Flow2(
N.Inc[int],
func(j int) string {
return fmt.Sprintf("F%d ~func(A%d) %s", j, j, nonGenericType(fmt.Sprintf("T%d", j)))
},
))
// non generic version
fmt.Fprintf(f, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tupleT))
fmt.Fprintf(f, "func TraverseTuple%d[%s any](", i, joinAll(", ")(typesF, extra, typesA, typesT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(f, ") func(%s) %s {\n", tupleA, nonGenericType(tupleT))
fmt.Fprintf(f, " return G.TraverseTuple%d[%s](", i, nonGenericType(tupleT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tupleT))
fmt.Fprintf(fg, "func TraverseTuple%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tupleT))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " F%d ~func(A%d) G_T%d,\n", j+1, j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](", joinAll(", ")(extra, typesA, typesT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(fg, ") func(%s) G_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return func(t %s) G_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return A.TraverseTuple%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " f%d,\n", j+1)
}
// tuple parameter
fmt.Fprintf(fg, " t)\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
}

View File

@@ -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)

View File

@@ -337,7 +337,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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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++ {
@@ -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",

View File

@@ -34,3 +34,7 @@ type Integer interface {
type Float interface {
~float32 | ~float64
}
type Complex interface {
~complex64 | ~complex128
}

View File

@@ -19,7 +19,7 @@ import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
)
// WithContext wraps an existing ReaderIOEither and performs a context check for cancellation before delegating
// WithContext wraps an existing [ReaderIOEither] and performs a context check for cancellation before delegating
func WithContext[A any](ma ReaderIOEither[A]) ReaderIOEither[A] {
return G.WithContext(ma)
}

View File

@@ -0,0 +1 @@
Carsten

View File

@@ -23,7 +23,7 @@ import (
EQ "github.com/IBM/fp-go/eq"
)
// Eq implements the equals predicate for values contained in the IOEither monad
// Eq implements the equals predicate for values contained in the [ReaderIOEither] monad
func Eq[A any](eq EQ.Eq[ET.Either[error, A]]) func(context.Context) EQ.Eq[ReaderIOEither[A]] {
return G.Eq[ReaderIOEither[A]](eq)
}

View File

@@ -48,7 +48,7 @@ func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
// ReadFile reads a file in the scope of a context
func ReadFile(path string) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[*os.File, []byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[[]byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
return func(ctx context.Context) IOE.IOEither[error, []byte] {
return IOE.MakeIO(func() ET.Either[error, []byte] {
return file.ReadAll(ctx, r)

View File

@@ -1,23 +1,8 @@
// 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
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:43.4901011 +0200 CEST m=+0.009264601
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101
import (
"context"

View File

@@ -1,23 +1,8 @@
// 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
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:43.4901011 +0200 CEST m=+0.009264601
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101
import (
"context"

View File

@@ -220,7 +220,7 @@ func MonadApPar[
fabIOE := withCancelCauseFunc(cancelSub, cfab(ctxSub))
faIOE := withCancelCauseFunc(cancelSub, cfa(ctxSub))
return IOE.MonadApPar[GIOA, GIOB, GIOAB](fabIOE, faIOE)()
return IOE.MonadApPar[GIOB, GIOAB](fabIOE, faIOE)()
}
}
}

View File

@@ -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)
}

View File

@@ -20,7 +20,7 @@ import (
)
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
func WithResource[R, A, ANY any](onCreate ReaderIOEither[R], onRelease func(R) ReaderIOEither[ANY]) func(func(R) ReaderIOEither[A]) ReaderIOEither[A] {
func WithResource[A, R, ANY any](onCreate ReaderIOEither[R], onRelease func(R) ReaderIOEither[ANY]) func(func(R) ReaderIOEither[A]) ReaderIOEither[A] {
// wraps the callback functions with a context check
return G.WithResource[ReaderIOEither[A]](onCreate, onRelease)
}

View 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 readerioeither
import (
"context"
"io"
"os"
B "github.com/IBM/fp-go/bytes"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither"
)
var (
openFile = F.Flow3(
IOE.Eitherize1(os.Open),
FromIOEither[*os.File],
ChainFirstIOK(F.Flow2(
(*os.File).Name,
IO.Logf[string]("Opened file [%s]"),
)),
)
)
func closeFile(f *os.File) ReaderIOEither[string] {
return F.Pipe1(
TryCatch(func(_ context.Context) func() (string, error) {
return func() (string, error) {
return f.Name(), f.Close()
}
}),
ChainFirstIOK(IO.Logf[string]("Closed file [%s]")),
)
}
func ExampleWithResource() {
stringReader := WithResource[string](openFile("data/file.txt"), closeFile)
rdr := stringReader(func(f *os.File) ReaderIOEither[string] {
return F.Pipe2(
TryCatch(func(_ context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
return io.ReadAll(f)
}
}),
ChainFirstIOK(F.Flow2(
B.Size,
IO.Logf[int]("Read content of length [%d]"),
)),
Map(B.ToString),
)
})
contentIOE := F.Pipe2(
context.Background(),
rdr,
IOE.ChainFirstIOK[error](IO.Printf[string]("Content: %s")),
)
contentIOE()
// Output: Content: Carsten
}

View File

@@ -21,5 +21,6 @@ import (
RE "github.com/IBM/fp-go/readerioeither"
)
// ReaderIOEither is a specialization of the Reader monad for the typical golang scenario
// ReaderIOEither is a specialization of the [RE.ReaderIOEither] monad for the typical golang scenario in which the
// left value is an [error] and the context is a [context.Context]
type ReaderIOEither[A any] RE.ReaderIOEither[context.Context, error, A]

46
either/array.go Normal file
View File

@@ -0,0 +1,46 @@
// 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"
)
// TraverseArray 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)
}
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)
}

View File

@@ -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

View File

@@ -146,8 +146,8 @@ func FromOption[E, A 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] {
@@ -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))
}

View 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)
}

View File

@@ -0,0 +1,64 @@
// 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"
F "github.com/IBM/fp-go/function"
N "github.com/IBM/fp-go/number"
)
func ExampleEither_extraction() {
leftValue := Left[int](fmt.Errorf("Division by Zero!"))
rightValue := Right[error](10)
// Convert Either[E, A] to A with a default value
leftWithDefault := GetOrElse(F.Constant1[error](0))(leftValue) // 0
rightWithDefault := GetOrElse(F.Constant1[error](0))(rightValue) // 10
// Apply a different function on Left(...)/Right(...)
doubleOrZero := Fold(F.Constant1[error](0), N.Mul(2)) // func(Either[error, int]) int
doubleFromLeft := doubleOrZero(leftValue) // 0
doubleFromRight := doubleOrZero(rightValue) // 20
// Pro-tip: Fold is short for the following:
doubleOrZeroBis := F.Flow2(
Map[error](N.Mul(2)),
GetOrElse(F.Constant1[error](0)),
)
doubleFromLeftBis := doubleOrZeroBis(leftValue) // 0
doubleFromRightBis := doubleOrZeroBis(rightValue) // 20
fmt.Println(leftValue)
fmt.Println(rightValue)
fmt.Println(leftWithDefault)
fmt.Println(rightWithDefault)
fmt.Println(doubleFromLeft)
fmt.Println(doubleFromRight)
fmt.Println(doubleFromLeftBis)
fmt.Println(doubleFromRightBis)
// Output:
// Left[*errors.errorString, int](Division by Zero!)
// Right[<nil>, int](10)
// 0
// 10
// 0
// 20
// 0
// 20
}

View File

@@ -1,21 +1,7 @@
// 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.
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:45.2674057 +0200 CEST m=+0.015622601
// 2023-08-17 22:58:57.9925506 +0200 CEST m=+0.033401101
package either
import (

View File

@@ -21,16 +21,12 @@ import (
S "github.com/IBM/fp-go/semigroup"
)
func concat[A any](first, second func(A) A) func(A) A {
return F.Flow2(first, second)
}
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
func Semigroup[A any]() S.Semigroup[func(A) A] {
return S.MakeSemigroup(concat[A])
return S.MakeSemigroup(F.Flow2[func(A) A, func(A) A])
}
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
func Monoid[A any]() M.Monoid[func(A) A] {
return M.MakeMonoid(concat[A], F.Identity[A])
return M.MakeMonoid(F.Flow2[func(A) A, func(A) A], F.Identity[A])
}

51
erasure/erasure.go Normal file
View File

@@ -0,0 +1,51 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package erasure
import (
F "github.com/IBM/fp-go/function"
)
// Erase converts a variable of type T to an any by returning a pointer to that variable
func Erase[T any](t T) any {
return &t
}
// Unerase converts an erased variable back to its original value
func Unerase[T any](t any) T {
return *t.(*T)
}
// Erase0 converts a type safe function into an erased function
func Erase0[T1 any](f func() T1) func() any {
return F.Nullary2(f, Erase[T1])
}
// Erase1 converts a type safe function into an erased function
func Erase1[T1, T2 any](f func(T1) T2) func(any) any {
return F.Flow3(
Unerase[T1],
f,
Erase[T2],
)
}
// Erase2 converts a type safe function into an erased function
func Erase2[T1, T2, T3 any](f func(T1, T2) T3) func(any, any) any {
return func(t1, t2 any) any {
return Erase(f(Unerase[T1](t1), Unerase[T2](t2)))
}
}

39
erasure/erasure_test.go Normal file
View File

@@ -0,0 +1,39 @@
// 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"
"strings"
"testing"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
)
func TestEither(t *testing.T) {
e1 := F.Pipe3(
E.Of[error](Erase("Carsten")),
E.Map[error](Erase1(strings.ToUpper)),
E.GetOrElse(func(e error) any {
return Erase("Error")
}),
Unerase[string],
)
fmt.Println(e1)
}

View File

@@ -28,6 +28,22 @@ func OnNone(msg string, args ...any) func() error {
}
}
// OnSome generates a unary function that produces a formatted error
func OnSome[T any](msg string, args ...any) func(T) error {
l := len(args)
if l == 0 {
return func(value T) error {
return fmt.Errorf(msg, value)
}
}
return func(value T) error {
data := make([]any, l)
copy(data[1:], args)
data[0] = value
return fmt.Errorf(msg, data...)
}
}
// OnError generates a unary function that produces a formatted error. The argument
// to that function is the root cause of the error and the message will be augmented with
// a format string containing %w

23
file/getters.go Normal file
View File

@@ -0,0 +1,23 @@
// 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"
// GetName is the getter for the `Name` property of [os.File]
func GetName(f *os.File) string {
return f.Name()
}

View File

@@ -1,21 +1,7 @@
// 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.
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:49.808764 +0200 CEST m=+0.064638701
// 2023-08-17 22:59:01.9404821 +0200 CEST m=+0.161366801
package function
// Combinations for a total of 1 arguments

30
function/cache.go Normal file
View 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 function
import (
G "github.com/IBM/fp-go/function/generic"
)
// Cache converts a unary function into a unary function that caches the value depending on the parameter
func Cache[K comparable, T any](f func(K) T) func(K) T {
return G.Cache(f)
}
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter
func ContramapCache[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
return G.ContramapCache[func(A) T](kf)
}

50
function/cache_test.go Normal file
View File

@@ -0,0 +1,50 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package function
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCache(t *testing.T) {
var count int
withSideEffect := func(n int) int {
count++
return n
}
cached := Cache(withSideEffect)
assert.Equal(t, 0, count)
assert.Equal(t, 10, cached(10))
assert.Equal(t, 1, count)
assert.Equal(t, 10, cached(10))
assert.Equal(t, 1, count)
assert.Equal(t, 20, cached(20))
assert.Equal(t, 2, count)
assert.Equal(t, 20, cached(20))
assert.Equal(t, 2, count)
assert.Equal(t, 10, cached(10))
assert.Equal(t, 2, count)
}

View File

@@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package function implements function composition primitives, most prominently [Pipe2] and [Flow2]
package function
//go:generate go run .. pipe --count 20 --filename gen.go

View File

@@ -1,21 +1,7 @@
// 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.
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:47.675104 +0200 CEST m=+0.112962501
// 2023-08-17 22:58:59.8663985 +0200 CEST m=+0.103744101
package function
// Pipe0 takes an initial value t0 and successively applies 0 functions where the input of a function is the return value of the previous function

65
function/generic/cache.go Normal file
View File

@@ -0,0 +1,65 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
"sync"
L "github.com/IBM/fp-go/internal/lazy"
)
// Cache converts a unary function into a unary function that caches the value depending on the parameter
func Cache[F ~func(K) T, K comparable, T any](f F) F {
return ContramapCache[F](func(k K) K { return k })(f)
}
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter
func ContramapCache[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
return CacheCallback[F](kf, getOrCreate[K, T]())
}
// getOrCreate is a naive implementation of a cache, without bounds
func getOrCreate[K comparable, T any]() func(K, func() func() T) func() T {
cache := make(map[K]func() T)
var l sync.Mutex
return func(k K, cb func() func() T) func() T {
// only lock to access a lazy accessor to the value
l.Lock()
existing, ok := cache[k]
if !ok {
existing = cb()
cache[k] = existing
}
l.Unlock()
// compute the value outside of the lock
return existing
}
}
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
func CacheCallback[F ~func(A) T, KF func(A) K, C ~func(K, func() func() T) func() T, A any, K comparable, T any](kf KF, getOrCreate C) func(F) F {
return func(f F) F {
return func(a A) T {
// cache entry
return getOrCreate(kf(a), func() func() T {
return L.Memoize[func() T](func() T {
return f(a)
})
})()
}
}
}

62
function/pipe_test.go Normal file
View File

@@ -0,0 +1,62 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package function
import (
"fmt"
)
func addSthg(value int) int {
return value + 1
}
func doSthgElse(value int) int {
return value * 2
}
func doFinalSthg(value int) string {
return fmt.Sprintf("final value: %d", value)
}
func Example() {
// start point
value := 1
// imperative style
value1 := addSthg(value) // 2
value2 := doSthgElse(value1) // 4
finalValueImperative := doFinalSthg(value2) // "final value: 4"
// the same but inline
finalValueInline := doFinalSthg(doSthgElse(addSthg(value)))
// with pipe
finalValuePipe := Pipe3(value, addSthg, doSthgElse, doFinalSthg)
// with flow
transform := Flow3(addSthg, doSthgElse, doFinalSthg)
finalValueFlow := transform(value)
fmt.Println(finalValueImperative)
fmt.Println(finalValueInline)
fmt.Println(finalValuePipe)
fmt.Println(finalValueFlow)
// Output:
// final value: 4
// final value: 4
// final value: 4
// final value: 4
}

View File

@@ -1,21 +1,7 @@
// 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.
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:53.6381914 +0200 CEST m=+0.019961301
// 2023-08-17 22:59:06.2987136 +0200 CEST m=+0.049156901
package identity
import (

View File

@@ -1,21 +1,7 @@
// 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.
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:55.7987979 +0200 CEST m=+0.076670601
// 2023-08-17 22:59:08.1313362 +0200 CEST m=+0.111171801
package apply
import (

View File

@@ -42,10 +42,27 @@ func Reduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
return current
}
func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
current := initial
count := len(fa)
for i := 0; i < count; i++ {
current = f(i, current, fa[i])
}
return current
}
func Append[GA ~[]A, A any](as GA, a A) GA {
return append(as, a)
}
func Push[GA ~[]A, A any](as GA, a A) GA {
l := len(as)
cpy := make(GA, l+1)
copy(cpy, as)
cpy[l] = a
return cpy
}
func Empty[GA ~[]A, A any]() GA {
return make(GA, 0)
}

75
internal/bindt/bind.go Normal file
View File

@@ -0,0 +1,75 @@
// 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 bindt
import (
F "github.com/IBM/fp-go/function"
I "github.com/IBM/fp-go/identity"
T "github.com/IBM/fp-go/tuple"
)
func Bind[SET ~func(B) func(S1) S2, FCT ~func(S1) HKTB, S1, S2, B, HKTS1, HKTS2, HKTB any](
mchain func(func(S1) HKTS2) func(HKTS1) HKTS2,
mmap func(func(B) S2) func(HKTB) HKTS2,
s SET,
f FCT,
) func(HKTS1) HKTS2 {
return mchain(F.Flow3(
T.Replicate2[S1],
T.Map2(F.Flow2(
I.Ap[S2, S1],
F.Flow2(
F.Bind1st(F.Flow2[SET, func(func(S1) S2) S2], s),
mmap,
)), f),
T.Tupled2(I.MonadAp[HKTS2, HKTB]),
))
}
func BindTo[SET ~func(B) S2, S2, B, HKTS2, HKTB any](
mmap func(func(B) S2) func(HKTB) HKTS2,
s SET,
) func(HKTB) HKTS2 {
return mmap(s)
}
func ApS[
SET ~func(B) func(S1) S2,
S1, S2, B, HKTS1S2, HKTS1, HKTS2, HKTB any,
](
ap func(HKTS1) func(HKTS1S2) HKTS2,
mmap func(func(B) func(S1) S2) func(HKTB) HKTS1S2,
s SET, fb HKTB) func(HKTS1) HKTS2 {
return F.Flow2(
ap,
I.Ap[HKTS2, HKTS1S2](mmap(s)(fb)),
)
}
func Let[SET ~func(B) func(S1) S2, FCT ~func(S1) B, S1, S2, B, HKTS1, HKTS2 any](
mmap func(func(S1) S2) func(HKTS1) HKTS2,
s SET,
f FCT,
) func(HKTS1) HKTS2 {
return mmap(F.Flow3(
T.Replicate2[S1],
T.Map2(F.Flow2(
I.Ap[S2, S1],
F.Bind1st(F.Flow2[SET, func(func(S1) S2) S2], s)), f),
T.Tupled2(I.MonadAp[S2, B]),
))
}

34
internal/lazy/memoize.go Normal file
View 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 lazy
import "sync"
// Memoize computes the value of the provided IO monad lazily but exactly once
func Memoize[GA ~func() A, A any](ma GA) GA {
// synchronization primitives
var once sync.Once
var result A
// callback
gen := func() {
result = ma()
}
// returns our memoized wrapper
return func() A {
once.Do(gen)
return result
}
}

View File

@@ -0,0 +1,80 @@
// 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 optiont
import (
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/apply"
FC "github.com/IBM/fp-go/internal/functor"
O "github.com/IBM/fp-go/option"
)
func Of[A, HKTA any](fof func(O.Option[A]) HKTA, a A) HKTA {
return F.Pipe2(a, O.Of[A], fof)
}
func None[A, HKTA any](fof func(O.Option[A]) HKTA) HKTA {
return F.Pipe1(O.None[A](), fof)
}
func OfF[A, HKTA, HKTEA any](fmap func(HKTA, func(A) O.Option[A]) HKTEA, fa HKTA) HKTEA {
return fmap(fa, O.Of[A])
}
func MonadMap[A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(O.Option[A]) O.Option[B]) HKTFB, fa HKTFA, f func(A) B) HKTFB {
// HKTGA = Either[E, A]
// HKTGB = Either[E, B]
return FC.MonadMap(fmap, O.MonadMap[A, B], fa, f)
}
func MonadChain[A, B, HKTFA, HKTFB any](
fchain func(HKTFA, func(O.Option[A]) HKTFB) HKTFB,
fof func(O.Option[B]) HKTFB,
ma HKTFA,
f func(A) HKTFB) HKTFB {
// dispatch to the even more generic implementation
return fchain(ma, O.Fold(F.Nullary2(O.None[B], fof), f))
}
func MonadAp[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
fap func(HKTFGAB, HKTFA) HKTFB,
fmap func(HKTFAB, func(O.Option[func(A) B]) func(O.Option[A]) O.Option[B]) HKTFGAB,
fab HKTFAB,
fa HKTFA) HKTFB {
// HKTGA = O.Option[A]
// HKTGB = O.Option[B]
// HKTGAB = O.Option[func(a A) B]
return apply.MonadAp(fap, fmap, O.MonadAp[B, A], fab, fa)
}
func MatchE[A, HKTEA, HKTB any](mchain func(HKTEA, func(O.Option[A]) HKTB) HKTB, onNone func() HKTB, onSome func(A) HKTB) func(HKTEA) HKTB {
return F.Bind2nd(mchain, O.Fold(onNone, onSome))
}
func FromOptionK[A, B, HKTB any](
fof func(O.Option[B]) HKTB,
f func(A) O.Option[B]) func(A) HKTB {
return F.Flow2(f, fof)
}
func MonadChainOptionK[A, B, HKTA, HKTB any](
fchain func(HKTA, func(O.Option[A]) HKTB) HKTB,
fof func(O.Option[B]) HKTB,
ma HKTA,
f func(A) O.Option[B],
) HKTB {
return MonadChain(fchain, fof, ma, FromOptionK(fof, f))
}

View File

@@ -22,6 +22,14 @@ import (
var Upper = strings.ToUpper
func Inc(i int) int {
return i + 1
}
func Dec(i int) int {
return i - 1
}
func Sum(left, right int) int {
return left + right
}

18
io/doc.go Normal file
View File

@@ -0,0 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package io
//go:generate go run .. io --count 10 --filename gen.go

39
io/file/file.go Normal file
View File

@@ -0,0 +1,39 @@
// 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 (
"io"
"os"
IO "github.com/IBM/fp-go/io"
)
// Close closes a closeable resource and ignores a potential error
func Close[R io.Closer](r R) IO.IO[R] {
return IO.MakeIO[R](func() R {
r.Close() // #nosec: G104
return r
})
}
// Remove removes a resource and ignores a potential error
func Remove(name string) IO.IO[string] {
return IO.MakeIO[string](func() string {
os.Remove(name) // #nosec: G104
return name
})
}

375
io/gen.go Normal file
View File

@@ -0,0 +1,375 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-08-17 22:59:10.1040409 +0200 CEST m=+0.089470201
package io
import (
G "github.com/IBM/fp-go/io/generic"
T "github.com/IBM/fp-go/tuple"
)
// SequenceT1 converts 1 [IO[T]] into a [IO[T.Tuple1[T1]]]
func SequenceT1[T1 any](
t1 IO[T1],
) IO[T.Tuple1[T1]] {
return G.SequenceT1[
IO[T.Tuple1[T1]],
IO[T1],
](t1)
}
// SequenceTuple1 converts a [T.Tuple1[IO[T]]] into a [IO[T.Tuple1[T1]]]
func SequenceTuple1[T1 any](t T.Tuple1[IO[T1]]) IO[T.Tuple1[T1]] {
return G.SequenceTuple1[
IO[T.Tuple1[T1]],
IO[T1],
](t)
}
// TraverseTuple1 converts a [T.Tuple1[IO[T]]] into a [IO[T.Tuple1[T1]]]
func TraverseTuple1[F1 ~func(A1) IO[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) IO[T.Tuple1[T1]] {
return G.TraverseTuple1[IO[T.Tuple1[T1]]](f1)
}
// SequenceT2 converts 2 [IO[T]] into a [IO[T.Tuple2[T1, T2]]]
func SequenceT2[T1, T2 any](
t1 IO[T1],
t2 IO[T2],
) IO[T.Tuple2[T1, T2]] {
return G.SequenceT2[
IO[T.Tuple2[T1, T2]],
IO[T1],
IO[T2],
](t1, t2)
}
// SequenceTuple2 converts a [T.Tuple2[IO[T]]] into a [IO[T.Tuple2[T1, T2]]]
func SequenceTuple2[T1, T2 any](t T.Tuple2[IO[T1], IO[T2]]) IO[T.Tuple2[T1, T2]] {
return G.SequenceTuple2[
IO[T.Tuple2[T1, T2]],
IO[T1],
IO[T2],
](t)
}
// TraverseTuple2 converts a [T.Tuple2[IO[T]]] into a [IO[T.Tuple2[T1, T2]]]
func TraverseTuple2[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], A1, A2, T1, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) IO[T.Tuple2[T1, T2]] {
return G.TraverseTuple2[IO[T.Tuple2[T1, T2]]](f1, f2)
}
// SequenceT3 converts 3 [IO[T]] into a [IO[T.Tuple3[T1, T2, T3]]]
func SequenceT3[T1, T2, T3 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
) IO[T.Tuple3[T1, T2, T3]] {
return G.SequenceT3[
IO[T.Tuple3[T1, T2, T3]],
IO[T1],
IO[T2],
IO[T3],
](t1, t2, t3)
}
// SequenceTuple3 converts a [T.Tuple3[IO[T]]] into a [IO[T.Tuple3[T1, T2, T3]]]
func SequenceTuple3[T1, T2, T3 any](t T.Tuple3[IO[T1], IO[T2], IO[T3]]) IO[T.Tuple3[T1, T2, T3]] {
return G.SequenceTuple3[
IO[T.Tuple3[T1, T2, T3]],
IO[T1],
IO[T2],
IO[T3],
](t)
}
// TraverseTuple3 converts a [T.Tuple3[IO[T]]] into a [IO[T.Tuple3[T1, T2, T3]]]
func TraverseTuple3[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], A1, A2, A3, T1, T2, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) IO[T.Tuple3[T1, T2, T3]] {
return G.TraverseTuple3[IO[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// SequenceT4 converts 4 [IO[T]] into a [IO[T.Tuple4[T1, T2, T3, T4]]]
func SequenceT4[T1, T2, T3, T4 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
t4 IO[T4],
) IO[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceT4[
IO[T.Tuple4[T1, T2, T3, T4]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
](t1, t2, t3, t4)
}
// SequenceTuple4 converts a [T.Tuple4[IO[T]]] into a [IO[T.Tuple4[T1, T2, T3, T4]]]
func SequenceTuple4[T1, T2, T3, T4 any](t T.Tuple4[IO[T1], IO[T2], IO[T3], IO[T4]]) IO[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceTuple4[
IO[T.Tuple4[T1, T2, T3, T4]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
](t)
}
// TraverseTuple4 converts a [T.Tuple4[IO[T]]] into a [IO[T.Tuple4[T1, T2, T3, T4]]]
func TraverseTuple4[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], F4 ~func(A4) IO[T4], A1, A2, A3, A4, T1, T2, T3, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) IO[T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseTuple4[IO[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// SequenceT5 converts 5 [IO[T]] into a [IO[T.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceT5[T1, T2, T3, T4, T5 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
t4 IO[T4],
t5 IO[T5],
) IO[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceT5[
IO[T.Tuple5[T1, T2, T3, T4, T5]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
](t1, t2, t3, t4, t5)
}
// SequenceTuple5 converts a [T.Tuple5[IO[T]]] into a [IO[T.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5]]) IO[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceTuple5[
IO[T.Tuple5[T1, T2, T3, T4, T5]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
](t)
}
// TraverseTuple5 converts a [T.Tuple5[IO[T]]] into a [IO[T.Tuple5[T1, T2, T3, T4, T5]]]
func TraverseTuple5[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], F4 ~func(A4) IO[T4], F5 ~func(A5) IO[T5], A1, A2, A3, A4, A5, T1, T2, T3, T4, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) IO[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseTuple5[IO[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// SequenceT6 converts 6 [IO[T]] into a [IO[T.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceT6[T1, T2, T3, T4, T5, T6 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
t4 IO[T4],
t5 IO[T5],
t6 IO[T6],
) IO[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceT6[
IO[T.Tuple6[T1, T2, T3, T4, T5, T6]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
](t1, t2, t3, t4, t5, t6)
}
// SequenceTuple6 converts a [T.Tuple6[IO[T]]] into a [IO[T.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6]]) IO[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceTuple6[
IO[T.Tuple6[T1, T2, T3, T4, T5, T6]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
](t)
}
// TraverseTuple6 converts a [T.Tuple6[IO[T]]] into a [IO[T.Tuple6[T1, T2, T3, T4, T5, T6]]]
func TraverseTuple6[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], F4 ~func(A4) IO[T4], F5 ~func(A5) IO[T5], F6 ~func(A6) IO[T6], A1, A2, A3, A4, A5, A6, T1, T2, T3, T4, T5, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) IO[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseTuple6[IO[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// SequenceT7 converts 7 [IO[T]] into a [IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
t4 IO[T4],
t5 IO[T5],
t6 IO[T6],
t7 IO[T7],
) IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceT7[
IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceTuple7 converts a [T.Tuple7[IO[T]]] into a [IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7]]) IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceTuple7[
IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
](t)
}
// TraverseTuple7 converts a [T.Tuple7[IO[T]]] into a [IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func TraverseTuple7[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], F4 ~func(A4) IO[T4], F5 ~func(A5) IO[T5], F6 ~func(A6) IO[T6], F7 ~func(A7) IO[T7], A1, A2, A3, A4, A5, A6, A7, T1, T2, T3, T4, T5, T6, 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]) IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseTuple7[IO[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// SequenceT8 converts 8 [IO[T]] into a [IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
t4 IO[T4],
t5 IO[T5],
t6 IO[T6],
t7 IO[T7],
t8 IO[T8],
) IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceT8[
IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
IO[T8],
](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceTuple8 converts a [T.Tuple8[IO[T]]] into a [IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8]]) IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceTuple8[
IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
IO[T8],
](t)
}
// TraverseTuple8 converts a [T.Tuple8[IO[T]]] into a [IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func TraverseTuple8[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], F4 ~func(A4) IO[T4], F5 ~func(A5) IO[T5], F6 ~func(A6) IO[T6], F7 ~func(A7) IO[T7], F8 ~func(A8) IO[T8], A1, A2, A3, A4, A5, A6, A7, A8, T1, T2, T3, T4, T5, T6, T7, 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]) IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseTuple8[IO[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// SequenceT9 converts 9 [IO[T]] into a [IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
t4 IO[T4],
t5 IO[T5],
t6 IO[T6],
t7 IO[T7],
t8 IO[T8],
t9 IO[T9],
) IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceT9[
IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
IO[T8],
IO[T9],
](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceTuple9 converts a [T.Tuple9[IO[T]]] into a [IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9]]) IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceTuple9[
IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
IO[T8],
IO[T9],
](t)
}
// TraverseTuple9 converts a [T.Tuple9[IO[T]]] into a [IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func TraverseTuple9[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], F4 ~func(A4) IO[T4], F5 ~func(A5) IO[T5], F6 ~func(A6) IO[T6], F7 ~func(A7) IO[T7], F8 ~func(A8) IO[T8], F9 ~func(A9) IO[T9], A1, A2, A3, A4, A5, A6, A7, A8, A9, T1, T2, T3, T4, T5, T6, T7, T8, 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]) IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseTuple9[IO[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
}
// SequenceT10 converts 10 [IO[T]] into a [IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](
t1 IO[T1],
t2 IO[T2],
t3 IO[T3],
t4 IO[T4],
t5 IO[T5],
t6 IO[T6],
t7 IO[T7],
t8 IO[T8],
t9 IO[T9],
t10 IO[T10],
) IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceT10[
IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
IO[T8],
IO[T9],
IO[T10],
](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceTuple10 converts a [T.Tuple10[IO[T]]] into a [IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9], IO[T10]]) IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceTuple10[
IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]],
IO[T1],
IO[T2],
IO[T3],
IO[T4],
IO[T5],
IO[T6],
IO[T7],
IO[T8],
IO[T9],
IO[T10],
](t)
}
// TraverseTuple10 converts a [T.Tuple10[IO[T]]] into a [IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func TraverseTuple10[F1 ~func(A1) IO[T1], F2 ~func(A2) IO[T2], F3 ~func(A3) IO[T3], F4 ~func(A4) IO[T4], F5 ~func(A5) IO[T5], F6 ~func(A6) IO[T6], F7 ~func(A7) IO[T7], F8 ~func(A8) IO[T8], F9 ~func(A9) IO[T9], F10 ~func(A10) IO[T10], A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, T1, T2, T3, T4, T5, T6, T7, T8, T9, 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]) IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseTuple10[IO[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}

View File

@@ -64,6 +64,28 @@ func MonadApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](f
)
}
// MonadApFirstPar combines two effectful actions, keeping only the result of the first.
func MonadApFirstPar[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](first GA, second GB) GA {
return G.MonadApFirst(
MonadApPar[GB, GA, GBA, B, A],
MonadMap[GA, GBA, A, func(B) A],
first,
second,
)
}
// MonadApFirstSeq combines two effectful actions, keeping only the result of the first.
func MonadApFirstSeq[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](first GA, second GB) GA {
return G.MonadApFirst(
MonadApSeq[GB, GA, GBA, B, A],
MonadMap[GA, GBA, A, func(B) A],
first,
second,
)
}
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second GB) func(GA) GA {
return G.ApFirst(
@@ -74,6 +96,26 @@ func ApFirst[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second
)
}
// ApFirstPar combines two effectful actions, keeping only the result of the first.
func ApFirstPar[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second GB) func(GA) GA {
return G.ApFirst(
MonadApPar[GB, GA, GBA, B, A],
MonadMap[GA, GBA, A, func(B) A],
second,
)
}
// ApFirstSeq combines two effectful actions, keeping only the result of the first.
func ApFirstSeq[GA ~func() A, GB ~func() B, GBA ~func() func(B) A, A, B any](second GB) func(GA) GA {
return G.ApFirst(
MonadApSeq[GB, GA, GBA, B, A],
MonadMap[GA, GBA, A, func(B) A],
second,
)
}
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[GA ~func() A, GB ~func() B, GBB ~func() func(B) B, A, B any](first GA, second GB) GB {
return G.MonadApSecond(

829
io/generic/gen.go Normal file
View File

@@ -0,0 +1,829 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-08-17 22:59:10.1132645 +0200 CEST m=+0.098693801
package generic
import (
A "github.com/IBM/fp-go/internal/apply"
T "github.com/IBM/fp-go/tuple"
)
// SequenceT1 converts 1 [func() T] into a [func() T.Tuple1[T1]]
func SequenceT1[
G_TUPLE1 ~func() T.Tuple1[T1],
G_T1 ~func() T1,
T1 any](
t1 G_T1,
) G_TUPLE1 {
return A.SequenceT1(
Map[G_T1, G_TUPLE1, T1, T.Tuple1[T1]],
t1,
)
}
// SequenceTuple1 converts a [T.Tuple1[func() T]] into a [func() T.Tuple1[T1]]
func SequenceTuple1[
G_TUPLE1 ~func() T.Tuple1[T1],
G_T1 ~func() T1,
T1 any](t T.Tuple1[G_T1]) G_TUPLE1 {
return A.SequenceTuple1(
Map[G_T1, G_TUPLE1, T1, T.Tuple1[T1]],
t)
}
// TraverseTuple1 converts a [T.Tuple1[func() T]] into a [func() T.Tuple1[T1]]
func TraverseTuple1[
G_TUPLE1 ~func() T.Tuple1[T1],
F1 ~func(A1) G_T1,
G_T1 ~func() T1,
A1, T1 any](f1 F1) func(T.Tuple1[A1]) G_TUPLE1 {
return func(t T.Tuple1[A1]) G_TUPLE1 {
return A.TraverseTuple1(
Map[G_T1, G_TUPLE1, T1, T.Tuple1[T1]],
f1,
t)
}
}
// SequenceT2 converts 2 [func() T] into a [func() T.Tuple2[T1, T2]]
func SequenceT2[
G_TUPLE2 ~func() T.Tuple2[T1, T2],
G_T1 ~func() T1,
G_T2 ~func() T2,
T1, T2 any](
t1 G_T1,
t2 G_T2,
) G_TUPLE2 {
return A.SequenceT2(
Map[G_T1, func() func(T2) T.Tuple2[T1, T2], T1, func(T2) T.Tuple2[T1, T2]],
Ap[G_TUPLE2, func() func(T2) T.Tuple2[T1, T2], G_T2],
t1,
t2,
)
}
// SequenceTuple2 converts a [T.Tuple2[func() T]] into a [func() T.Tuple2[T1, T2]]
func SequenceTuple2[
G_TUPLE2 ~func() T.Tuple2[T1, T2],
G_T1 ~func() T1,
G_T2 ~func() T2,
T1, T2 any](t T.Tuple2[G_T1, G_T2]) G_TUPLE2 {
return A.SequenceTuple2(
Map[G_T1, func() func(T2) T.Tuple2[T1, T2], T1, func(T2) T.Tuple2[T1, T2]],
Ap[G_TUPLE2, func() func(T2) T.Tuple2[T1, T2], G_T2],
t)
}
// TraverseTuple2 converts a [T.Tuple2[func() T]] into a [func() T.Tuple2[T1, T2]]
func TraverseTuple2[
G_TUPLE2 ~func() T.Tuple2[T1, T2],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
G_T1 ~func() T1,
G_T2 ~func() T2,
A1, A2, T1, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) G_TUPLE2 {
return func(t T.Tuple2[A1, A2]) G_TUPLE2 {
return A.TraverseTuple2(
Map[G_T1, func() func(T2) T.Tuple2[T1, T2], T1, func(T2) T.Tuple2[T1, T2]],
Ap[G_TUPLE2, func() func(T2) T.Tuple2[T1, T2], G_T2],
f1,
f2,
t)
}
}
// SequenceT3 converts 3 [func() T] into a [func() T.Tuple3[T1, T2, T3]]
func SequenceT3[
G_TUPLE3 ~func() T.Tuple3[T1, T2, T3],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
T1, T2, T3 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
) G_TUPLE3 {
return A.SequenceT3(
Map[G_T1, func() func(T2) func(T3) T.Tuple3[T1, T2, T3], T1, func(T2) func(T3) T.Tuple3[T1, T2, T3]],
Ap[func() func(T3) T.Tuple3[T1, T2, T3], func() func(T2) func(T3) T.Tuple3[T1, T2, T3], G_T2],
Ap[G_TUPLE3, func() func(T3) T.Tuple3[T1, T2, T3], G_T3],
t1,
t2,
t3,
)
}
// SequenceTuple3 converts a [T.Tuple3[func() T]] into a [func() T.Tuple3[T1, T2, T3]]
func SequenceTuple3[
G_TUPLE3 ~func() T.Tuple3[T1, T2, T3],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
T1, T2, T3 any](t T.Tuple3[G_T1, G_T2, G_T3]) G_TUPLE3 {
return A.SequenceTuple3(
Map[G_T1, func() func(T2) func(T3) T.Tuple3[T1, T2, T3], T1, func(T2) func(T3) T.Tuple3[T1, T2, T3]],
Ap[func() func(T3) T.Tuple3[T1, T2, T3], func() func(T2) func(T3) T.Tuple3[T1, T2, T3], G_T2],
Ap[G_TUPLE3, func() func(T3) T.Tuple3[T1, T2, T3], G_T3],
t)
}
// TraverseTuple3 converts a [T.Tuple3[func() T]] into a [func() T.Tuple3[T1, T2, T3]]
func TraverseTuple3[
G_TUPLE3 ~func() T.Tuple3[T1, T2, T3],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
A1, A2, A3, T1, T2, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) G_TUPLE3 {
return func(t T.Tuple3[A1, A2, A3]) G_TUPLE3 {
return A.TraverseTuple3(
Map[G_T1, func() func(T2) func(T3) T.Tuple3[T1, T2, T3], T1, func(T2) func(T3) T.Tuple3[T1, T2, T3]],
Ap[func() func(T3) T.Tuple3[T1, T2, T3], func() func(T2) func(T3) T.Tuple3[T1, T2, T3], G_T2],
Ap[G_TUPLE3, func() func(T3) T.Tuple3[T1, T2, T3], G_T3],
f1,
f2,
f3,
t)
}
}
// SequenceT4 converts 4 [func() T] into a [func() T.Tuple4[T1, T2, T3, T4]]
func SequenceT4[
G_TUPLE4 ~func() T.Tuple4[T1, T2, T3, T4],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
T1, T2, T3, T4 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
t4 G_T4,
) G_TUPLE4 {
return A.SequenceT4(
Map[G_T1, func() func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], T1, func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]],
Ap[func() func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], func() func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], G_T2],
Ap[func() func(T4) T.Tuple4[T1, T2, T3, T4], func() func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], G_T3],
Ap[G_TUPLE4, func() func(T4) T.Tuple4[T1, T2, T3, T4], G_T4],
t1,
t2,
t3,
t4,
)
}
// SequenceTuple4 converts a [T.Tuple4[func() T]] into a [func() T.Tuple4[T1, T2, T3, T4]]
func SequenceTuple4[
G_TUPLE4 ~func() T.Tuple4[T1, T2, T3, T4],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
T1, T2, T3, T4 any](t T.Tuple4[G_T1, G_T2, G_T3, G_T4]) G_TUPLE4 {
return A.SequenceTuple4(
Map[G_T1, func() func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], T1, func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]],
Ap[func() func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], func() func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], G_T2],
Ap[func() func(T4) T.Tuple4[T1, T2, T3, T4], func() func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], G_T3],
Ap[G_TUPLE4, func() func(T4) T.Tuple4[T1, T2, T3, T4], G_T4],
t)
}
// TraverseTuple4 converts a [T.Tuple4[func() T]] into a [func() T.Tuple4[T1, T2, T3, T4]]
func TraverseTuple4[
G_TUPLE4 ~func() T.Tuple4[T1, T2, T3, T4],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
F4 ~func(A4) G_T4,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
A1, A2, A3, A4, T1, T2, T3, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) G_TUPLE4 {
return func(t T.Tuple4[A1, A2, A3, A4]) G_TUPLE4 {
return A.TraverseTuple4(
Map[G_T1, func() func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], T1, func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4]],
Ap[func() func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], func() func(T2) func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], G_T2],
Ap[func() func(T4) T.Tuple4[T1, T2, T3, T4], func() func(T3) func(T4) T.Tuple4[T1, T2, T3, T4], G_T3],
Ap[G_TUPLE4, func() func(T4) T.Tuple4[T1, T2, T3, T4], G_T4],
f1,
f2,
f3,
f4,
t)
}
}
// SequenceT5 converts 5 [func() T] into a [func() T.Tuple5[T1, T2, T3, T4, T5]]
func SequenceT5[
G_TUPLE5 ~func() T.Tuple5[T1, T2, T3, T4, T5],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
T1, T2, T3, T4, T5 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
t4 G_T4,
t5 G_T5,
) G_TUPLE5 {
return A.SequenceT5(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], T1, func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]],
Ap[func() func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T2],
Ap[func() func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T3],
Ap[func() func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T4],
Ap[G_TUPLE5, func() func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T5],
t1,
t2,
t3,
t4,
t5,
)
}
// SequenceTuple5 converts a [T.Tuple5[func() T]] into a [func() T.Tuple5[T1, T2, T3, T4, T5]]
func SequenceTuple5[
G_TUPLE5 ~func() T.Tuple5[T1, T2, T3, T4, T5],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
T1, T2, T3, T4, T5 any](t T.Tuple5[G_T1, G_T2, G_T3, G_T4, G_T5]) G_TUPLE5 {
return A.SequenceTuple5(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], T1, func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]],
Ap[func() func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T2],
Ap[func() func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T3],
Ap[func() func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T4],
Ap[G_TUPLE5, func() func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T5],
t)
}
// TraverseTuple5 converts a [T.Tuple5[func() T]] into a [func() T.Tuple5[T1, T2, T3, T4, T5]]
func TraverseTuple5[
G_TUPLE5 ~func() T.Tuple5[T1, T2, T3, T4, T5],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
F4 ~func(A4) G_T4,
F5 ~func(A5) G_T5,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
A1, A2, A3, A4, A5, T1, T2, T3, T4, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) G_TUPLE5 {
return func(t T.Tuple5[A1, A2, A3, A4, A5]) G_TUPLE5 {
return A.TraverseTuple5(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], T1, func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5]],
Ap[func() func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T2) func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T2],
Ap[func() func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T3) func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T3],
Ap[func() func(T5) T.Tuple5[T1, T2, T3, T4, T5], func() func(T4) func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T4],
Ap[G_TUPLE5, func() func(T5) T.Tuple5[T1, T2, T3, T4, T5], G_T5],
f1,
f2,
f3,
f4,
f5,
t)
}
}
// SequenceT6 converts 6 [func() T] into a [func() T.Tuple6[T1, T2, T3, T4, T5, T6]]
func SequenceT6[
G_TUPLE6 ~func() T.Tuple6[T1, T2, T3, T4, T5, T6],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
T1, T2, T3, T4, T5, T6 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
t4 G_T4,
t5 G_T5,
t6 G_T6,
) G_TUPLE6 {
return A.SequenceT6(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], T1, func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]],
Ap[func() func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T2],
Ap[func() func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T3],
Ap[func() func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T4],
Ap[func() func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T5],
Ap[G_TUPLE6, func() func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T6],
t1,
t2,
t3,
t4,
t5,
t6,
)
}
// SequenceTuple6 converts a [T.Tuple6[func() T]] into a [func() T.Tuple6[T1, T2, T3, T4, T5, T6]]
func SequenceTuple6[
G_TUPLE6 ~func() T.Tuple6[T1, T2, T3, T4, T5, T6],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
T1, T2, T3, T4, T5, T6 any](t T.Tuple6[G_T1, G_T2, G_T3, G_T4, G_T5, G_T6]) G_TUPLE6 {
return A.SequenceTuple6(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], T1, func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]],
Ap[func() func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T2],
Ap[func() func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T3],
Ap[func() func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T4],
Ap[func() func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T5],
Ap[G_TUPLE6, func() func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T6],
t)
}
// TraverseTuple6 converts a [T.Tuple6[func() T]] into a [func() T.Tuple6[T1, T2, T3, T4, T5, T6]]
func TraverseTuple6[
G_TUPLE6 ~func() T.Tuple6[T1, T2, T3, T4, T5, T6],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
F4 ~func(A4) G_T4,
F5 ~func(A5) G_T5,
F6 ~func(A6) G_T6,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
A1, A2, A3, A4, A5, A6, T1, T2, T3, T4, T5, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) G_TUPLE6 {
return func(t T.Tuple6[A1, A2, A3, A4, A5, A6]) G_TUPLE6 {
return A.TraverseTuple6(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], T1, func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6]],
Ap[func() func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T2) func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T2],
Ap[func() func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T3) func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T3],
Ap[func() func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T4) func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T4],
Ap[func() func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], func() func(T5) func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T5],
Ap[G_TUPLE6, func() func(T6) T.Tuple6[T1, T2, T3, T4, T5, T6], G_T6],
f1,
f2,
f3,
f4,
f5,
f6,
t)
}
}
// SequenceT7 converts 7 [func() T] into a [func() T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
func SequenceT7[
G_TUPLE7 ~func() T.Tuple7[T1, T2, T3, T4, T5, T6, T7],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
T1, T2, T3, T4, T5, T6, T7 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
t4 G_T4,
t5 G_T5,
t6 G_T6,
t7 G_T7,
) G_TUPLE7 {
return A.SequenceT7(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T3],
Ap[func() func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T4],
Ap[func() func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T5],
Ap[func() func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T6],
Ap[G_TUPLE7, func() func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T7],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
)
}
// SequenceTuple7 converts a [T.Tuple7[func() T]] into a [func() T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
func SequenceTuple7[
G_TUPLE7 ~func() T.Tuple7[T1, T2, T3, T4, T5, T6, T7],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[G_T1, G_T2, G_T3, G_T4, G_T5, G_T6, G_T7]) G_TUPLE7 {
return A.SequenceTuple7(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T3],
Ap[func() func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T4],
Ap[func() func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T5],
Ap[func() func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T6],
Ap[G_TUPLE7, func() func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T7],
t)
}
// TraverseTuple7 converts a [T.Tuple7[func() T]] into a [func() T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
func TraverseTuple7[
G_TUPLE7 ~func() T.Tuple7[T1, T2, T3, T4, T5, T6, T7],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
F4 ~func(A4) G_T4,
F5 ~func(A5) G_T5,
F6 ~func(A6) G_T6,
F7 ~func(A7) G_T7,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
A1, A2, A3, A4, A5, A6, A7, T1, T2, T3, T4, T5, T6, 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]) G_TUPLE7 {
return func(t T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) G_TUPLE7 {
return A.TraverseTuple7(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T3) func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T3],
Ap[func() func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T4) func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T4],
Ap[func() func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T5) func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T5],
Ap[func() func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], func() func(T6) func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T6],
Ap[G_TUPLE7, func() func(T7) T.Tuple7[T1, T2, T3, T4, T5, T6, T7], G_T7],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
t)
}
}
// SequenceT8 converts 8 [func() T] into a [func() T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
func SequenceT8[
G_TUPLE8 ~func() T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
T1, T2, T3, T4, T5, T6, T7, T8 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
t4 G_T4,
t5 G_T5,
t6 G_T6,
t7 G_T7,
t8 G_T8,
) G_TUPLE8 {
return A.SequenceT8(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T4],
Ap[func() func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T5],
Ap[func() func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T6],
Ap[func() func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T7],
Ap[G_TUPLE8, func() func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T8],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
)
}
// SequenceTuple8 converts a [T.Tuple8[func() T]] into a [func() T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
func SequenceTuple8[
G_TUPLE8 ~func() T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[G_T1, G_T2, G_T3, G_T4, G_T5, G_T6, G_T7, G_T8]) G_TUPLE8 {
return A.SequenceTuple8(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T4],
Ap[func() func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T5],
Ap[func() func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T6],
Ap[func() func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T7],
Ap[G_TUPLE8, func() func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T8],
t)
}
// TraverseTuple8 converts a [T.Tuple8[func() T]] into a [func() T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
func TraverseTuple8[
G_TUPLE8 ~func() T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
F4 ~func(A4) G_T4,
F5 ~func(A5) G_T5,
F6 ~func(A6) G_T6,
F7 ~func(A7) G_T7,
F8 ~func(A8) G_T8,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
A1, A2, A3, A4, A5, A6, A7, A8, T1, T2, T3, T4, T5, T6, T7, 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]) G_TUPLE8 {
return func(t T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) G_TUPLE8 {
return A.TraverseTuple8(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T4) func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T4],
Ap[func() func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T5) func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T5],
Ap[func() func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T6) func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T6],
Ap[func() func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], func() func(T7) func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T7],
Ap[G_TUPLE8, func() func(T8) T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8], G_T8],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
t)
}
}
// SequenceT9 converts 9 [func() T] into a [func() T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
func SequenceT9[
G_TUPLE9 ~func() T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
G_T9 ~func() T9,
T1, T2, T3, T4, T5, T6, T7, T8, T9 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
t4 G_T4,
t5 G_T5,
t6 G_T6,
t7 G_T7,
t8 G_T8,
t9 G_T9,
) G_TUPLE9 {
return A.SequenceT9(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T4],
Ap[func() func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T5],
Ap[func() func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T6],
Ap[func() func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T7],
Ap[func() func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T8],
Ap[G_TUPLE9, func() func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T9],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
t9,
)
}
// SequenceTuple9 converts a [T.Tuple9[func() T]] into a [func() T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
func SequenceTuple9[
G_TUPLE9 ~func() T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
G_T9 ~func() T9,
T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[G_T1, G_T2, G_T3, G_T4, G_T5, G_T6, G_T7, G_T8, G_T9]) G_TUPLE9 {
return A.SequenceTuple9(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T4],
Ap[func() func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T5],
Ap[func() func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T6],
Ap[func() func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T7],
Ap[func() func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T8],
Ap[G_TUPLE9, func() func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T9],
t)
}
// TraverseTuple9 converts a [T.Tuple9[func() T]] into a [func() T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
func TraverseTuple9[
G_TUPLE9 ~func() T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
F4 ~func(A4) G_T4,
F5 ~func(A5) G_T5,
F6 ~func(A6) G_T6,
F7 ~func(A7) G_T7,
F8 ~func(A8) G_T8,
F9 ~func(A9) G_T9,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
G_T9 ~func() T9,
A1, A2, A3, A4, A5, A6, A7, A8, A9, T1, T2, T3, T4, T5, T6, T7, T8, 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]) G_TUPLE9 {
return func(t T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) G_TUPLE9 {
return A.TraverseTuple9(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T4],
Ap[func() func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T5) func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T5],
Ap[func() func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T6) func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T6],
Ap[func() func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T7) func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T7],
Ap[func() func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], func() func(T8) func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T8],
Ap[G_TUPLE9, func() func(T9) T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9], G_T9],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
t)
}
}
// SequenceT10 converts 10 [func() T] into a [func() T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
func SequenceT10[
G_TUPLE10 ~func() T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
G_T9 ~func() T9,
G_T10 ~func() T10,
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](
t1 G_T1,
t2 G_T2,
t3 G_T3,
t4 G_T4,
t5 G_T5,
t6 G_T6,
t7 G_T7,
t8 G_T8,
t9 G_T9,
t10 G_T10,
) G_TUPLE10 {
return A.SequenceT10(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T4],
Ap[func() func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T5],
Ap[func() func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T6],
Ap[func() func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T7],
Ap[func() func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T8],
Ap[func() func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T9],
Ap[G_TUPLE10, func() func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T10],
t1,
t2,
t3,
t4,
t5,
t6,
t7,
t8,
t9,
t10,
)
}
// SequenceTuple10 converts a [T.Tuple10[func() T]] into a [func() T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
func SequenceTuple10[
G_TUPLE10 ~func() T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10],
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
G_T9 ~func() T9,
G_T10 ~func() T10,
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[G_T1, G_T2, G_T3, G_T4, G_T5, G_T6, G_T7, G_T8, G_T9, G_T10]) G_TUPLE10 {
return A.SequenceTuple10(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T4],
Ap[func() func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T5],
Ap[func() func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T6],
Ap[func() func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T7],
Ap[func() func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T8],
Ap[func() func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T9],
Ap[G_TUPLE10, func() func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T10],
t)
}
// TraverseTuple10 converts a [T.Tuple10[func() T]] into a [func() T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
func TraverseTuple10[
G_TUPLE10 ~func() T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10],
F1 ~func(A1) G_T1,
F2 ~func(A2) G_T2,
F3 ~func(A3) G_T3,
F4 ~func(A4) G_T4,
F5 ~func(A5) G_T5,
F6 ~func(A6) G_T6,
F7 ~func(A7) G_T7,
F8 ~func(A8) G_T8,
F9 ~func(A9) G_T9,
F10 ~func(A10) G_T10,
G_T1 ~func() T1,
G_T2 ~func() T2,
G_T3 ~func() T3,
G_T4 ~func() T4,
G_T5 ~func() T5,
G_T6 ~func() T6,
G_T7 ~func() T7,
G_T8 ~func() T8,
G_T9 ~func() T9,
G_T10 ~func() T10,
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, T1, T2, T3, T4, T5, T6, T7, T8, T9, 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]) G_TUPLE10 {
return func(t T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) G_TUPLE10 {
return A.TraverseTuple10(
Map[G_T1, func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T1, func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]],
Ap[func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T2) func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T2],
Ap[func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T3) func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T3],
Ap[func() func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T4) func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T4],
Ap[func() func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T5) func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T5],
Ap[func() func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T6) func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T6],
Ap[func() func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T7) func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T7],
Ap[func() func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T8) func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T8],
Ap[func() func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], func() func(T9) func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T9],
Ap[G_TUPLE10, func() func(T10) T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], G_T10],
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
t)
}
}

View File

@@ -16,11 +16,11 @@
package generic
import (
"sync"
"time"
F "github.com/IBM/fp-go/function"
C "github.com/IBM/fp-go/internal/chain"
L "github.com/IBM/fp-go/internal/lazy"
)
// type IO[A any] = func() A
@@ -119,18 +119,7 @@ func Flatten[GA ~func() A, GAA ~func() GA, A any](mma GAA) GA {
// Memoize computes the value of the provided IO monad lazily but exactly once
func Memoize[GA ~func() A, A any](ma GA) GA {
// synchronization primitives
var once sync.Once
var result A
// callback
gen := func() {
result = ma()
}
// returns our memoized wrapper
return func() A {
once.Do(gen)
return result
}
return L.Memoize[GA, A](ma)
}
// Delay creates an operation that passes in the value after some delay

View File

@@ -16,6 +16,7 @@
package generic
import (
"fmt"
"log"
Logging "github.com/IBM/fp-go/logging"
@@ -39,3 +40,11 @@ func Logf[GA ~func() any, A any](prefix string) func(A) GA {
})
}
}
func Printf[GA ~func() any, A any](prefix string) func(A) GA {
return func(a A) GA {
return FromImpure[GA](func() {
fmt.Printf(prefix, a)
})
}
}

View File

@@ -1,60 +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 generic
import (
"github.com/IBM/fp-go/internal/apply"
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[GA ~func() A, GTA ~func() T.Tuple1[A], A any](a GA) GTA {
return apply.SequenceT1(
Map[GA, GTA, A, T.Tuple1[A]],
a,
)
}
func SequenceT2[GA ~func() A, GB ~func() B, GTAB ~func() T.Tuple2[A, B], A, B any](a GA, b GB) GTAB {
return apply.SequenceT2(
Map[GA, func() func(B) T.Tuple2[A, B], A, func(B) T.Tuple2[A, B]],
Ap[GTAB, func() func(B) T.Tuple2[A, B], GB],
a, b,
)
}
func SequenceT3[GA ~func() A, GB ~func() B, GC ~func() C, GTABC ~func() T.Tuple3[A, B, C], A, B, C any](a GA, b GB, c GC) GTABC {
return apply.SequenceT3(
Map[GA, func() func(B) func(C) T.Tuple3[A, B, C], A, func(B) func(C) T.Tuple3[A, B, C]],
Ap[func() func(C) T.Tuple3[A, B, C], func() func(B) func(C) T.Tuple3[A, B, C], GB],
Ap[GTABC, func() func(C) T.Tuple3[A, B, C], GC],
a, b, c,
)
}
func SequenceT4[GA ~func() A, GB ~func() B, GC ~func() C, GD ~func() D, GTABCD ~func() T.Tuple4[A, B, C, D], A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
return apply.SequenceT4(
Map[GA, func() func(B) func(C) func(D) T.Tuple4[A, B, C, D], A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
Ap[func() func(C) func(D) T.Tuple4[A, B, C, D], func() func(B) func(C) func(D) T.Tuple4[A, B, C, D], GB],
Ap[func() func(D) T.Tuple4[A, B, C, D], func() func(C) func(D) T.Tuple4[A, B, C, D], GC],
Ap[GTABCD, func() func(D) T.Tuple4[A, B, C, D], GD],
a, b, c, d,
)
}

View File

@@ -31,3 +31,9 @@ func Logger[A any](loggers ...*log.Logger) func(string) func(A) IO[any] {
func Logf[A any](prefix string) func(A) IO[any] {
return G.Logf[IO[any], A](prefix)
}
// Printf constructs a printer function that can be used with ChainXXXIOK
// the string prefix contains the format string for the log value
func Printf[A any](prefix string) func(A) IO[any] {
return G.Printf[IO[any], A](prefix)
}

View File

@@ -20,21 +20,21 @@ import (
)
// MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApFirst[E, A, B any](first IOEither[E, A], second IOEither[E, B]) IOEither[E, A] {
func MonadApFirst[A, E, B any](first IOEither[E, A], second IOEither[E, B]) IOEither[E, A] {
return G.MonadApFirst[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) A]](first, second)
}
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[E, A, B any](second IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] {
func ApFirst[A, E, B any](second IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] {
return G.ApFirst[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) A]](second)
}
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[E, A, B any](first IOEither[E, A], second IOEither[E, B]) IOEither[E, B] {
func MonadApSecond[A, E, B any](first IOEither[E, A], second IOEither[E, B]) IOEither[E, B] {
return G.MonadApSecond[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) B]](first, second)
}
// ApSecond combines two effectful actions, keeping only the result of the second.
func ApSecond[E, A, B any](second IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
func ApSecond[A, E, B any](second IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ApSecond[IOEither[E, A], IOEither[E, B], IOEither[E, func(B) B]](second)
}

44
ioeither/bind.go Normal file
View 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 ioeither
import (
G "github.com/IBM/fp-go/ioeither/generic"
)
// Bind applies a function to an input state and merges the result into that state
func Bind[E, A, S1, S2 any](s func(A) func(S1) S2, f func(S1) IOEither[E, A]) func(IOEither[E, S1]) IOEither[E, S2] {
return G.Bind[IOEither[E, S1], IOEither[E, S2], IOEither[E, A], func(S1) IOEither[E, A]](s, f)
}
// BindTo initializes some state based on a value
func BindTo[
E, A, S2 any](s func(A) S2) func(IOEither[E, A]) IOEither[E, S2] {
return G.BindTo[IOEither[E, S2], IOEither[E, A]](s)
}
func ApS[
E, A, S1, S2 any,
](s func(A) func(S1) S2, fa IOEither[E, A]) func(IOEither[E, S1]) IOEither[E, S2] {
return G.ApS[IOEither[E, S1], IOEither[E, S2], IOEither[E, A], IOEither[E, func(S1) S2]](s, fa)
}
func Let[E, A, S1, S2 any](
s func(A) func(S1) S2,
f func(S1) A,
) func(IOEither[E, S1]) IOEither[E, S2] {
return G.Let[IOEither[E, S1], IOEither[E, S2]](s, f)
}

18
ioeither/doc.go Normal file
View File

@@ -0,0 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ioeither
//go:generate go run .. ioeither --count 10 --filename gen.go

View 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 ioeither
import (
"fmt"
E "github.com/IBM/fp-go/either"
)
func ExampleIOEither_creation() {
// Build an IOEither
leftValue := Left[string](fmt.Errorf("some error"))
rightValue := Right[error]("value")
// Convert from Either
eitherValue := E.Of[error](42)
ioFromEither := FromEither(eitherValue)
// some predicate
isEven := func(num int) (int, error) {
if num%2 == 0 {
return num, nil
}
return 0, fmt.Errorf("%d is an odd number", num)
}
fromEven := Eitherize1(isEven)
leftFromPred := fromEven(3)
rightFromPred := fromEven(4)
fmt.Println(leftValue())
fmt.Println(rightValue())
fmt.Println(ioFromEither())
fmt.Println(leftFromPred())
fmt.Println(rightFromPred())
// Output:
// Left[*errors.errorString, string](some error)
// Right[<nil>, string](value)
// Right[<nil>, int](42)
// Left[*errors.errorString, int](3 is an odd number)
// Right[<nil>, int](4)
}

View 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 ioeither
import (
"fmt"
"log"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
T "github.com/IBM/fp-go/tuple"
)
func ExampleIOEither_do() {
foo := Of[error]("foo")
bar := Of[error](1)
// quux consumes the state of three bindings and returns an [IO] instead of an [IOEither]
quux := func(t T.Tuple3[string, int, string]) IO.IO[any] {
return IO.FromImpure(func() {
log.Printf("t1: %s, t2: %d, t3: %s", t.F1, t.F2, t.F3)
})
}
transform := func(t T.Tuple3[string, int, string]) int {
return len(t.F1) + t.F2 + len(t.F3)
}
b := F.Pipe5(
foo,
BindTo[error](T.Of[string]),
ApS(T.Push1[string, int], bar),
Bind(T.Push2[string, int, string], func(t T.Tuple2[string, int]) IOEither[error, string] {
return Of[error](fmt.Sprintf("%s%d", t.F1, t.F2))
}),
ChainFirstIOK[error](quux),
Map[error](transform),
)
fmt.Println(b())
// Output:
// Right[<nil>, int](8)
}

View 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 ioeither
import (
"fmt"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
)
func ExampleIOEither_extraction() {
// IOEither
someIOEither := Right[error](42)
eitherValue := someIOEither() // E.Right(42)
value := E.GetOrElse(F.Constant1[error](0))(eitherValue) // 42
// Or more directly
infaillibleIO := GetOrElse(F.Constant1[error](IO.Of(0)))(someIOEither) // => IO.Right(42)
valueFromIO := infaillibleIO() // => 42
fmt.Println(eitherValue)
fmt.Println(value)
fmt.Println(valueFromIO)
// Output:
// Right[<nil>, int](42)
// 42
// 42
}

View File

@@ -21,6 +21,7 @@ import (
IOE "github.com/IBM/fp-go/ioeither"
)
// onClose closes a closeable resource
func onClose[R io.Closer](r R) IOE.IOEither[error, R] {
return IOE.TryCatchError(func() (R, error) {
return r, r.Close()

View File

@@ -24,14 +24,24 @@ import (
var (
// Open opens a file for reading
Open = IOE.Eitherize1(os.Open)
// Create opens a file for writing
Create = IOE.Eitherize1(os.Create)
// ReadFile reads the context of a file
ReadFile = IOE.Eitherize1(os.ReadFile)
// WriteFile writes a data blob to a file
WriteFile = func(dstName string, perm os.FileMode) func([]byte) IOE.IOEither[error, []byte] {
return func(data []byte) IOE.IOEither[error, []byte] {
return IOE.TryCatchError(func() ([]byte, error) {
return data, os.WriteFile(dstName, data, perm)
})
}
}
)
// WriteFile writes a data blob to a file
func WriteFile(dstName string, perm os.FileMode) func([]byte) IOE.IOEither[error, []byte] {
return func(data []byte) IOE.IOEither[error, []byte] {
return IOE.TryCatchError(func() ([]byte, error) {
return data, os.WriteFile(dstName, data, perm)
})
}
}
// Remove removes a file by name
func Remove(name string) IOE.IOEither[error, string] {
return IOE.TryCatchError(func() (string, error) {
return name, os.Remove(name)
})
}

View File

@@ -29,7 +29,7 @@ func onReadAll[R io.Reader](r R) IOE.IOEither[error, []byte] {
// ReadAll uses a generator function to create a stream, reads it and closes it
func ReadAll[R io.ReadCloser](acquire IOE.IOEither[error, R]) IOE.IOEither[error, []byte] {
return IOE.WithResource[error, R, []byte](
return IOE.WithResource[[]byte](
acquire,
onClose[R])(
onReadAll[R],

45
ioeither/file/tempfile.go Normal file
View 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 file
import (
"os"
FL "github.com/IBM/fp-go/file"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
IOF "github.com/IBM/fp-go/io/file"
IOE "github.com/IBM/fp-go/ioeither"
)
var (
// CreateTemp created a temp file with proper parametrization
CreateTemp = IOE.Eitherize2(os.CreateTemp)
// onCreateTempFile creates a temp file with sensible defaults
onCreateTempFile = CreateTemp("", "*")
// destroy handler
onReleaseTempFile = F.Flow4(
IOF.Close[*os.File],
IO.Map(FL.GetName),
IOE.FromIO[error, string],
IOE.Chain(Remove),
)
)
// 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) IOE.IOEither[error, A]) IOE.IOEither[error, A] {
return IOE.WithResource[A](onCreateTempFile, onReleaseTempFile)(f)
}

View File

@@ -0,0 +1,46 @@
// 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"
"testing"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
IOE "github.com/IBM/fp-go/ioeither"
"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())
}
func TestWithTempFileOnClosedFile(t *testing.T) {
res := WithTempFile(func(f *os.File) IOE.IOEither[error, []byte] {
return F.Pipe2(
f,
onWriteAll[*os.File]([]byte("Carsten")),
IOE.ChainFirst(F.Constant1[[]byte](onClose(f))),
)
})
assert.Equal(t, E.Of[error]([]byte("Carsten")), res())
}

View File

@@ -34,7 +34,7 @@ func onWriteAll[W io.Writer](data []byte) func(w W) IOE.IOEither[error, []byte]
func WriteAll[W io.WriteCloser](data []byte) func(acquire IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
onWrite := onWriteAll[W](data)
return func(onCreate IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
return IOE.WithResource[error, W, []byte](
return IOE.WithResource[[]byte](
onCreate,
onClose[W])(
onWrite,
@@ -43,8 +43,8 @@ func WriteAll[W io.WriteCloser](data []byte) func(acquire IOE.IOEither[error, W]
}
// Write uses a generator function to create a stream, writes data to it and closes it
func Write[W io.WriteCloser, R any](acquire IOE.IOEither[error, W]) func(use func(W) IOE.IOEither[error, R]) IOE.IOEither[error, R] {
return IOE.WithResource[error, W, R](
func Write[R any, W io.WriteCloser](acquire IOE.IOEither[error, W]) func(use func(W) IOE.IOEither[error, R]) IOE.IOEither[error, R] {
return IOE.WithResource[R](
acquire,
onClose[W])
}

485
ioeither/gen.go Normal file
View File

@@ -0,0 +1,485 @@
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-08-17 22:59:12.0033119 +0200 CEST m=+0.096740401
package ioeither
import (
G "github.com/IBM/fp-go/ioeither/generic"
T "github.com/IBM/fp-go/tuple"
)
// Eitherize0 converts a function with 1 parameters returning a tuple into a function with 0 parameters returning a [IOEither[error, R]]
func Eitherize0[F ~func() (R, error), R any](f F) func() IOEither[error, R] {
return G.Eitherize0[IOEither[error, R]](f)
}
// Uneitherize0 converts a function with 1 parameters returning a tuple into a function with 0 parameters returning a [IOEither[error, R]]
func Uneitherize0[F ~func() IOEither[error, R], R any](f F) func() (R, error) {
return G.Uneitherize0[IOEither[error, R]](f)
}
// Eitherize1 converts a function with 2 parameters returning a tuple into a function with 1 parameters returning a [IOEither[error, R]]
func Eitherize1[F ~func(T1) (R, error), T1, R any](f F) func(T1) IOEither[error, R] {
return G.Eitherize1[IOEither[error, R]](f)
}
// Uneitherize1 converts a function with 2 parameters returning a tuple into a function with 1 parameters returning a [IOEither[error, R]]
func Uneitherize1[F ~func(T1) IOEither[error, R], T1, R any](f F) func(T1) (R, error) {
return G.Uneitherize1[IOEither[error, R]](f)
}
// SequenceT1 converts 1 [IOEither[E, T]] into a [IOEither[E, T.Tuple1[T1]]]
func SequenceT1[E, T1 any](
t1 IOEither[E, T1],
) IOEither[E, T.Tuple1[T1]] {
return G.SequenceT1[
IOEither[E, T.Tuple1[T1]],
IOEither[E, T1],
](t1)
}
// SequenceTuple1 converts a [T.Tuple1[IOEither[E, T]]] into a [IOEither[E, T.Tuple1[T1]]]
func SequenceTuple1[E, T1 any](t T.Tuple1[IOEither[E, T1]]) IOEither[E, T.Tuple1[T1]] {
return G.SequenceTuple1[
IOEither[E, T.Tuple1[T1]],
IOEither[E, T1],
](t)
}
// TraverseTuple1 converts a [T.Tuple1[IOEither[E, T]]] into a [IOEither[E, T.Tuple1[T1]]]
func TraverseTuple1[F1 ~func(A1) IOEither[E, T1], E, A1, T1 any](f1 F1) func(T.Tuple1[A1]) IOEither[E, T.Tuple1[T1]] {
return G.TraverseTuple1[IOEither[E, T.Tuple1[T1]]](f1)
}
// Eitherize2 converts a function with 3 parameters returning a tuple into a function with 2 parameters returning a [IOEither[error, R]]
func Eitherize2[F ~func(T1, T2) (R, error), T1, T2, R any](f F) func(T1, T2) IOEither[error, R] {
return G.Eitherize2[IOEither[error, R]](f)
}
// Uneitherize2 converts a function with 3 parameters returning a tuple into a function with 2 parameters returning a [IOEither[error, R]]
func Uneitherize2[F ~func(T1, T2) IOEither[error, R], T1, T2, R any](f F) func(T1, T2) (R, error) {
return G.Uneitherize2[IOEither[error, R]](f)
}
// SequenceT2 converts 2 [IOEither[E, T]] into a [IOEither[E, T.Tuple2[T1, T2]]]
func SequenceT2[E, T1, T2 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
) IOEither[E, T.Tuple2[T1, T2]] {
return G.SequenceT2[
IOEither[E, T.Tuple2[T1, T2]],
IOEither[E, T1],
IOEither[E, T2],
](t1, t2)
}
// SequenceTuple2 converts a [T.Tuple2[IOEither[E, T]]] into a [IOEither[E, T.Tuple2[T1, T2]]]
func SequenceTuple2[E, T1, T2 any](t T.Tuple2[IOEither[E, T1], IOEither[E, T2]]) IOEither[E, T.Tuple2[T1, T2]] {
return G.SequenceTuple2[
IOEither[E, T.Tuple2[T1, T2]],
IOEither[E, T1],
IOEither[E, T2],
](t)
}
// TraverseTuple2 converts a [T.Tuple2[IOEither[E, T]]] into a [IOEither[E, T.Tuple2[T1, T2]]]
func TraverseTuple2[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], E, A1, A2, T1, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) IOEither[E, T.Tuple2[T1, T2]] {
return G.TraverseTuple2[IOEither[E, T.Tuple2[T1, T2]]](f1, f2)
}
// Eitherize3 converts a function with 4 parameters returning a tuple into a function with 3 parameters returning a [IOEither[error, R]]
func Eitherize3[F ~func(T1, T2, T3) (R, error), T1, T2, T3, R any](f F) func(T1, T2, T3) IOEither[error, R] {
return G.Eitherize3[IOEither[error, R]](f)
}
// Uneitherize3 converts a function with 4 parameters returning a tuple into a function with 3 parameters returning a [IOEither[error, R]]
func Uneitherize3[F ~func(T1, T2, T3) IOEither[error, R], T1, T2, T3, R any](f F) func(T1, T2, T3) (R, error) {
return G.Uneitherize3[IOEither[error, R]](f)
}
// SequenceT3 converts 3 [IOEither[E, T]] into a [IOEither[E, T.Tuple3[T1, T2, T3]]]
func SequenceT3[E, T1, T2, T3 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
) IOEither[E, T.Tuple3[T1, T2, T3]] {
return G.SequenceT3[
IOEither[E, T.Tuple3[T1, T2, T3]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
](t1, t2, t3)
}
// SequenceTuple3 converts a [T.Tuple3[IOEither[E, T]]] into a [IOEither[E, T.Tuple3[T1, T2, T3]]]
func SequenceTuple3[E, T1, T2, T3 any](t T.Tuple3[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3]]) IOEither[E, T.Tuple3[T1, T2, T3]] {
return G.SequenceTuple3[
IOEither[E, T.Tuple3[T1, T2, T3]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
](t)
}
// TraverseTuple3 converts a [T.Tuple3[IOEither[E, T]]] into a [IOEither[E, T.Tuple3[T1, T2, T3]]]
func TraverseTuple3[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], E, A1, A2, A3, T1, T2, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) IOEither[E, T.Tuple3[T1, T2, T3]] {
return G.TraverseTuple3[IOEither[E, T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// Eitherize4 converts a function with 5 parameters returning a tuple into a function with 4 parameters returning a [IOEither[error, R]]
func Eitherize4[F ~func(T1, T2, T3, T4) (R, error), T1, T2, T3, T4, R any](f F) func(T1, T2, T3, T4) IOEither[error, R] {
return G.Eitherize4[IOEither[error, R]](f)
}
// Uneitherize4 converts a function with 5 parameters returning a tuple into a function with 4 parameters returning a [IOEither[error, R]]
func Uneitherize4[F ~func(T1, T2, T3, T4) IOEither[error, R], T1, T2, T3, T4, R any](f F) func(T1, T2, T3, T4) (R, error) {
return G.Uneitherize4[IOEither[error, R]](f)
}
// SequenceT4 converts 4 [IOEither[E, T]] into a [IOEither[E, T.Tuple4[T1, T2, T3, T4]]]
func SequenceT4[E, T1, T2, T3, T4 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
t4 IOEither[E, T4],
) IOEither[E, T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceT4[
IOEither[E, T.Tuple4[T1, T2, T3, T4]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
](t1, t2, t3, t4)
}
// SequenceTuple4 converts a [T.Tuple4[IOEither[E, T]]] into a [IOEither[E, T.Tuple4[T1, T2, T3, T4]]]
func SequenceTuple4[E, T1, T2, T3, T4 any](t T.Tuple4[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3], IOEither[E, T4]]) IOEither[E, T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceTuple4[
IOEither[E, T.Tuple4[T1, T2, T3, T4]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
](t)
}
// TraverseTuple4 converts a [T.Tuple4[IOEither[E, T]]] into a [IOEither[E, T.Tuple4[T1, T2, T3, T4]]]
func TraverseTuple4[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], F4 ~func(A4) IOEither[E, T4], E, A1, A2, A3, A4, T1, T2, T3, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) IOEither[E, T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseTuple4[IOEither[E, T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// Eitherize5 converts a function with 6 parameters returning a tuple into a function with 5 parameters returning a [IOEither[error, R]]
func Eitherize5[F ~func(T1, T2, T3, T4, T5) (R, error), T1, T2, T3, T4, T5, R any](f F) func(T1, T2, T3, T4, T5) IOEither[error, R] {
return G.Eitherize5[IOEither[error, R]](f)
}
// Uneitherize5 converts a function with 6 parameters returning a tuple into a function with 5 parameters returning a [IOEither[error, R]]
func Uneitherize5[F ~func(T1, T2, T3, T4, T5) IOEither[error, R], T1, T2, T3, T4, T5, R any](f F) func(T1, T2, T3, T4, T5) (R, error) {
return G.Uneitherize5[IOEither[error, R]](f)
}
// SequenceT5 converts 5 [IOEither[E, T]] into a [IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceT5[E, T1, T2, T3, T4, T5 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
t4 IOEither[E, T4],
t5 IOEither[E, T5],
) IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceT5[
IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
](t1, t2, t3, t4, t5)
}
// SequenceTuple5 converts a [T.Tuple5[IOEither[E, T]]] into a [IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceTuple5[E, T1, T2, T3, T4, T5 any](t T.Tuple5[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3], IOEither[E, T4], IOEither[E, T5]]) IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceTuple5[
IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
](t)
}
// TraverseTuple5 converts a [T.Tuple5[IOEither[E, T]]] into a [IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]]]
func TraverseTuple5[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], F4 ~func(A4) IOEither[E, T4], F5 ~func(A5) IOEither[E, T5], E, A1, A2, A3, A4, A5, T1, T2, T3, T4, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseTuple5[IOEither[E, T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// Eitherize6 converts a function with 7 parameters returning a tuple into a function with 6 parameters returning a [IOEither[error, R]]
func Eitherize6[F ~func(T1, T2, T3, T4, T5, T6) (R, error), T1, T2, T3, T4, T5, T6, R any](f F) func(T1, T2, T3, T4, T5, T6) IOEither[error, R] {
return G.Eitherize6[IOEither[error, R]](f)
}
// Uneitherize6 converts a function with 7 parameters returning a tuple into a function with 6 parameters returning a [IOEither[error, R]]
func Uneitherize6[F ~func(T1, T2, T3, T4, T5, T6) IOEither[error, R], T1, T2, T3, T4, T5, T6, R any](f F) func(T1, T2, T3, T4, T5, T6) (R, error) {
return G.Uneitherize6[IOEither[error, R]](f)
}
// SequenceT6 converts 6 [IOEither[E, T]] into a [IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceT6[E, T1, T2, T3, T4, T5, T6 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
t4 IOEither[E, T4],
t5 IOEither[E, T5],
t6 IOEither[E, T6],
) IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceT6[
IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
](t1, t2, t3, t4, t5, t6)
}
// SequenceTuple6 converts a [T.Tuple6[IOEither[E, T]]] into a [IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceTuple6[E, T1, T2, T3, T4, T5, T6 any](t T.Tuple6[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3], IOEither[E, T4], IOEither[E, T5], IOEither[E, T6]]) IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceTuple6[
IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
](t)
}
// TraverseTuple6 converts a [T.Tuple6[IOEither[E, T]]] into a [IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]]]
func TraverseTuple6[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], F4 ~func(A4) IOEither[E, T4], F5 ~func(A5) IOEither[E, T5], F6 ~func(A6) IOEither[E, T6], E, A1, A2, A3, A4, A5, A6, T1, T2, T3, T4, T5, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseTuple6[IOEither[E, T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// Eitherize7 converts a function with 8 parameters returning a tuple into a function with 7 parameters returning a [IOEither[error, R]]
func Eitherize7[F ~func(T1, T2, T3, T4, T5, T6, T7) (R, error), T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T1, T2, T3, T4, T5, T6, T7) IOEither[error, R] {
return G.Eitherize7[IOEither[error, R]](f)
}
// Uneitherize7 converts a function with 8 parameters returning a tuple into a function with 7 parameters returning a [IOEither[error, R]]
func Uneitherize7[F ~func(T1, T2, T3, T4, T5, T6, T7) IOEither[error, R], T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T1, T2, T3, T4, T5, T6, T7) (R, error) {
return G.Uneitherize7[IOEither[error, R]](f)
}
// SequenceT7 converts 7 [IOEither[E, T]] into a [IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceT7[E, T1, T2, T3, T4, T5, T6, T7 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
t4 IOEither[E, T4],
t5 IOEither[E, T5],
t6 IOEither[E, T6],
t7 IOEither[E, T7],
) IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceT7[
IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceTuple7 converts a [T.Tuple7[IOEither[E, T]]] into a [IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceTuple7[E, T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3], IOEither[E, T4], IOEither[E, T5], IOEither[E, T6], IOEither[E, T7]]) IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceTuple7[
IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
](t)
}
// TraverseTuple7 converts a [T.Tuple7[IOEither[E, T]]] into a [IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func TraverseTuple7[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], F4 ~func(A4) IOEither[E, T4], F5 ~func(A5) IOEither[E, T5], F6 ~func(A6) IOEither[E, T6], F7 ~func(A7) IOEither[E, T7], E, A1, A2, A3, A4, A5, A6, A7, T1, T2, T3, T4, T5, T6, 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]) IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseTuple7[IOEither[E, T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// Eitherize8 converts a function with 9 parameters returning a tuple into a function with 8 parameters returning a [IOEither[error, R]]
func Eitherize8[F ~func(T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8) IOEither[error, R] {
return G.Eitherize8[IOEither[error, R]](f)
}
// Uneitherize8 converts a function with 9 parameters returning a tuple into a function with 8 parameters returning a [IOEither[error, R]]
func Uneitherize8[F ~func(T1, T2, T3, T4, T5, T6, T7, T8) IOEither[error, R], T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8) (R, error) {
return G.Uneitherize8[IOEither[error, R]](f)
}
// SequenceT8 converts 8 [IOEither[E, T]] into a [IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceT8[E, T1, T2, T3, T4, T5, T6, T7, T8 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
t4 IOEither[E, T4],
t5 IOEither[E, T5],
t6 IOEither[E, T6],
t7 IOEither[E, T7],
t8 IOEither[E, T8],
) IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceT8[
IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
IOEither[E, T8],
](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceTuple8 converts a [T.Tuple8[IOEither[E, T]]] into a [IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceTuple8[E, T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3], IOEither[E, T4], IOEither[E, T5], IOEither[E, T6], IOEither[E, T7], IOEither[E, T8]]) IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceTuple8[
IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
IOEither[E, T8],
](t)
}
// TraverseTuple8 converts a [T.Tuple8[IOEither[E, T]]] into a [IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func TraverseTuple8[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], F4 ~func(A4) IOEither[E, T4], F5 ~func(A5) IOEither[E, T5], F6 ~func(A6) IOEither[E, T6], F7 ~func(A7) IOEither[E, T7], F8 ~func(A8) IOEither[E, T8], E, A1, A2, A3, A4, A5, A6, A7, A8, T1, T2, T3, T4, T5, T6, T7, 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]) IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseTuple8[IOEither[E, T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// Eitherize9 converts a function with 10 parameters returning a tuple into a function with 9 parameters returning a [IOEither[error, R]]
func Eitherize9[F ~func(T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8, T9) IOEither[error, R] {
return G.Eitherize9[IOEither[error, R]](f)
}
// Uneitherize9 converts a function with 10 parameters returning a tuple into a function with 9 parameters returning a [IOEither[error, R]]
func Uneitherize9[F ~func(T1, T2, T3, T4, T5, T6, T7, T8, T9) IOEither[error, R], T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error) {
return G.Uneitherize9[IOEither[error, R]](f)
}
// SequenceT9 converts 9 [IOEither[E, T]] into a [IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceT9[E, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
t4 IOEither[E, T4],
t5 IOEither[E, T5],
t6 IOEither[E, T6],
t7 IOEither[E, T7],
t8 IOEither[E, T8],
t9 IOEither[E, T9],
) IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceT9[
IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
IOEither[E, T8],
IOEither[E, T9],
](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceTuple9 converts a [T.Tuple9[IOEither[E, T]]] into a [IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceTuple9[E, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3], IOEither[E, T4], IOEither[E, T5], IOEither[E, T6], IOEither[E, T7], IOEither[E, T8], IOEither[E, T9]]) IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceTuple9[
IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
IOEither[E, T8],
IOEither[E, T9],
](t)
}
// TraverseTuple9 converts a [T.Tuple9[IOEither[E, T]]] into a [IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func TraverseTuple9[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], F4 ~func(A4) IOEither[E, T4], F5 ~func(A5) IOEither[E, T5], F6 ~func(A6) IOEither[E, T6], F7 ~func(A7) IOEither[E, T7], F8 ~func(A8) IOEither[E, T8], F9 ~func(A9) IOEither[E, T9], E, A1, A2, A3, A4, A5, A6, A7, A8, A9, T1, T2, T3, T4, T5, T6, T7, T8, 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]) IOEither[E, T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseTuple9[IOEither[E, 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 11 parameters returning a tuple into a function with 10 parameters returning a [IOEither[error, R]]
func Eitherize10[F ~func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) (R, error), T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) IOEither[error, R] {
return G.Eitherize10[IOEither[error, R]](f)
}
// Uneitherize10 converts a function with 11 parameters returning a tuple into a function with 10 parameters returning a [IOEither[error, R]]
func Uneitherize10[F ~func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) IOEither[error, R], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R any](f F) func(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) (R, error) {
return G.Uneitherize10[IOEither[error, R]](f)
}
// SequenceT10 converts 10 [IOEither[E, T]] into a [IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceT10[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](
t1 IOEither[E, T1],
t2 IOEither[E, T2],
t3 IOEither[E, T3],
t4 IOEither[E, T4],
t5 IOEither[E, T5],
t6 IOEither[E, T6],
t7 IOEither[E, T7],
t8 IOEither[E, T8],
t9 IOEither[E, T9],
t10 IOEither[E, T10],
) IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceT10[
IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
IOEither[E, T8],
IOEither[E, T9],
IOEither[E, T10],
](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceTuple10 converts a [T.Tuple10[IOEither[E, T]]] into a [IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceTuple10[E, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[IOEither[E, T1], IOEither[E, T2], IOEither[E, T3], IOEither[E, T4], IOEither[E, T5], IOEither[E, T6], IOEither[E, T7], IOEither[E, T8], IOEither[E, T9], IOEither[E, T10]]) IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceTuple10[
IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]],
IOEither[E, T1],
IOEither[E, T2],
IOEither[E, T3],
IOEither[E, T4],
IOEither[E, T5],
IOEither[E, T6],
IOEither[E, T7],
IOEither[E, T8],
IOEither[E, T9],
IOEither[E, T10],
](t)
}
// TraverseTuple10 converts a [T.Tuple10[IOEither[E, T]]] into a [IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func TraverseTuple10[F1 ~func(A1) IOEither[E, T1], F2 ~func(A2) IOEither[E, T2], F3 ~func(A3) IOEither[E, T3], F4 ~func(A4) IOEither[E, T4], F5 ~func(A5) IOEither[E, T5], F6 ~func(A6) IOEither[E, T6], F7 ~func(A7) IOEither[E, T7], F8 ~func(A8) IOEither[E, T8], F9 ~func(A9) IOEither[E, T9], F10 ~func(A10) IOEither[E, T10], E, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, T1, T2, T3, T4, T5, T6, T7, T8, T9, 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]) IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseTuple10[IOEither[E, T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}

View File

@@ -23,7 +23,7 @@ import (
// MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBA ~func() ET.Either[E, func(B) A], E, A, B any](first GA, second GB) GA {
return G.MonadApFirst(
MonadAp[GB, GA, GBA, E, B, A],
MonadAp[GA, GBA, GB],
MonadMap[GA, GBA, E, A, func(B) A],
first,
@@ -34,7 +34,7 @@ func MonadApFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBA ~f
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBA ~func() ET.Either[E, func(B) A], E, A, B any](second GB) func(GA) GA {
return G.ApFirst(
MonadAp[GB, GA, GBA, E, B, A],
MonadAp[GA, GBA, GB],
MonadMap[GA, GBA, E, A, func(B) A],
second,
@@ -44,7 +44,7 @@ func ApFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBA ~func()
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBB ~func() ET.Either[E, func(B) B], E, A, B any](first GA, second GB) GB {
return G.MonadApSecond(
MonadAp[GB, GB, GBB, E, B, B],
MonadAp[GB, GBB, GB],
MonadMap[GA, GBB, E, A, func(B) B],
first,
@@ -55,7 +55,7 @@ func MonadApSecond[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBB ~
// ApSecond combines two effectful actions, keeping only the result of the second.
func ApSecond[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GBB ~func() ET.Either[E, func(B) B], E, A, B any](second GB) func(GA) GB {
return G.ApSecond(
MonadAp[GB, GB, GBB, E, B, B],
MonadAp[GB, GBB, GB],
MonadMap[GA, GBB, E, A, func(B) B],
second,

79
ioeither/generic/bind.go Normal file
View 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 generic
import (
ET "github.com/IBM/fp-go/either"
G "github.com/IBM/fp-go/internal/bindt"
)
// Bind applies a function to an input state and merges the result into that state
func Bind[
GS1 ~func() ET.Either[E, S1],
GS2 ~func() ET.Either[E, S2],
GA ~func() ET.Either[E, A],
FCT ~func(S1) GA,
E any,
SET ~func(A) func(S1) S2,
A, S1, S2 any](s SET, f FCT) func(GS1) GS2 {
return G.Bind(
Chain[GS1, GS2, E, S1, S2],
Map[GA, GS2, E, A, S2],
s,
f,
)
}
// BindTo initializes some state based on a value
func BindTo[
GS2 ~func() ET.Either[E, S2],
GA ~func() ET.Either[E, A],
E any,
SET ~func(A) S2,
A, S2 any](s SET) func(GA) GS2 {
return G.BindTo(
Map[GA, GS2, E, A, S2],
s,
)
}
func ApS[
GS1 ~func() ET.Either[E, S1],
GS2 ~func() ET.Either[E, S2],
GB ~func() ET.Either[E, B],
GS1S2 ~func() ET.Either[E, func(S1) S2],
SET ~func(B) func(S1) S2,
E, S1, S2, B any,
](s SET, fb GB) func(GS1) GS2 {
return G.ApS[SET, S1, S2, B, GS1S2, GS1, GS2, GB](
Ap[GS2, GS1S2, GS1, E, S1, S2],
Map[GB, GS1S2, E, B, func(S1) S2],
s,
fb,
)
}
func Let[
GS1 ~func() ET.Either[E, S1],
GS2 ~func() ET.Either[E, S2],
SET ~func(B) func(S1) S2,
FCT ~func(S1) B,
E, S1, S2, B any](
s SET,
f FCT,
) func(GS1) GS2 {
return G.Let[SET, FCT, S1, S2, B, GS1, GS2](Map[GS1, GS2, E, S1, S2], s, f)
}

1017
ioeither/generic/gen.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -144,37 +144,37 @@ func ChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A,
return F.Bind2nd(MonadChainEitherK[GA, GB, E, A, B], f)
}
func MonadAp[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](mab GAB, ma GA) GB {
func MonadAp[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
return eithert.MonadAp(
IO.MonadAp[GA, GB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, A], ET.Either[E, B]],
IO.MonadMap[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
mab, ma)
}
func Ap[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadAp[GA, GB, GAB, E, A, B], ma)
func Ap[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadAp[GB, GAB, GA], ma)
}
func MonadApSeq[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](mab GAB, ma GA) GB {
func MonadApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
return eithert.MonadAp(
IO.MonadApSeq[GA, GB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, A], ET.Either[E, B]],
IO.MonadMap[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
mab, ma)
}
func ApSeq[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadApSeq[GA, GB, GAB, E, A, B], ma)
func ApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadApSeq[GB, GAB, GA], ma)
}
func MonadApPar[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](mab GAB, ma GA) GB {
func MonadApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
return eithert.MonadAp(
IO.MonadApPar[GA, GB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, A], ET.Either[E, B]],
IO.MonadMap[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
mab, ma)
}
func ApPar[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], E, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadApPar[GA, GB, GAB, E, A, B], ma)
func ApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
return F.Bind2nd(MonadApPar[GB, GAB, GA], ma)
}
func Flatten[GA ~func() ET.Either[E, A], GAA ~func() ET.Either[E, GA], E, A any](mma GAA) GA {
@@ -191,79 +191,6 @@ func TryCatchError[GA ~func() ET.Either[error, A], A any](f func() (A, error)) G
return TryCatch[GA](f, errors.IdentityError)
}
func Eitherize0[GEA ~func() ET.Either[error, A], GA ~func() (A, error), A any](f GA) func() GEA {
ef := ET.Eitherize0(f)
return func() GEA {
return MakeIO(ef)
}
}
func Uneitherize0[GEA ~func() ET.Either[error, A], GTA ~func() GEA, A any](f GTA) func() (A, error) {
return func() (A, error) {
return ET.Unwrap(f()())
}
}
func Eitherize1[GEA ~func() ET.Either[error, A], GA ~func(t1 T1) (A, error), T1, A any](f GA) func(T1) GEA {
ef := ET.Eitherize1(f)
return func(t1 T1) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1)
})
}
}
func Uneitherize1[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1) GEA, T1, A any](f GTA) func(T1) (A, error) {
return func(t1 T1) (A, error) {
return ET.Unwrap(f(t1)())
}
}
func Eitherize2[GEA ~func() ET.Either[error, A], GA ~func(t1 T1, t2 T2) (A, error), T1, T2, A any](f GA) func(T1, T2) GEA {
ef := ET.Eitherize2(f)
return func(t1 T1, t2 T2) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1, t2)
})
}
}
func Uneitherize2[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1, t2 T2) GEA, T1, T2, A any](f GTA) func(T1, T2) (A, error) {
return func(t1 T1, t2 T2) (A, error) {
return ET.Unwrap(f(t1, t2)())
}
}
func Eitherize3[GEA ~func() ET.Either[error, A], GA ~func(t1 T1, t2 T2, t3 T3) (A, error), T1, T2, T3, A any](f GA) func(T1, T2, T3) GEA {
ef := ET.Eitherize3(f)
return func(t1 T1, t2 T2, t3 T3) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1, t2, t3)
})
}
}
func Uneitherize3[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1, t2 T2, t3 T3) GEA, T1, T2, T3, A any](f GTA) func(T1, T2, T3) (A, error) {
return func(t1 T1, t2 T2, t3 T3) (A, error) {
return ET.Unwrap(f(t1, t2, t3)())
}
}
func Eitherize4[GEA ~func() ET.Either[error, A], GA ~func(t1 T1, t2 T2, t3 T3, t4 T4) (A, error), T1, T2, T3, T4, A any](f GA) func(T1, T2, T3, T4) GEA {
ef := ET.Eitherize4(f)
return func(t1 T1, t2 T2, t3 T3, t4 T4) GEA {
return MakeIO[GEA](func() ET.Either[error, A] {
return ef(t1, t2, t3, t4)
})
}
}
func Uneitherize4[GEA ~func() ET.Either[error, A], GTA ~func(t1 T1, t2 T2, t3 T3, t4 T4) GEA, T1, T2, T3, T4, A any](f GTA) func(T1, T2, T3, T4) (A, error) {
return func(t1 T1, t2 T2, t3 T3, t4 T4) (A, error) {
return ET.Unwrap(f(t1, t2, t3, t4)())
}
}
// Memoize computes the value of the provided IO monad lazily but exactly once
func Memoize[GA ~func() ET.Either[E, A], E, A any](ma GA) GA {
return IO.Memoize(ma)

View File

@@ -1,62 +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 generic
import (
ET "github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/internal/apply"
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[GA ~func() ET.Either[E, A], GTA ~func() ET.Either[E, T.Tuple1[A]], E, A any](a GA) GTA {
return apply.SequenceT1(
Map[GA, GTA, E, A, T.Tuple1[A]],
a,
)
}
func SequenceT2[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GTAB ~func() ET.Either[E, T.Tuple2[A, B]], E, A, B any](a GA, b GB) GTAB {
return apply.SequenceT2(
Map[GA, func() ET.Either[E, func(B) T.Tuple2[A, B]], E, A, func(B) T.Tuple2[A, B]],
Ap[GB, GTAB, func() ET.Either[E, func(B) T.Tuple2[A, B]], E, B, T.Tuple2[A, B]],
a, b,
)
}
func SequenceT3[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GC ~func() ET.Either[E, C], GTABC ~func() ET.Either[E, T.Tuple3[A, B, C]], E, A, B, C any](a GA, b GB, c GC) GTABC {
return apply.SequenceT3(
Map[GA, func() ET.Either[E, func(B) func(C) T.Tuple3[A, B, C]], E, A, func(B) func(C) T.Tuple3[A, B, C]],
Ap[GB, func() ET.Either[E, func(C) T.Tuple3[A, B, C]], func() ET.Either[E, func(B) func(C) T.Tuple3[A, B, C]], E, B, func(C) T.Tuple3[A, B, C]],
Ap[GC, GTABC, func() ET.Either[E, func(C) T.Tuple3[A, B, C]], E, C, T.Tuple3[A, B, C]],
a, b, c,
)
}
func SequenceT4[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GC ~func() ET.Either[E, C], GD ~func() ET.Either[E, D], GTABCD ~func() ET.Either[E, T.Tuple4[A, B, C, D]], E, A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
return apply.SequenceT4(
Map[GA, func() ET.Either[E, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], E, A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
Ap[GB, func() ET.Either[E, func(C) func(D) T.Tuple4[A, B, C, D]], func() ET.Either[E, func(B) func(C) func(D) T.Tuple4[A, B, C, D]], E, B, func(C) func(D) T.Tuple4[A, B, C, D]],
Ap[GC, func() ET.Either[E, func(D) T.Tuple4[A, B, C, D]], func() ET.Either[E, func(C) func(D) T.Tuple4[A, B, C, D]], E, C, func(D) T.Tuple4[A, B, C, D]],
Ap[GD, GTABCD, func() ET.Either[E, func(D) T.Tuple4[A, B, C, D]], E, D, T.Tuple4[A, B, C, D]],
a, b, c, d,
)
}

View File

@@ -27,7 +27,7 @@ func MonadTraverseArray[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS
return RA.MonadTraverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
tas,
f,
@@ -39,7 +39,7 @@ func TraverseArray[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AA
return RA.Traverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
f,
)
@@ -55,7 +55,7 @@ func MonadTraverseRecord[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BB
return RR.MonadTraverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
tas,
f,
@@ -67,7 +67,7 @@ func TraverseRecord[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], A
return RR.Traverse[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GB, GBS, func() ET.Either[E, func(B) BBS], E, B, BBS],
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
f,
)

View File

@@ -22,7 +22,7 @@ import (
O "github.com/IBM/fp-go/option"
)
// IO represents a synchronous computation that may fail
// IOEither represents a synchronous computation that may fail
// refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioeitherlte-agt] for more details
type IOEither[E, A any] I.IO[ET.Either[E, A]]
@@ -111,11 +111,11 @@ func ChainEitherK[E, A, B any](f func(A) ET.Either[E, B]) func(IOEither[E, A]) I
}
func MonadAp[B, E, A any](mab IOEither[E, func(A) B], ma IOEither[E, A]) IOEither[E, B] {
return G.MonadAp[IOEither[E, A], IOEither[E, B]](mab, ma)
return G.MonadAp[IOEither[E, B]](mab, ma)
}
func Ap[B, E, A any](ma IOEither[E, A]) func(IOEither[E, func(A) B]) IOEither[E, B] {
return G.Ap[IOEither[E, A], IOEither[E, B], IOEither[E, func(A) B]](ma)
return G.Ap[IOEither[E, B], IOEither[E, func(A) B]](ma)
}
func Flatten[E, A any](mma IOEither[E, IOEither[E, A]]) IOEither[E, A] {
@@ -130,26 +130,6 @@ func TryCatchError[A any](f func() (A, error)) IOEither[error, A] {
return G.TryCatchError[IOEither[error, A]](f)
}
func Eitherize0[A any](f func() (A, error)) func() IOEither[error, A] {
return G.Eitherize0[IOEither[error, A]](f)
}
func Eitherize1[T1, A any](f func(t1 T1) (A, error)) func(T1) IOEither[error, A] {
return G.Eitherize1[IOEither[error, A]](f)
}
func Eitherize2[T1, T2, A any](f func(t1 T1, t2 T2) (A, error)) func(T1, T2) IOEither[error, A] {
return G.Eitherize2[IOEither[error, A]](f)
}
func Eitherize3[T1, T2, T3, A any](f func(t1 T1, t2 T2, t3 T3) (A, error)) func(T1, T2, T3) IOEither[error, A] {
return G.Eitherize3[IOEither[error, A]](f)
}
func Eitherize4[T1, T2, T3, T4, A any](f func(t1 T1, t2 T2, t3 T3, t4 T4) (A, error)) func(T1, T2, T3, T4) IOEither[error, A] {
return G.Eitherize4[IOEither[error, A]](f)
}
func Memoize[E, A any](ma IOEither[E, A]) IOEither[E, A] {
return G.Memoize(ma)
}
@@ -212,7 +192,7 @@ func ChainFirstIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither
}
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
func WithResource[E, R, A, ANY any](onCreate IOEither[E, R], onRelease func(R) IOEither[E, ANY]) func(func(R) IOEither[E, A]) IOEither[E, A] {
func WithResource[A, E, R, ANY any](onCreate IOEither[E, R], onRelease func(R) IOEither[E, ANY]) func(func(R) IOEither[E, A]) IOEither[E, A] {
return G.WithResource[IOEither[E, A]](onCreate, onRelease)
}

View File

@@ -119,7 +119,7 @@ func TestApFirst(t *testing.T) {
x := F.Pipe1(
Of[error]("a"),
ApFirst[error, string](Of[error]("b")),
ApFirst[string](Of[error]("b")),
)
assert.Equal(t, E.Of[error]("a"), x())
@@ -129,7 +129,7 @@ func TestApSecond(t *testing.T) {
x := F.Pipe1(
Of[error]("a"),
ApSecond[error, string](Of[error]("b")),
ApSecond[string](Of[error]("b")),
)
assert.Equal(t, E.Of[error]("b"), x())

View File

@@ -1,69 +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 ioeither
import (
G "github.com/IBM/fp-go/ioeither/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[E, A any](a IOEither[E, A]) IOEither[E, T.Tuple1[A]] {
return G.SequenceT1[
IOEither[E, A],
IOEither[E, T.Tuple1[A]],
](a)
}
func SequenceT2[E, A, B any](
a IOEither[E, A],
b IOEither[E, B],
) IOEither[E, T.Tuple2[A, B]] {
return G.SequenceT2[
IOEither[E, A],
IOEither[E, B],
IOEither[E, T.Tuple2[A, B]],
](a, b)
}
func SequenceT3[E, A, B, C any](
a IOEither[E, A],
b IOEither[E, B],
c IOEither[E, C],
) IOEither[E, T.Tuple3[A, B, C]] {
return G.SequenceT3[
IOEither[E, A],
IOEither[E, B],
IOEither[E, C],
IOEither[E, T.Tuple3[A, B, C]],
](a, b, c)
}
func SequenceT4[E, A, B, C, D any](
a IOEither[E, A],
b IOEither[E, B],
c IOEither[E, C],
d IOEither[E, D],
) IOEither[E, T.Tuple4[A, B, C, D]] {
return G.SequenceT4[
IOEither[E, A],
IOEither[E, B],
IOEither[E, C],
IOEither[E, D],
IOEither[E, T.Tuple4[A, B, C, D]],
](a, b, c, d)
}

30
iooption/array.go Normal file
View 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 iooption
import (
G "github.com/IBM/fp-go/iooption/generic"
)
// TraverseArray transforms an array
func TraverseArray[A, B any](f func(A) IOOption[B]) func([]A) IOOption[[]B] {
return G.TraverseArray[IOOption[B], IOOption[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []IOOption[A]) IOOption[[]A] {
return G.SequenceArray[IOOption[A], IOOption[[]A], []IOOption[A], []A, A](ma)
}

Some files were not shown because too many files have changed in this diff Show More